You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Feature request: savefig with separated pad_inches in each direction #11764
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.
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.
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.
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.
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.
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.
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.
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.
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.
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)
Separate keywords pad_inches_left, pad_inches_right, ...
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.
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.
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.
I opted for a [l,r,b,t] tuple because I think that's going to be the most accessible. Additional kwargs and more complex datatypes seem like overkill for most users to me. If I'm understanding the above correctly, SubplotParams()'s lbrt order is the black sheep and a lrbt tuple will be reasonably conventional. Can't speak to tab-completion as I don't think it's functional in my Spyder environment
Therefore, it might be an option to make its parameters kwonly. This would remove the inconsistency. It also adds to clarity, and SubplotParams Is such an advanced use case that we can bear the additional verbosity.
Edit: It's more complicated than that, as this also has to be done in other places like SubplotParams. update and Figure.subplots_adjust (usage). So likely not worth it. I think subplot params are generally less used nowadays since constrained layout is often a good automatic default.
Summarizing the current APIs we have (partially taken from above):
Axes.imshow(extent=) uses (left, right, bottom, top) - while they share the same structure, at least they are positions not pad
SubplotParams(left, bottom, right, top) - these are pads, but in a weird order
tight_layout (and related functionality) - only scalars as separate parameters: pad, h_pad, w_pad.
So no matter what we do with a 4-tuple: It's a different API than tight_layout and it will be inconsistent either with the subplot_params or extent tuples.
If we want to expand pad semantics, I'm inclined to go with the CSS margin / padding approach; i.e. accept
a single value for all cases
two values (vertical, horizontal)
four values (top, right, bottom left)
Advantages:
a widely known convention and thus better memorizable
convenient as often the two-value version is sufficient (and reduces the need to think too much about the order of the individual sides)
can easily be retrofitted to any place we can currently have only a scalar pad (including tight_layout)
Disadvantages:
Inconsistent with the order in subplot_params - but hopefully less used nowadays
Inconsistent with the order in extent. - we need to clearly document this.
I agree it makes sense for imshow, SubplotParams, and tight_layout (and largely anything else where we're specifying a bounding box type of thing) to accept all of
a single value
specify the x and y axes
specify all four bounds
But I want to point out that the left, right, bottom, top order is used in other contexts in matplotlib. Off the top of my head, hist2d's range ([[xmin, xmax], [ymin, ymax]]), and imshow's extent ([l, r, b, t]), though I'm sure there are a lot of other examples. In the typical "turn data into a pretty png for a powerpoint" tasks that I do, I see l, r, b, t quite a bit and other orders never.
I'd vote for any argument in this bounding box-ish domain to accept
a single number or len-1 list-like to specify all
[x, y] list-like
[left, right, bottom, top] list-like
wherever we can do that without breaking changes
, hist2d's range ([[xmin, xmax], [ymin, ymax]]), and imshow's extent ([l, r, b, t])
This is not directly comparable. Logically, it’s a lis of ranges. A grouping [[pad_l, pad_r], [pad_top, pad_bottom]] wouldn’t make sense.
It think we need to create a systematic overview of all cases involving „sizing“ in x and y to make an informed decision. Rectangle and Bbox directly to my mind. Though not all of these will be logically equivalent (see hist2d‘s range) I think it’s valuable to have the broader picture.
I agree that these things are just convention and it would be nice to have one paradigm in Matplotlib, though for back compat reasons I expect this will be hard.
I find [t, r, b, l] super unintuitive, and I'm pretty surprised that is the CSS default. However, it makes some sense in CSS to start from the top, since web layout is from the top down (and then they went clockwise, I guess). I'm also unaware of it ever being used in Matplotlib.
However, for Matplotlib, ax.set_position is [l, b, w, h]. For Bbox: "extents" are [l, b, r, t], and "bounds" are [l, b, w, h]. Given that these are super fundamental to Matplotlib, I'd suggest we keep the same convention and use [l, b, r, t]. I dont' find Rectangle as useful an analogy, but it is specified (xy), width, height where (xy) is "typically" the bottom left corner.
So I think its pretty universal for Matplotlib (and Matlab before it) to start "left, bottom,..." I can see where the other convention comes from, but I think it's just a different paradigm.
Given that there is no canonical order of the values and that this is and advanced feature used for fine-tuning, I vote to be defensive and only accept a dict for specifying per-side pads (option 3 from above).
Advantage:
makes per-side pads possilbe
unambiguous
we can always add tuple support later once/if we come to an agreement this is worth it and we have a consistent memorizable API
Disadvantage:
more typing, in particular if you want vertical pads and horizontal pads (i.e. the dict doesn't have an equivalent for the 2-tuple variant)
Activity
jklymak commentedon 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.timhoffm commentedon 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)(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 commentedon 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
SubplotParamshas the kwarg order lbrt, but the documentation aslrbt. I always get confused about kwargs, but can__init__be called w positional arguments? I don't see anywhere in the codebase wherefig.subplots_adjustis called with positional arguments, so I somewhat suspect no one was really paying attention to the order of the kwargs.timhoffm commentedon Jul 24, 2018
Since the doc is
lrbt, it's probably an unintended mistake to have the orderSubplotParams(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 commentedon Jul 25, 2018
And (matplotlib) basemap use for same reason, left, right, top, bottom.
I believe that the best API would be to let
pad_inchesbe 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 commentedon 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 commentedon 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 commentedon Jul 27, 2018
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 commentedon 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 commentedon Jul 30, 2018
Short summary of options:
pad_inchessupports tuple(left, right, bottom, top)(maybe alternative order, but the one given here seems prevalent within matplotlib - though we are not consistent with ourselves)pad_inches_left,pad_inches_right, ...pad_inchessupports 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 commentedon 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 commentedon 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.
Allow BboxBase.padded to accept a tuple or list
Roald87 commentedon Aug 16, 2018
Is there something against using a
namedtuple?22 remaining items
ttshaw1 commentedon Jun 17, 2025
Can we reopen this? @zjpoh is this on your to-do list? I can take it over if not, this would be useful for a graph I'm making right now
jklymak commentedon Jun 17, 2025
You are welcome to put in a PR even if the issue is closed
ttshaw1 commentedon Jun 17, 2025
I opted for a [l,r,b,t] tuple because I think that's going to be the most accessible. Additional kwargs and more complex datatypes seem like overkill for most users to me. If I'm understanding the above correctly,
SubplotParams()'s lbrt order is the black sheep and a lrbt tuple will be reasonably conventional. Can't speak to tab-completion as I don't think it's functional in my Spyder environmenttimhoffm commentedon Dec 21, 2025
Semi-OT: Very few users seem to rely on the parameter in SubplotParams(): https://github.com/search?q=%2F%5CbSubplotParams%5C%28%5B%5Cw%5C.%5D%2B%2C%2F+language%3APython+NOT+is%3Afork&type=code
Therefore, it might be an option to make its parameters kwonly. This would remove the inconsistency. It also adds to clarity, and SubplotParams Is such an advanced use case that we can bear the additional verbosity.
Edit: It's more complicated than that, as this also has to be done in other places like
SubplotParams. updateandFigure.subplots_adjust(usage). So likely not worth it. I think subplot params are generally less used nowadays since constrained layout is often a good automatic default.timhoffm commentedon Dec 21, 2025
Summarizing the current APIs we have (partially taken from above):
Axes.imshow(extent=)uses(left, right, bottom, top)- while they share the same structure, at least they are positions not padSubplotParams(left, bottom, right, top)- these are pads, but in a weird ordertight_layout(and related functionality) - only scalars as separate parameters:pad,h_pad,w_pad.So no matter what we do with a 4-tuple: It's a different API than tight_layout and it will be inconsistent either with the subplot_params or extent tuples.
If we want to expand pad semantics, I'm inclined to go with the CSS margin / padding approach; i.e. accept
Advantages:
Disadvantages:
ttshaw1 commentedon Dec 22, 2025
I agree it makes sense for imshow, SubplotParams, and tight_layout (and largely anything else where we're specifying a bounding box type of thing) to accept all of
But I want to point out that the left, right, bottom, top order is used in other contexts in matplotlib. Off the top of my head, hist2d's
range([[xmin, xmax], [ymin, ymax]]), and imshow'sextent([l, r, b, t]), though I'm sure there are a lot of other examples. In the typical "turn data into a pretty png for a powerpoint" tasks that I do, I see l, r, b, t quite a bit and other orders never.I'd vote for any argument in this bounding box-ish domain to accept
wherever we can do that without breaking changes
timhoffm commentedon Dec 22, 2025
This is not directly comparable. Logically, it’s a lis of ranges. A grouping [[pad_l, pad_r], [pad_top, pad_bottom]] wouldn’t make sense.
It think we need to create a systematic overview of all cases involving „sizing“ in x and y to make an informed decision.
RectangleandBboxdirectly to my mind. Though not all of these will be logically equivalent (see hist2d‘s range) I think it’s valuable to have the broader picture.jklymak commentedon Dec 22, 2025
I agree that these things are just convention and it would be nice to have one paradigm in Matplotlib, though for back compat reasons I expect this will be hard.
I find
[t, r, b, l]super unintuitive, and I'm pretty surprised that is the CSS default. However, it makes some sense in CSS to start from the top, since web layout is from the top down (and then they went clockwise, I guess). I'm also unaware of it ever being used in Matplotlib.However, for Matplotlib,
ax.set_positionis[l, b, w, h]. ForBbox: "extents" are[l, b, r, t], and "bounds" are[l, b, w, h]. Given that these are super fundamental to Matplotlib, I'd suggest we keep the same convention and use[l, b, r, t]. I dont' findRectangleas useful an analogy, but it is specified(xy), width, heightwhere(xy)is "typically" the bottom left corner.So I think its pretty universal for Matplotlib (and Matlab before it) to start "left, bottom,..." I can see where the other convention comes from, but I think it's just a different paradigm.
timhoffm commentedon Jan 2, 2026
Given that there is no canonical order of the values and that this is and advanced feature used for fine-tuning, I vote to be defensive and only accept a dict for specifying per-side pads (option 3 from above).
Advantage:
Disadvantage: