-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
fig.set_dpi() does not set the dpi correctly #11227
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
Comments
yes exhibit A as to why setting the figure dpi before rendering make our lives a lot harder. I had similar bug reports 6 months ago. |
Apparently they still haven't been solved? Are they duplicates? |
Some of this is due to the high-dpi support for Qt which effectively renders the figure at double resolution for the screen (this is due to the way that GUI frameworks deal with high-dpi, they default to using a 2x2 pixel grid for your images unless you explicitly ask it to give you access to the screen resolution). To keep the figure the correct size on the screen and the fonts at the expected size. There are a number of some what fragile latches to keep track of the 'real' and 'screen' DPI and to cope with the user moving the window from a low to a high dpi screen etc. Some of these rely on callbacks from the Qt side to fire to work correctly (see the comments in https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/tests/test_backend_qt5.py#L94 ). You are running these as The Tk one looks like a bug in the Tk window resize code (we need to set the window to be the size of the plot + the size of the toolbar, looks like we are missing the correction is the case of changing the DPI) |
I tested everything via |
The high-res stuff might explain the problems of Bug 2 I suppose. But if there is no figure shown at all, none of this should take any effect, right? |
For figure:
So I think if you don't specify the dpi it'll fall back to the default, so that is your first case. Why it does something different for tk is beyond me... EDIT oops sorry I see you specified dpi=figure. Well that is mysterious. |
For |
Uh, so there is even another bug? Because the first two figures are identical. I thought this to be expected because I assumed the default to be "figure", but if it isn't then the first figure should have a dpi of 100 instead of 200. |
No, the first two are correct because for the first one you are setting the figure DPI to 200 (which will render to the screen at 400) and save at 200, in the second case you are telling savefig to use 200 DPI (which it is). The third case is exposing a race condition someplace between the figure state and the GUI state. |
What the heck does "screen resolution" mean here? I'm not measuring anything with a ruler on my screen. But just because you are asking, I have a 1920x1080 pixel monitor with a diagonal of 27 inch, hence my screen resolution is |
This does not make any sense to me at all. Where is the number 400 coming from? And why should it save at 200 dpi, if - as the documentation states - the default rcParam is used, But as I said, feel free to replace the respective line by |
Again I ask. What is the point of setting the figure dpi before print time? It’s not documented so far as I can see |
OK, so on hi-dpi my machine using Qt5Agg import matplotlib
#matplotlib.use('tkagg')
import matplotlib.pyplot as plt
plt.close("all")
fig1, ax1 = plt.subplots(num="expected", dpi=100)
ax1.plot([1,2])
fig3, ax3 = plt.subplots(num="buggy", dpi=50)
fig3.set_dpi(100)
plt.show()
print(fig3.get_dpi()) prints If I change the original dpi to 30:
So it makes the window 50% the size of the default window in both cases, and then makes the lines thinner according to the original figure dpi. If I do fig3, ax3 = plt.subplots(num="buggy", dpi=30)
fig3.set_dpi(150) I get the bigger window, but still at the fuzzier resolution. |
The high-dpi GUI frameworks need a double-resolution image for painting to the screen. It is rather annoying, but it is the way it is (you can dig up quite a few comments from me about a year ago complaining vociferously about this, but I have moved on to acceptance). The default value of `savefig.dpi' is 'figure'. matplotlib/lib/matplotlib/figure.py Line 1852 in 9ec4b95
matplotlib/lib/matplotlib/rcsetup.py Line 1347 in 9ec4b95
which eventually falls through to backend bases matplotlib/lib/matplotlib/backend_bases.py Lines 2147 to 2148 in 9ec4b95
to resolve the string to a number. Note that this looks for an optional
and similarly in webagg. However it is not updated when @jklymak Either we set the dpi at the figure level and fold it into the transform stack or we would have to pass the dpi into every single backend draw method. We also use the dpi + figure size to sort out how big to make the gui windows. |
...glad you moved onto acceptance, I'm still in denial 😉 Thanks for bearing w/ me! |
See #11232 for what I think is a reasonable fix that shouldn't break anything.... |
I am experiencing a similar issue on EDIT: I am using TkAgg as my backend tl;dr:
More details: When I run the following code in a Jupyter notebook running fig, ax = plt.subplots()
fig.set_dpi(150)
ax.plot([1, 2], [1, 2])
print(fig.get_dpi())
fig.savefig("test.png", dpi="figure")
plt.show() I find that the Jupyter preview window reflects the increased DPI but the saved figure does NOT respect the changed dpi (it is still at the default 72 dpi). Moreover, I'm finding that on my machine, the |
@BearBearCodes Can you please check the value of I do not understand what you mean by "jupyter preview window" and our default dpi has been 100 from mpl2. Can you reproduce this issues with complete stand alone script (including imports) and no |
Actually let's close this, since DPI handling in most of the backends has changed significantly. @BearBearCodes if you can open a new issue with all the required information, that would be more clear. Thanks! |
Hi @tacaswell, thanks for your quick response and apologies for the confusion. By "jupyter preview window", I just mean the output you see under the Jupyter code cell after executing the code in that cell. A screenshot of what I mean is below. Also as you can see in the screenshot, the Interestingly, if I run the exact same code seen in the screenshot above in a python file rather than in a Jupyter notebook, the default figure dpi is 100. But if I change the dpi to, e.g., 150 using the following code in a standalone python file import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
fig.set_dpi(150)
ax.plot([1, 2], [1, 2])
print(fig.get_dpi())
print(mpl.rcParams["figure.dpi"])
print(mpl.rcParams["savefig.dpi"])
fig.savefig("test.png", dpi="figure")
plt.show() then the saved figure is still at 100 dpi rather than 150. |
Okay I will do that. Thank you! |
Sorry for the crossed posts. Please also be careful to use the same python environment to start Jupyter and run the standalone scripts. |
@jklymak yep I am using running both the Jupyter notebook and the standalone python script from a conda environment. |
Bug report
Bug summary
Changing the figure's dpi via
fig.set_dpi()
does not have the desired effect. There are strange things happening when saving or showing the figure as detailed below.Bug 1 - saving
In the following a figure with dpi=200 should be saved in all 3 cases.
Qt5Agg
The outcome using the Qt5Agg backend of this is
i.e. in the first two cases we get the expected 200 dpi figure. In the last case, where the figure dpi is set via
fig.set_dpi
it seems to be ignored and the output image has a dpi of 100.TkAgg
Using the TkAgg backend, the saved figures are as expected (
(960, 1280, 4)
in all cases.)Bug 2 - showing
In the following we would expect to get two identical figures shown, both with dpi=100 and 640x480 pixels large.
Qt5Agg
The output (with Qt5Agg) is the following:
The printed dpi is correctly 100 before showing the figure. After showing, it prints 50. The shown figures have both the correct size, but the figure where dpi is set via
fig.set_dpi
has narrower linewidth and smaller fontsize. It looks exaclty like a figure that would have been expected for dpi=50, just with the wrong pixel size.TkAgg
Using TkAgg backend, the output is correctly printed as
100
in all cases, but the shown figures differ in size; the left (expected) figure is 640x480 pixels, while the right figure is 640x445 pixels.Matplotlib version
Running the same with matplotlib 2.0.2 (all other versions the same) I get
Qt5Agg, saving:
(960, 1280, 4), (960, 1280, 4), (480, 640, 4)
- same bug as above with master.Qt5Agg, showing
100, 100, 100
- printed dpi are all the same, shown figures are the same.TkAgg, saving:
(960, 1280, 4)
in all cases. - same expected behaviour as above.TkAgg, showing
100, 100, 100
- printed dpi are all the same, shown figures differ in same manner as above.The text was updated successfully, but these errors were encountered: