How can I scale inline matplotlib figures within JupyterLab? - python

I'm trying out JupyterLab having used Jupyter notebooks for some time. I use the standard %matplotlib inline magic at the start. I've noticed that JupyterLab displays matplotlib figures much larger than Jupyter notebooks used to.
Is there a way to force JupyterLab to display the images in smaller window/area? I know I can change the figsize I pass when creating the figure but that does not scale the text/labels within the figure and I end up with effectively oversize labels and titles.
Ideally within JupyterLab I'd like to be able to set it up so images fit in an area I can define the size of and if they're larger they get scaled to fit.
I've been reading the JupyterLab docs but nothing leaps out at me at solving this particular problem.
Update: I'm running JupyterLab in Chrome. Chrome displays images up to the full width of the browser window; if the window is smaller than that width that allows the full size of the image, the image is scaled to fit - this is fully dynamic, if you shrink the width of the window the image will rescale on the fly. I changed my figsize parameter (and carefully adjusted font sizes to work) and I got a reasonably sized figure in JuptyerLab. I noticed that when I saved this to a jpg and put that in a powerpoint doc is was quite small (3,2). So I enlarged it, but it became blurred. So I regenerated it with dip=1200. The figure in JuputerLab got bigger. So JupyterLab does not respect the figsize. It's making somekind of judgement based on the number of pixels in the image.
Update 2: This piece of code demonstrates that the Juptyer Lab front end doesn't display images according to the figsize parameter but the product of figsize and dpi (upto the width of the screen, after which it is scaled to fit, presumably by Chrome itself). Note that the font size you see on the screen scales only with dpi and not with figsize (as it should).
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
xys = np.random.multivariate_normal([0.0, 0.0], [[1.0,-0.5],[-0.5,1.0]], 50)
for figsize in [(3,2),(6,4)]:
for dpi in [25,50,100]:
fig = plt.figure(figsize=figsize, dpi=dpi)
ax = fig.add_subplot(1,1,1)
ax.scatter(xys[:,0], xys[:,1])
ax.set_title('figsize = {}, dip = {}'.format(figsize, dpi))
A work around is to work in Jupyter Lab generating figures at a low dpi setting but saving figures at a high dpi setting for publications.

Related

Output images of Matplotlib figures have different sizes across operating systems

One of our tests is failing because the output image is sometimes a slightly different size. On Linux it is 579x517 pixels and on Windows it is 582x520 pixels. I have checked the versions of matplotlib and pandas and they are the same. There are slight differences in matplotlib.rcParams; I've tried changing the parameters that look relevant, but it didn't help.
Is it because the display size is slightly different on the two machines? If I set dpi=99.99 on the savefig on the Windows machine, the output size is 579x517 pixels. I don't want to change this in the application though as it is a bit of a hack just to fix a failing test.
This is the plot function we're using, percentages is a pandas dataframe.
def plot_and_save(percentages, output_directory, filename, title, legend, x_label, y_label,
font_size=16):
"""Plot data and save figure to file."""
matplotlib.rcParams['font.size'] = font_size
ax1 = percentages.plot.bar(color=['#484D7A', '#F6A124'])
ax1.grid(which='major', axis='y', color='#4A4A49', alpha=0.1)
ax1.set_axisbelow(True) # Puts gridlines below the bars
ax1.set(xlabel=x_label, ylabel=y_label, title=title)
ax1.legend(legend, framealpha=1)
output_path = os.path.join(output_directory, filename)
plt.savefig(output_path, bbox_inches='tight')
plt.close()
EDIT:
I have a simpler repro case for this. Running this code on my Linux machine, I get an image of 576x455 pixels.
plt.plot(1)
plt.title('Title')
plt.xlabel('Label')
plt.ylabel('Label')
plt.savefig('test.png', bbox_inches='tight')
The Windows machine produces an image of 576x453 pixels, so if I divide the expected pixel size by the actual pixel size then alter the default image size by that ratio, it should produce an image of the right size.
exp_x, exp_y = 576, 455
plt.plot(1)
fig = plt.gcf()
def_size = fig.get_size_inches()
print('default size', def_size)
new_size = (def_size[0] * exp_x / act_x, def_size[1] * exp_y / act_y)
print('new size', new_size)
fig.set_size_inches(*new_size)
plt.title('Title')
plt.xlabel('Label')
plt.ylabel('Label')
plt.savefig('test.png', bbox_inches='tight')
The output is a 576x454 pixel image, so there must be some rounding going on.
default size [6.4 4.8]
new size (6.4, 4.821192052980132)
This is unexpected behavior. Matplotlib is designed to produce pixel-identical output images on all platforms.
I cannot reproduce the behavior that you describe. Using your minimal example, I get byte-for-byte identical .png images on Linux (Ubuntu 20.04 LTS) and Windows (10), using Matplotlib 3.4.2 on either platform. The resolution is 576×455 pixels, which is what you report for Linux, but not Windows.
For basic tests such as creating a simple figure (like in your example), the Matplotlib test suite renders them on the test system and then compares the final output to a "baseline" image in the source-code repository, such as this simple figure. See "Writing an image comparison test" in the Matplotlib Developer's Guide. The test fixture that handles the comparison has a default tolerance of zero, which is overridden for certain tests, but not for that simple figure. It then just uses numpy.array_equal to compare actual and expected image. In other words: There should be no difference, especially not in resolution. These tests are routinely run on Linux, macOS, and Windows.
So the behavior you describe is highly unexpected and can only be explained by the differences of default values that you hinted at, in matplotlib.rcParams. Arguably the cleanest solution is to use the exact configuration that Matplotlib ships with and adapt your plot routines accordingly. Otherwise consider running the Matplotlib test suite on both systems to narrow down the deviation. Your Windows installation is the more likely culprit.

How to increase matplotlib figure dpi without increasing the window size of the shown plot?

I want to increase the dpi of plots in matplotlib, but the window that displays the plot gets far too large when deviating from the default of
100. I've been using
import matplotlib
matplotlib.rcParams['figure.dpi'] = 300
matplotlib.rcParams['figure.figsize'] = (6.4, 4.8)
to increase the dpi of all plots shown and forcing it to have the default size but it still has the size issue. I would like it so that all plots displayed are uniform in size and dpi without having to individually set this for every figure. Any way to do this?
I think that this won't work as you wish for. The resolution (given in dpi) determines how many points an inch has. The size defines how many inches the figure should have. But none of both sets the number of pixels that your monitor should display for an inch. The thing is that matplotlib and python do not resize plots (only images). So if you save the plot as an image and open it again (with any image viewer) and you click on "show me 100% size", the figure will behave as you intended it to. But while drawing the pixels in a plot (that is what matplotlib does if you call matplotlib.pyplot.draw()), it needs to draw every pixel, which is why one might think that figuresize and dpi both result in a larger plot in matplotlib. Essentially figuresize tells the image viewer how to resize the image when displaying it.
I found this post is particularly useful for explaining the different behavior of size and resolution.

How to zoom charts in jupyterlab

I am plotting some charts with a fixed size.
I need to keep this size because they are later saved and embedded in a Latex document.
While working in jupyter they look too small.
I know I can change the size with matplotlib but this is not my point. I just want jupyter to zoom them (even if that means lower resolution in my notebook).
Is there a way I can increase the size when they are shown without touching matplotlib sizes?

Different figsize definition in Matplotlib 2.0

I have recently updated matplotlib from 1.5 to 2.0
I have noticed a difference in the definition of figsize parameter in plt.subplots:
In matplotlib 1.5, figsize would set the dimension of the window generated
In matplotlib 2.0, figsize would set the dimension of the plot only
So to make an example, I used to set figsize = (23, 8) that would generate a window that almost perfectly fitted the width of my screen.
Now the same parameters generate a window that exceeds the width of the screen, but if I center the window I see that the actual plot fits the window of the screen.
Is there a way to revert to previous convention, where I specify the size of the window?
In case somebody had the same problem, I have found the solution looking at the matplotlib 2.0 documentation.
The change is due to a change in the default screen dpi from 80 to 100, as documented here. This had the effect (among others) of making the figure size appear bigger on the screen. (In order to mitigate this, in fact, the default figure size was reduced from 8x6 inches to 6.4x4.8 inches).
So in order to restore the same window size in matplotlib 2.0, I re-set the figure dpi to 80:
import matplotlib as mpl
mpl.rcParams['figure.dpi'] = 80

How can I keep figure size constant with matplotlib although using pyplot.show()?

Look at the following python example:
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['figure.figsize'] = [8.27, 11.69]
fig = plt.figure()
plt.show() # This line causes problems with figsize
fig.savefig('test.pdf')
If I use "plt.show()" the figure size of test.pdf changes a lot (from
210 x 297 [mm] to
213 x 250 [mm]
What do I have to do in order to keep it constant?
There's a good demo on adjusting image size in matplotlib figures on the SciPy site.
The effect of show() on the figure size will depend upon which matplotlib backend is used. For example, when I used the TkAgg backend (the default on my system) it added about 12 pixels to the width and height of the figure. But when I switched to the WXAgg backend, the figure size was actually reduced.
In addition, manually resizing the window displayed by show() will also change the figure size. Moreover, if displaying the figure would require a window too large for the screen, then the window size will be reduced, and the figure size reduced accordingly.
In any case, your best bet is likely going to be to reset the figure size before rendering the pdf. I.e.:
fig.set_size_inches(8.27, 11.69)
fig.savefig('test.pdf')

Categories