I often want to make a figure that is larger than what I have in my rcParams. However, I would also like to keep the same aspect ratio for this new figure, unfortunately this then requires that I do mental math 😞. For example if I want a figure be to be 1.5 times larger than the rcDefault size of [6.4, 4.8] then I will have to multiply in my head or add a few lines of code. Instead I normally just make a haphazard guess of two numbers of that I hope will result in a similar aspect ratio.
Proposed Solution
Modify the figsize argument to plt.figure to also accept a single float value. When given as (float, float) the original behavior will remain. When given as float then the figsize will be computed as a multiple of the rcParam figsize. Like so:
That doesn't seem completely unreasonable. OTOH, it is idiosyncratic. For instance, I usually want the width of my figures to stay the same (so they fit on a journal page), and the height to change.
This is somewhat redundant with the dpi argument, but I think the proposed solution is more intuitive.
They are not redundant! If you have the letter "A" at 12 points on a figure, figsize says how much of that figure the "A" takes up. dpi says how many dots are used to represent it in a rasterized backend, and nothing about it for a vectorized backend. They control very different things.
What could a user anticipate figsize=0.75 (or figsize=3/4) to be?
a) an aspect ratio. Width could be taken from rcParams and height be adapted. (Could also be the other way round, but @jklymak made a good point that widths are usually kept more constant.)
b) the scaling factor proposed above.
I'm undecided which one would be the more natural choice. - If a) was, that would be an argument against adding the proposed API. Both are ideosyncratic in that they use rcParams[figure.size], whereas the standard figsize=(with, height) overrides it.
I'm not quite clear if scaling is a common use case. IMHO larger figures tend to consist of multiple subplots and in that case it's usually reasonable to adapt the aspect ratio as well.
Interactive usage / quick look as some data. If you write program, it's probably not a big deal to calculate two numbers instead of using one.
Non-resizable backends. If you have a resizable figure, it's faster to resize the figure after showing than typing figsize=foo.
This basically leaves jupyter inline figures with a single axes but lots of data.
Overall the proposed feature is not really a straight forward extension, but OTOH it's also not too outlandish.
@ianhi what exactly is your use case?
This basically leaves jupyter inline figures with a single axes but lots of data.
It is generally when I rapidly iterating on a plot that has lots of data. I am a heavy user of jupyter notebooks and I tend to want this with both the inline and ipympl backends. With the inline backend I obviously cannot resize a plot post creation, and with the ipympl backend while I can resize with the mouse I prefer not two for two reason:
I use the vim bindings so switching to using the mouse to resize the figure can break flow
This is clearly an insufficient reason on it's own...
If I resize the plot and then realize I want to make a small change I will rerun the cell and then will need to manually resize again. It would preferable to just realize that I want the plot to be bigger and only need to add figsize=2 in addition to whatever other change I make.
Arguably I could just make my rcParam figsize bigger, but if I were to do that then all of my plots would be bigger which takes up too much space in the notebook
On Thu, Aug 13, 2020 at 10:34 PM Ian Hunt-Isaak ***@***.***> wrote:
@ianhi <https://github.com/ianhi> what exactly is your use case?
This basically leaves jupyter inline figures with a single axes but lots
of data.
It is generally when I rapidly iterating on a plot that has lots of data.
I am a heavy user of jupyter notebooks and I tend to want this with both
the inline and ipympl backends. With the inline backend I obviously cannot
resize a plot post creation, and with the ipympl backend while I can resize
with the mouse I prefer not two for two reason:
1. I use the vim bindings so switching to using the mouse to resize
the figure can break flow
- This is clearly an insufficient reason on it's own...
2. If I resize the plot and then realize I want to make a small change
I will rerun the cell and then will need to manually resize again. It would
preferable to just realize that I want the plot to be bigger and only need
to add figsize=2 in addition to whatever other change I make.
Arguably I could just make my rcParam figsize bigger, but if I were to do
that then all of my plots would be bigger which takes up too much space in
the notebook
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#18244 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACHF6B7GHYZ46JXRLMM6LTSASPEFANCNFSM4P6UVI7Q>
.
figaspect is even wackier. It adjusts the aspect ratio by leaving the height the same as the rcParam, and adjusting the width.
I think assuming that a single float means "make the figure this much bigger" is just one of many choices, and that makes it a hard sell. I don't particularly like overloading kwargs as it just leads to confusion and typos.
OTOH, if you wanted to write something analogous to figaspect and put it in pyplot that might be easier. It'd be self-contained and still give you what you want. i.e. plt.figure(figsize=plt.figsizemult(2.78))
I think assuming that a single float means "make the figure this much bigger" is just one of many choices
That's reasonable. It seems to be that that there are three basic ways we could imagine specifying figuresize: Explicitly, via figsize and implicitly via aspect ratio and/or scale. I think it would be cool to support all of those options within figure, though it would come at the cost of adding yet more kwargs. How you would you feel about adding two optional arguments to figure: figaspect and figscale both as None or Float.
figaspect: take width from rcParams and adapt height
figscale(or figsizemult): take width/height after accounting for figaspect and scale it like I originally described.
With both of these arguments deferring to figsize if that was passed?
I think its fine too - in fact I could imagine using the functionality. @ianhi, if you implement this, suggest warning if conflicting kwargs are passed. Also beware that this has a big documentation footprint (subplots, figure, their pyplot equivalents, etc...) Before embarking on the journey, you may want to get a couple more thumbs up. @timhoffm. @WeatherGod@tacaswell@anntzer@efiring any opinions?
IMO if you implement an aspect parameter, fixing height and varying width would be more in line with how display aspects are usually defined (and how it works in seaborn).
Although matplotlib has a different concept of aspect that may be confusing...
Having s = np.array(plt.rcParams['figure.size']) at the the top of your notebook and doing fig = plt.figure(figsize=s*2) does not seem too bad to carry around.
This reminds me of the "should we take fig size as cm as well" discussions where we have historically landed on "would be nice, but not worth the extra complexity". Similarly here, I see how this is a nice quality of life improvement, but am not convinced that it would improve the lives of many people
I'm pretty thoroughly in-different to this proposal (will not block it but also would not merge it).
if you implement an aspect parameter, fixing height and varying width would be more in line with how display aspects are usually defined (and how it works in seaborn).
For sure, varying ideas of how to implement this will be huge problem.
Here I was arguing that if you choose a dimension to fix, it should be the width, because when you publish a paper that is usually the narrower constraint. However, if you are making webpages, I guess vertical is usually more constrained, so you'll never make anyone everyone happy...
Historical footnote: the reason is that I think in terms of sailboats, and a high-aspect-ratio rig is one with a tall mast and a short boom. So, long ago, when I put in aspect ratio handling, that's the way I defined it.
I'm convinced by #18244 (comment). We can always provide more convenience via additional kwargs, but beyond some point they become counter-productive, adding more complexity to code and documentation than they are worth. The figsize kwarg, as-is, gives complete control, and is not hard to set explicitly to match whatever conditions are desired.
Just for explicitness if you don't remember its h/w. And as @mwaskom points out, it is pretty conventional to specify aspect ratios as width-to-height. But I'm not seriously advocating we should do this.
However, if you are making webpages, I guess vertical is usually more constrained, so you'll never make anyone everyone happy...
I'd say the opposite. Even if screens happen to be wider than taller, the width is still the fixed constraint, as it's much more natural to scroll vertically than to scroll horizontally.
My PoV is pretty close to @efiring's (#18244 (comment)). Also note that if you really want this it is easy to write your own wrapper function(s) around figure() (and friends) that provides the functionality, and use that instead.
@tacaswell, is there an issue tracking the desire to have a tutorial that helps folks make themselves "helper" libraries? I think that was on your todo?
Overall, this again is a conflict between "library with a minimal and clear API" and "additional redundance for user convenience to achieve a certian behavior with less code".
Note on kwargs
How you would you feel about adding two optional arguments to figure: figaspect and figscale both as None or Float.
figaspect: take width from rcParams and adapt height
figscale(or figsizemult): take width/height after accounting for figaspect and scale it like I originally described.
With both of these arguments deferring to figsize if that was passed?
Generally, mutually exclusive (or interfering) parameters are an indication for bad API design. This is also true here, if thinking from the library API perspective. There are better options, but they are not as convenient to type as figscale=2.
In comparison, I'd still favor figsize=2.
Compromise?
Would it be reasonable to make rcParams['figure.figsize'] a ndarray? If so, one could do figure(figsize=2*plt.rcParams[figure.figsize]). That's comfortingly explicit. It's a bit longer to type once, but you can easily scale afterwards.
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!
Activity
jklymak commented on Aug 13, 2020
That doesn't seem completely unreasonable. OTOH, it is idiosyncratic. For instance, I usually want the width of my figures to stay the same (so they fit on a journal page), and the height to change.
They are not redundant! If you have the letter "A" at 12 points on a figure, figsize says how much of that figure the "A" takes up. dpi says how many dots are used to represent it in a rasterized backend, and nothing about it for a vectorized backend. They control very different things.
timhoffm commented on Aug 13, 2020
Comment on the API
What could a user anticipate figsize=0.75 (or figsize=3/4) to be?
a) an aspect ratio. Width could be taken from rcParams and height be adapted. (Could also be the other way round, but @jklymak made a good point that widths are usually kept more constant.)
b) the scaling factor proposed above.
I'm undecided which one would be the more natural choice. - If a) was, that would be an argument against adding the proposed API. Both are ideosyncratic in that they use rcParams[figure.size], whereas the standard figsize=(with, height) overrides it.
Comment on use case
@ianhi what exactly is your use case?
I'm not quite clear if scaling is a common use case. IMHO larger figures tend to consist of multiple subplots and in that case it's usually reasonable to adapt the aspect ratio as well.
This basically leaves jupyter inline figures with a single axes but lots of data.
Overall the proposed feature is not really a straight forward extension, but OTOH it's also not too outlandish.
ianhi commented on Aug 14, 2020
It is generally when I rapidly iterating on a plot that has lots of data. I am a heavy user of jupyter notebooks and I tend to want this with both the inline and ipympl backends. With the inline backend I obviously cannot resize a plot post creation, and with the ipympl backend while I can resize with the mouse I prefer not two for two reason:
Arguably I could just make my rcParam figsize bigger, but if I were to do that then all of my plots would be bigger which takes up too much space in the notebook
WeatherGod commented on Aug 14, 2020
jklymak commented on Aug 14, 2020
figaspect is even wackier. It adjusts the aspect ratio by leaving the height the same as the rcParam, and adjusting the width.
I think assuming that a single float means "make the figure this much bigger" is just one of many choices, and that makes it a hard sell. I don't particularly like overloading kwargs as it just leads to confusion and typos.
OTOH, if you wanted to write something analogous to figaspect and put it in pyplot that might be easier. It'd be self-contained and still give you what you want. i.e. plt.figure(figsize=plt.figsizemult(2.78))
ianhi commented on Aug 14, 2020
That's reasonable. It seems to be that that there are three basic ways we could imagine specifying figuresize: Explicitly, via figsize and implicitly via aspect ratio and/or scale. I think it would be cool to support all of those options within figure, though it would come at the cost of adding yet more kwargs. How you would you feel about adding two optional arguments to figure: figaspect and figscale both as None or Float.
With both of these arguments deferring to figsize if that was passed?
dopplershift commented on Aug 14, 2020
I'm undecided overall, but I will say this most recent suggestion is the one that sounds most reasonable thus far.
jklymak commented on Aug 14, 2020
I think its fine too - in fact I could imagine using the functionality. @ianhi, if you implement this, suggest warning if conflicting kwargs are passed. Also beware that this has a big documentation footprint (subplots, figure, their pyplot equivalents, etc...) Before embarking on the journey, you may want to get a couple more thumbs up. @timhoffm. @WeatherGod @tacaswell @anntzer @efiring any opinions?
mwaskom commented on Aug 14, 2020
IMO if you implement an aspect parameter, fixing height and varying width would be more in line with how display aspects are usually defined (and how it works in seaborn).
Although matplotlib has a different concept of aspect that may be confusing...
tacaswell commented on Aug 14, 2020
Having s = np.array(plt.rcParams['figure.size']) at the the top of your notebook and doing fig = plt.figure(figsize=s*2) does not seem too bad to carry around.
This reminds me of the "should we take fig size as cm as well" discussions where we have historically landed on "would be nice, but not worth the extra complexity". Similarly here, I see how this is a nice quality of life improvement, but am not convinced that it would improve the lives of many people
I'm pretty thoroughly in-different to this proposal (will not block it but also would not merge it).
jklymak commented on Aug 14, 2020
For sure, varying ideas of how to implement this will be huge problem.
Though I'll note that matplotlib, for whatever historic reason says aspect=3 is three times as tall as wide. https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.set_aspect.html
Here I was arguing that if you choose a dimension to fix, it should be the width, because when you publish a paper that is usually the narrower constraint. However, if you are making webpages, I guess vertical is usually more constrained, so you'll never make anyone everyone happy...
efiring commented on Aug 14, 2020
Historical footnote: the reason is that I think in terms of sailboats, and a high-aspect-ratio rig is one with a tall mast and a short boom. So, long ago, when I put in aspect ratio handling, that's the way I defined it.
efiring commented on Aug 14, 2020
I'm convinced by #18244 (comment). We can always provide more convenience via additional kwargs, but beyond some point they become counter-productive, adding more complexity to code and documentation than they are worth. The figsize kwarg, as-is, gives complete control, and is not hard to set explicitly to match whatever conditions are desired.
jklymak commented on Aug 14, 2020
Well, set_aspect would ideally allow a vector instead of a float, which would be the exact converse of the request here 😉.
dopplershift commented on Aug 14, 2020
I don’t see the point of set_aspect taking a vector:
jklymak commented on Aug 14, 2020
Just for explicitness if you don't remember its h/w. And as @mwaskom points out, it is pretty conventional to specify aspect ratios as width-to-height. But I'm not seriously advocating we should do this.
mwaskom commented on Aug 14, 2020
"That's the way it works on sailboats" is officially my favorite explanation for a matplotlib API quirk.
jklymak commented on Aug 14, 2020
We are lucky he didn't do ax.set_xlim(port=-1, starboard=+1)
QuLogic commented on Aug 14, 2020
I'd say the opposite. Even if screens happen to be wider than taller, the width is still the fixed constraint, as it's much more natural to scroll vertically than to scroll horizontally.
anntzer commented on Aug 14, 2020
My PoV is pretty close to @efiring's (#18244 (comment)). Also note that if you really want this it is easy to write your own wrapper function(s) around figure() (and friends) that provides the functionality, and use that instead.
jklymak commented on Aug 14, 2020
@tacaswell, is there an issue tracking the desire to have a tutorial that helps folks make themselves "helper" libraries? I think that was on your todo?
timhoffm commented on Aug 14, 2020
I tend to agree with @efiring (#18244 (comment)) as well.
While I see the use case, all possible APIs are a bit awkward, and it's relatively easy to work around this by one of:
Overall, this again is a conflict between "library with a minimal and clear API" and "additional redundance for user convenience to achieve a certian behavior with less code".
Note on kwargs
Generally, mutually exclusive (or interfering) parameters are an indication for bad API design. This is also true here, if thinking from the library API perspective. There are better options, but they are not as convenient to type as figscale=2.
In comparison, I'd still favor figsize=2.
Compromise?
Would it be reasonable to make rcParams['figure.figsize'] a ndarray? If so, one could do figure(figsize=2*plt.rcParams[figure.figsize]). That's comfortingly explicit. It's a bit longer to type once, but you can easily scale afterwards.
github-actions commented on Aug 16, 2023
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!