63

I'm loading a TIF file with scikit-image and displaying it inline in an ipython notebook (version 2.2.0). This works, however, the image is quite small when first displayed, and when I resize it using the draggable handle on the bottom right of the image, it just rescales the image while retaining the resolution of the original, so it's very blurry when enlarged. It's basically as if ipython is converting my image into a thumbnail on the fly.

I've tried using matplotlib's plt.imshow() as well, which has the exact same result. I'm starting the notebook with ipython notebook --pylab inline.

from skimage import io
import matplotlib.pyplot as plt
image_stack = io.MultiImage("my_image.tif")
image = image_stack[0]  # it's a multi-page TIF, this gets the first image in the stack

io.imshow(image)  # or plt.imshow(image)
io.show()  # or plt.show()
jimbotron
  • 655
  • 1
  • 5
  • 8

4 Answers4

63

To change the "%matplotlib inline" figure resolution on the notebook do:

import matplotlib as mpl
mpl.rcParams['figure.dpi']= dpi

I recommend setting the dpi somewhere between 150 and 300 if you are going to download/print the notebook. Ensure that %matplotlib inline runs before the mpl.rcParams['figure.dpi']= dpi otherwise the magic command resets the dpi to its default value (credits to @fabioedoardoluigialberto for noticing this).

The snipppet below only changes the dpi of figures saved through the savefig method, not of inline generated figures.

import matplotlib as mpl
mpl.rc("savefig", dpi=dpi)
Frâncio Rodrigues
  • 2,190
  • 3
  • 21
  • 30
  • 3
    This is actually the correct and simplest answer. Thanks – Garini Nov 29 '17 at 11:18
  • 5
    Notice that if you put everything in the same cell you get wrong behavior. I assume this is because the magic command `%matplotlib` triggers asynchronous behavior which sets the dpi *after* the `mpl.rcParams['figure.dpi'] = dpi` command gets executed. A quick solution is to split the command into a different cell. – fabioedoardoluigialberto Aug 30 '18 at 15:25
  • 1
    Humm good point. I did some testing and it seems that the `%matplotlib inline` magic command resets the dpi to the matplotlib default (probably whatever is set at the matplotlib.rc file). If you run the `mpl.rcParams['figure.dpi']= dpi` after the magic command it should be fine. – Frâncio Rodrigues Aug 30 '18 at 20:34
  • Just adding that `%matplotlib inline` is no longer required for Python 3, but this solution still works. Just added it after the import commands. – Cebbie Jan 05 '21 at 20:16
  • 1
    Oh man, this is gold. This will definitely get me out of the friend zone with the senior analyst. – Edison Jun 22 '22 at 10:09
53

According to https://www.reddit.com/r/IPython/comments/1kg9e2/ipython_tip_for_getting_better_quality_inline/

You could also execute this magic in your cell:

%config InlineBackend.figure_format = 'svg'

The print quality will look significantly better. You can also change svg to retina, to use higher-res PNGs (not as nice). Nevertheless, note that if your picture becomes too complicated, the svg picture will have a much larger size than that of the retina picture

Costa Huang
  • 1,415
  • 15
  • 15
  • 6
    This should be more widely known :) – Ricky McMaster Jul 01 '18 at 14:54
  • 1
    For some reason that completely messes up Jupyter notebook page for me. –  Aug 30 '19 at 13:44
  • 1
    @IgorFilippov Sorry to hear that. Maybe try the ``%config InlineBackend.figure_format = 'retina'``? – Costa Huang Sep 25 '19 at 18:02
  • 1
    NB SVG cannot be `nbconvert` to latex yet. https://github.com/jupyter/nbconvert/issues/244 – Jeff Jan 28 '20 at 05:26
  • It works as it should, but it makes my notebook way slower. So it might be worth considering adding this only after you're ready building the notebook and only need to export it – Jem May 24 '22 at 09:30
7

The resolution of inline matplotlib figures is downscaled a bit from what you would see in a GUI window or saved image, presumably to save space in the notebook file. To change it, you can do:

import matplotlib as mpl
mpl.rc("figure", dpi=dpi)

Where dpi is some number that will control the size/resolution of the inline plots. I believe the inline default is 80, and the default elsewhere with matplotlib is 100.

The reason scaling the resulting plot by dragging the handle doesn't work is that the plot is rendered as a png, so scaling it zooms but does not change the intrinsic resolution.

mwaskom
  • 46,693
  • 16
  • 125
  • 127
  • 1
    Also, you can adjust the size of the figure: ``plt.figure(figsize=(5, 10)``, which should make your images more detailed on screen. – Stefan van der Walt Aug 20 '14 at 22:26
  • 1
    @mwaskom - this made no difference – jimbotron Aug 21 '14 at 15:02
  • @StefanvanderWalt this throws: FormatterWarning: Exception in image/png formatter: width and height must each be below 32768 (which they both are, so I don't know how to interpret this exception) – jimbotron Aug 21 '14 at 15:02
  • You'll need to be more specific about exactly what you did and exactly what the outputs looked like, or else we probably won't be able to help more. You can edit the original question with this information. – mwaskom Aug 21 '14 at 19:16
  • See also http://stackoverflow.com/questions/16905028/why-is-matplotlib-plot-produced-from-ipython-notebook-slightly-different-from-te which explains how ipython matplotlib defaults differ from normal – patricksurry Nov 04 '15 at 23:32
  • 1
    In order for this to work, I have to execute `%matplotlib inline` before the `mpl.rc(..)` call. – william_grisaitis Jun 16 '16 at 17:53
  • See [this answer](https://stackoverflow.com/a/46161614/614241) for why this doesn't work as expected. If you want to save the image without displaying it you can always use `savefig` [command](https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.savefig.html) with `dpi` argument and this has nothing to do with whether you are in a notebook or not. – kon psych Nov 21 '17 at 21:09
2

Assuming this is the same thing that happens with iPython notebook (with %matplotlib inline) when you go to drag and resize the image, the fix is fairly simple.

If you just create a figure with a different default size, then the resolution also increases with the size of the default (Change resolution of imshow in ipython). For example:

fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(111)
ax.imshow(array)

Something like this should increase the resolution of the thing you are trying to plot. This seemed to work for me with your code:

from skimage import io
import matplotlib.pyplot as plt
%matplotlib inline

image_stack = io.MultiImage("my_image.tif")
image = image_stack[0] 

fig = plt.figure(figsize= (20,20)) #create an empty figure to plot into with 20x20 size
io.imshow(image)
io.show()
Community
  • 1
  • 1
nanoman
  • 51
  • 1
  • 9