8000 Feature request: savefig with separated pad_inches in each direction · Issue #11764 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Feature request: savefig with separated pad_inches in each direction #11764

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
scarlehoff opened this issue Jul 24, 2018 · 17 comments
Closed

Feature request: savefig with separated pad_inches in each direction #11764

scarlehoff opened this issue Jul 24, 2018 · 17 comments
Labels
API: changes API: consistency status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. status: inactive Marked by the “Stale” Github Action

Comments

@scarlehoff
Copy link
scarlehoff commented Jul 24, 2018

This is just a thought I had, it would be desirable to be able to select "pad_inches" separately for the top/bottom/right/left margins.

Just to clarify, I want to be able to create my figures and whatever and only at the time of saving them to disk be able to do:

figure.savefig(filename, bbox_inches = 'tight', pad_inches_top = 0.4, pad_inches_right = 0.3)

Instead of having to change the shape of the figure I'm working with or creating a new figure with the right dimensions, as the padding work in all directions at the same time. Of course it's not a critical thing but in terms of usability would be a great help.

ps. I'm not sure whether this is a good idea or whether this is the correct place to submit a feature request. Apologies in advance.

@jklymak
Copy link
Member
jklymak commented Jul 24, 2018

Yes this is a good place to submit this idea. I don’t think it’d be a big deal to pass a four-tuple in pad_inches; I’d be against four new kwargs. Someone just has to write the PR!

Edit: just to be clear: fig.savefig(fname, bbox_inches='tight', pad_inches=[l, r, b, t]) is what I was thinking.

@jklymak jklymak added the Good first issue Open a pull request against these issues if there are no active ones! label Jul 24, 2018
@timhoffm
Copy link
Member
timhoffm commented Jul 24, 2018

I agree that this should be a tuple and not new kwargs.

Unfortunately, there's no consistent solution for the order.

  • Axes.imshow(extent=) uses (left, right, bottom, top)
  • SubplotParams(left, bottom, right, top)
  • CSS margin and padding use (top, right, bottom, left) - not part of matplotlib but a widely known convention.

If I would design something from scratch, I'd go for the CSS convention. However, that would be badly inconsistent with both conventions used in matplotib.

Because of this situation, I'm unsure if we want to support a simple tuple at all. A more verbose but unambiguous alternative would be a dict with keys left, right, bottom, top.

@jklymak
Copy link
Member
jklymak commented Jul 24, 2018

I think if you are going to do a dictionary, you might as well just do the explicit kwargs?

Its kind of funny that SubplotParams has the kwarg order lbrt, but the documentation as lrbt. I always get confused about kwargs, but can __init__ be called w positional arguments? I don't see anywhere in the codebase where fig.subplots_adjust is called with positional arguments, so I somewhat suspect no one was really paying attention to the order of the kwargs.

@timhoffm
Copy link
Member

I think if you are going to do a dictionary, you might as well just do the explicit kwargs?
Not quite. The call is comparable complex or lengthy with both versions, but the API stays simpler: Just one arg.

Since the doc is lrbt, it's probably an unintended mistake to have the order SubplotParams(left, bottom, right, top). However, even if we don't use that internally, it's now part of the public API and not easy to change.

@fredrik-1
Copy link
Contributor

And (matplotlib) basemap use for same reason, left, right, top, bottom.

I believe that the best API would be to let pad_inches be either a float or dict. I don't think that it would be a good idea to have four new kwargs for a functionality that is probably not going to be used that much. A tuple would also be good, less wordy but more difficult to remember.

@zjpoh
Copy link
zjpoh commented Jul 27, 2018

I agree that tuple is not the best option here. I also agree that adding one dict is better than four new kwargs for easy of maintenance.

If nobody is working on this yet, I would like to give it a try.

@jklymak
Copy link
Member
jklymak commented Jul 27, 2018

My objection to a dictionary is the same as my objection to fontdict for text. There is no discoverability for it from the command line of IPython or Jupyter notebook. Further to fill in a dictionary properly you have to get the keys correct; is it left-pad, leftpad, pad-left, padding-left etc etc etc. At least with a kwarg you can tab-complete to get the name.

A tuple on the other hand is easy to get wrong, but there are really only two sensible ways it can be organized so at most you make two guesses.

I understand why we have fontdict, but I have to google the entries every time I use it and that seems like bad API to me.

@timhoffm
Copy link
Member

If we use a dict as param it should be described fully in the docstring of the respective param. I know that's not the case for fontdict. You don't get tab-completion from that, but at least you can look it up in the docstring without leaving IPython / the notebook.

To that extent, a dict and a tuple are equally (non-)accessible. The dict has the advantage of being more explicit at the cost of being more verbose. I'd prefer that for rarely used options where there is no unambiguous order as in this case.

Fontdict has another issue in that it's redundant to other kwargs, cf #10293. I think the situations between here and fontdict are not quite comparable. We should not mix this into the discussion here.

@jklymak
Copy link
Member
jklymak commented Jul 27, 2018

Just registering my general disaproval of packing method arguments in dictionaries; I don't really care about this kwarg in particular, but I think its a klunky API style in general.

@timhoffm
Copy link
Member

Short summary of options:

  1. pad_inches supports tuple (left, right, bottom, top) (maybe alternative order, but the one given here seems prevalent within matplotlib - though we are not consistent with ourselves)
  2. Separate keywords pad_inches_left, pad_inches_right, ...
  3. pad_inches supports dict {'left'=..., 'right'=..., 'bottom'=..., 'top'=...}.

Not adding the feature or supporting multiple ways are theoretically possible as well.

Personally, I'm 50/50 on 1. or 3. But there were also other opinions. For a detailed discussion of the advantages/disadvantages see above.

I think this is an important API decision, which should be taken deliberately. @tacaswell @efiring Can please some of the senior contributors decide on the API we want to use here.

@efiring
Copy link
Member
efiring commented Jul 30, 2018

Considerations: discoverability, readability, and code complexity, all viewed with the perspective of how often a feature will be used, and by whom.

Discoverability involves documentation as well as possible tab-completion. Having a large number of kwargs hurts discoverability; the docstring becomes overwhelming, and there is a problem even for tab-completion, given the present ipython default of providing a quasi-gui interface instead of listing everything.

Readability is high-priority, and having the option of packing related options into a single dict kwarg aids readability, compared to an opaque tuple with non-obvious ordering.

The option proposed here, allowing more detail in pad_inches, is to me low-priority; I think its use will be rare. This puts extra weight on readability (if the option is indeed worth adding at all).

If this is implemented, I think options 1 (tuple) and 2 (more kwargs) is perpetuating bad API; option 3 (allowing a dict) is by far superior.

@EzraBC
Copy link
EzraBC commented Aug 1, 2018

Be aware, this is my first attempt at contributing to something.

I propose to modify matplotlib.transforms.BboxBase.padded to return a Bbox with the points modified by values in a dict as opposed to a single value. If a single value is passed, it can be normalized via the dict.fromkeys method within BboxBase.padded as shown in master...EzraBC:master.

Edit: This may be opening a can of worms, by in my opinion the most "pythonic" (though maybe not the most "matplotlib-ic") approach is to allow for as many possibilities as is easy to implement. As such, the link above now shows the BboxBase.padded method changed to allow a dict, list, tuple, or single value for the parameter p. If people more important than I disagree with this approach I am happy to pare it down.

EzraBC added a commit to EzraBC/matplotlib that referenced this issue Aug 2, 2018
In addition to allowing a dict, added support for a tuple or list being passed. Also fixed some indentation and changed the dict keys to those mentioned in issue matplotlib#11764
@Roald87
Copy link
Roald87 commented Aug 16, 2018

Is there something against using a namedtuple?

@tacaswell tacaswell added this to the v3.1 milestone Aug 16, 2018
@tacaswell tacaswell added API: consistency API: changes and removed Good first issue Open a pull request against these issues if there are no active ones! labels Aug 16, 2018
@NeilGirdhar
Copy link

Instead of namedtuple, I would just support any object that exposes the four attributes you want. For convenience, provide a dataclass type.

@jklymak
Copy link
Member
jklymak commented Feb 12, 2019

Just to summarize above, I think the plan is to use a dict if someone cares enough to submit a PR...

@jklymak jklymak modified the milestones: v3.1.0, v3.2.0 Feb 12, 2019
@zjpoh
Copy link
zjpoh commented Feb 15, 2019

I'll do it.

@timhoffm timhoffm modified the milestones: v3.2.0, v3.3.0 Aug 26, 2019
@QuLogic QuLogic modified the milestones: v3.3.0, v3.4.0 Apr 30, 2020
@QuLogic QuLogic removed this from the v3.4.0 milestone Jan 27, 2021
Copy link
github-actions bot commented Aug 9, 2024

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Aug 9, 2024
@github-actions github-actions bot added the status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. label Sep 10, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API: changes API: consistency status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. status: inactive Marked by the “Stale” Github Action
Projects
None yet
Development

No branches or pull requests

0