Changing size of MatPlotLib figure with PS backend - matplotlib

I am generating a figure using the PS backend:
import matplotlib
matplotlib.use('ps')
from matplotlib import pyplot as plt
plt.plot((1, 2))
I would like to save the figure:
plt.savefig('test.eps', format='eps', bbox_inches='tight', pad_inches=1.0)
Incidentally, I will make a PNG out of it later (in case it turns out to be relevant to the solution):
gs -q -dSAFER -dBATCH -dNOPAUSE -dUseTrimBox -dEPSCrop -sDEVICE=pngalpha -sOutputFile=test.png test.eps
The result is (PNG viewed in eog):
I would like to change the size of the EPS or the PNG figure, but adding a dpi kwarg to savefig does not change the output. Calling plt.gcf().set_size_inches(10, 10) does nothing as well. How do I make my EPS or PNG file have a higher resolution?
This answer is relevant in that it hints that setting dpi for the ps backend may not be the way to go.
Update
For clarification, it is necessary for me to use the PS backend. At the moment, it is the only one that correctly renders LaTeX colored strings. PGF may or may not do what I want, but I do not have time to research its quirks in depth. I was able to get a hacky solution by adding a -r... argument to gs, but would prefer to control everything from MatPlotLib.

If you create the figure with plt.figure first, you can give the figsize-kwarg. An example:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10, 1)) # figsize in inches
fig.show() # if running in ipython
# plt.show() # if running as a script with "python script_name.py"
To save with a specific dpi, it should be enough with mentioned dpi-kwarg to the figures savefig-method, i.e.
fig.savefig(..., dpi=300)
Note that if you work with plt to save the figure or to plot, it will always work with the active figure, which might not be the figure you expect if you happen to have several of them opened.
UPDATE
1)
Based on the comment by Mad Physicist, the dpi-kwarg apperently does not work with the PS backend. I do not know why.

Related

Custom fonts in Google Colaboratory matplotlib charts

Using custom fonts in matplotlib locally involves storing the .ttfs in the matplotlib/mpl-data/fonts/ttf/ folder, then calling mpl.font_manager._rebuild(), then setting mpl.rcParams['font.sans-serif'].
Is there any way to do this in Google Colaboratory, where it doesn't seem that this ttf folder is accessible?
For example, I'd like to use the Roboto font. After installing, this would be invoked using mpl.rcParams['font.sans-serif'] = 'Roboto'.
The ttf folder is here:
/usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf
So you want to download the ttf there, e.g.:
!wget https://github.com/Phonbopit/sarabun-webfont/raw/master/fonts/thsarabunnew-webfont.ttf -P /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf
matplotlib.font_manager._rebuild()
matplotlib.rc('font', family='TH Sarabun New')
update 2019-12
_rebuild() no longer works. Here's another method which still works.
import matplotlib
import matplotlib.font_manager as fm
!wget https://github.com/Phonbopit/sarabun-webfont/raw/master/fonts/thsarabunnew-webfont.ttf
fm.fontManager.ttflist += fm.createFontList(['thsarabunnew-webfont.ttf'])
matplotlib.rc('font', family='TH Sarabun New')
Wanted to add a full, succinct answer that currently works.
# Download fonts of choice. Here we download Open Sans variants to
# the current directory.
# It's not necessary to download to the share or matplotlib folders:
# /usr/share/fonts/truetype
# /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf
!wget 'https://github.com/google/fonts/raw/master/apache/opensans/OpenSans-Regular.ttf'
!wget 'https://github.com/google/fonts/raw/master/apache/opensans/OpenSans-Light.ttf'
!wget 'https://github.com/google/fonts/raw/master/apache/opensans/OpenSans-SemiBold.ttf'
!wget 'https://github.com/google/fonts/raw/master/apache/opensans/OpenSans-Bold.ttf'
from matplotlib import font_manager as fm, pyplot as plt
# Pick up any fonts in the current directory.
# If you do end up downloading the fonts to /usr/share/fonts/truetype,
# change this to: fm.findSystemFonts()
font_files = fm.findSystemFonts('.')
# Go through and add each to Matplotlib's font cache.
for font_file in font_files:
fm.fontManager.addfont(font_file)
# Use your new font on all your plots.
plt.rc('font', family='Open Sans')
Note, a few times this didn't work properly and the requested font wasn't displayed (even though no error or warning was shown). If that happens, try factory resetting your Colab runtime and running again.
When matplotlib 3.2 is released, it will be easier.
# For now we must upgrade to 3.2 rc first
# !pip install -U --pre matplotlib
import matplotlib as mpl
mpl.font_manager.fontManager.addfont('thsarabunnew-webfont.ttf')
mpl.rc('font', family='TH Sarabun New')
I would like to add my solutions as another reference:
Change the seaborn style
I would strongly recommend this approach as changing the font family can be very troublesome and inconvenient per seaborn design (many of the posts are no longer working on my end in 2022/05). So if you just want to get rid of the stupid default font in matplotlib and seaborn and is OK with Arial, go and type
%matplotlib inline
import matplotlib.style as style
style.use('seaborn-deep')
Changing the font type (borrowed from top answers and tested myself. Restarting the runtime several times if it is not working as expected)
import matplotlib as mpl
import matplotlib.font_manager as fm
from matplotlib import font_manager as fm, pyplot as plt
!wget https://github.com/trishume/OpenTuringCompiler/blob/master/stdlib-sfml/fonts/Times%20New%20Roman.ttf
!wget https://github.com/matomo-org/travis-scripts/blob/master/fonts/Arial.ttf
font_files = fm.findSystemFonts()
# Go through and add each to Matplotlib's font cache.
for font_file in font_files:
fm.fontManager.addfont(font_file)
fm.fontManager.ttflist += fm.createFontList(['Times New Roman.ttf'])
# Use your new font on all your plots.
plt.rc('font', family='serif')
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2*np.pi*t)
plt.plot(t, s)
plt.xlabel('time (s)')
plt.ylabel('voltage (mV)')
plt.title('About as simple as it gets, folks')
plt.show()
Updates on 2022/06/08: Method 1 sometimes doesn't work out in Colab, but it works on the local Jupyter Notebook. It seems that explicitly installing and adding the font types is the only way if you want to customize font types on Colab.

Use a different matplotlibrc for savefig

I am using Jupyter Notebook, with a matplotlibrc style that's consistent with its theme set using jupyterthemes. That plotting style however does not look good if I want to export it to PNG to use it within my other documents.
How do I specify a different matplotlibrc when I do a savefig?
Most matplotlib style settings are applied at the moment the object they apply to is created.
You would hence need to create two different plots, one with the usual style of your notebook and another one with the style from the style file. The latter one would be the one to save.
A decent solution would be to create a plot in a function. You can then call this function within a context, with plt.style.context(<your style>): to give the figure a different style.
import matplotlib.pyplot as plt
def plot():
fig, ax = plt.subplots()
ax.plot([2,3,4], label="label")
ax.legend()
# Plot with general style of the notebook
plot()
# Plot with your chosen style for saved figures
with plt.style.context('ggplot'):
plot()
plt.savefig("dark.png")
#plt.close(plt.gcf()) # if you don't want to show this figure on screen
plt.show()
Relevant here: The matplotlib customizing guide.
Perusing matplotlib/__init__.py reveals a number of functions used for managing rcParams. To update rcParams from a file, use matplotlib.rc_file:
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rc_file('/tmp/matplotlibrc')
plt.plot([0,1], [0,10])
plt.savefig('/tmp/out.png')
with /tmp/matplotlibrc containing
lines.linewidth : 10 # line width in points
lines.linestyle : -- # dashed line
yields
PS. In hindsight, having found rc_file, googling shows it is documented here.

inline images have low quality

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()
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)
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
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.
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()

matplotlib tex renderer gives unexpected error

I am creating a scatter plot with color map based on some values and I am trying to make part of the x_axis label italic (inspired mostly by this post -> https://stackoverflow.com/a/8384685/1093485) but I am getting a LaTeX error that I can not explain myself, I would appreciate if anyone is able to explain what is going wrong with this chunk?
Minimum code required to reproduce problem here:
#! /usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
X = [1257.422648,1298.449197,1339.475746,1419.475471,1455.52309,1460.50202,1485.533655]
Y = [21.84637515,18.19617016,22.29456694,5.228978612,3.888695726,12.36598466,4.201838517]
Z = [44.02797944,9.758071204,21.58997772,64.53887544,53.09630431,8.461254471,291.4311435]
# Enable LaTeX style
rc('text',usetex=True)
# Plot the data
fig=plt.figure()
fig.patch.set_facecolor('white')
ax=fig.add_subplot(111)
s = ax.scatter(X,Y,c=np.log(Z))
ax.set_xlabel(r'Analyte \textit{m/z}')
ax.xaxis.labelpad = 7.5
cb = plt.colorbar(mappable=s,ax=ax)
plt.show()
Commenting the rc('text',usetex=True) causes the plot to show but obviously without italics. The whole traceback is rather large but seems to revolve around this part (if I read it correctly):
RuntimeError: LaTeX was not able to process the following string:
'$1450$'
Anyone have a suggestion on what to do to isolate the problem?

eps cmyk color matplotlib output

I need to output my plots in EPS with the CMYK color space. Unfortunately this particular format is requested by the journal I am submitting my work to!
This discussion was the only one I could find that has addressed the issue but it is more than 2 years old. I was hoping there might be some updates fixing the problem by now.
All my programming is in Python3 and so far I have been saving my plots in PDF which had no problem. But now that I want to plot EPS there is a problem. For example the code bellow prints the simple plot in .png and .pdf but the .eps output is totally blank!
import numpy as np
import matplotlib.pyplot as plt
X=[1,2,3]
Y=[4,5,6]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(X,Y)
fig.savefig('test.eps')
fig.savefig('test.pdf')
fig.savefig('test.png')
So I have two questions:
How can I fix the eps output?
How can I set the eps output color space to CMYK?
Thanks in advance.
I too have the same problem. One workaround I have found is to save plots as .svg and then use a program like Inkscape to convert to eps. I used to be able to save in .eps without any issues and then lost the ability after an update.
Update I was able to solve this problem for my specific setup by changing a few lines in my .matplotlibrc, so I will post the relevant lines here in the hope that it may be helpful to you as well. Note this requires that you have xpdf and ghostscript already installed.
For me the important one was
##Saving Figures
ps.usedistiller : xpdf
But I also have
path.simplify : True
savefig.format : eps
Now I am able to save directly to .eps and include them in LaTeX'ed journal articles...