Overview
This document extends the discussion of plots and graphs given in A Student’s Guide to Python for Physical Modeling. Here we give some recipes that work on our installation. If they don’t work on yours, please comment on that, especially if you find a workaround.
This post describes the following:
- Setting figure size
- Importing the SGPniceGraphics module
- Functions and parameters defined in the module
- Fixing crowded graphs
- Saving graphs for modification in other art software
- Typesetting labels with LaTeX
- Other
rc
settings - CMYK color
- Exporting raster images
Setting Figure Size
You can create a figure window of a specific size before plotting with the command
myfigsize = (6, 3)
plt.figure(frameon=False, figsize=myfigsize)
The first keyword argument suppresses the colored panel in the back of the
figure, so you won’t need to delete it by hand in some drawing software. The
second keyword argument specifies the desired width and height of the figure, in
inches (!!). Give it a name (myfigsize
) so that you can set it once and then
use it throughout your code (“Define once, and reuse often.”)
Importing the SGPniceGraphics Module
The SGPniceGraphics module contains a few functions which are described below. Their purpose is to make plots look nicer. You can download the module here.
To use the module, you must first put it in a place where Python can find it. The easiest way is just to put it in your Global Working Directory, along with the script you are working on. Almost as easily, however, you can put it in some central location and ask Python to add that folder to your Path. From the python menu bar in Spyder, select PYTHONPATH manager. Click the “Add path” button and fill in the full path to the central location. (Mac users can obtain the path name as follows: Navigate to the desired folder; select it in Finder; use “Copy”; launch the Terminal; use “Paste.” The path name will appear at the command line; now copy again and paste it into the PYTHONPATH manager.)
You can now issue the command
from SGPniceGraphics import *
in your Python scripts.
Functions and Parameters Defined in the Module
Pfixplot
By default, Matplotlib’s graphs sit on top of a background panel, which is at best clutter if you are embedding a figure in some other document. By default, Matplotlib’s graphs are also surrounded by a box consisting of four “spines” and their tick marks. You may not want that style.
After you create a figure, use my_axis=plt.gca()
to access its axis object.
Then Pfixplot(my_axis)
will make the plot background transparent. It also
removes the top and right axes (“spines”).
Pfixlegend
If you create a legend, for example by
my_legend = my_axis.legend(mylabels)
then by default, the legend will also sit on top of a background panel (i.e., an opaque background), which may obscure something behind it and in any case is clutter.
After you create the legend, you can use Pfixlegend(my_legend)
to make the
legend background transparent.
Pcircsize
Matplotlib’s default choice for circle markers is bigger than that for asterisk
markers, and in my opinion too big. When you create a graph plt.plot
, using
the marker option ‘o’, you can add the keyword argument ,markersize=Pcircsize
to make the circles smaller.
Psavefig
The command
Psavefig('myfilename.pdf')
saves the current figure to a disk file. It just issues plt.savefig
with some
useful options. After saving, you can edit this vector-graphics file in your
favorite art software, such as Inkscape (free) or Adobe Illustrator (not free).
You may instead prefer to save in the .svg format, depending on what art
software you use.
Fixing Crowded Graphs
If you try to make a graph that’s small enough for a journal article, particularly if it has multiple panels, Matplotlib may crowd it too much. For example, labels may collide with other things. One approach is to resize the graph by hand with the mouse before saving it. But maybe you already specified the size you want, and don’t want some other size! Before you start tweaking everything by hand, first try issuing the command
plt.tight_layout()
Often this persuades Matplotlib to do what you want.
Saving Graphs for Modification in Other Art Software
Graphs are “line art.” That is, they consist of geometrical objects like lines, circles, and text. For such graphics, you’ll get the best results if you save them in one of the “vector graphics” formats, because then they can be reproduced at any size without loss of quality. In contrast, a photograph is “bitmap art” — an array of individual pixels — and must be saved in one of the “raster image” formats. Converting from the pixellated image stored in such an image to the pixels actually used in the printer or screen, at the specified magnification, requires interpolation and can result in loss of quality. Line art can be converted to and saved in a raster format, but it’s a one-way process.
File formats like .tif and .jpg are strictly raster. File formats like .eps, .svg, and .pdf can accommodate either vector or raster objects, or both in the same file. If you save a graph from Matplotlib in .eps, .svg, or .pdf format, its vector character will be preserved and you can then edit the file in a vector-art program like Inkscape or Adobe Illustrator. That’s what we recommend.
Even if you save your graph as a .pdf or .svg file, however, text labels (title, axis labels, tick labels, etc.) will probably be rendered as “outlines.” These are genuine vector art, and will remain crisp upon reduction or enlargement. However, they are not “type,” that is, you can’t easily edit them in another software, change font, and so on. If you want that functionality, you’ll need to override a default parameter setting in Matplotlib. One way to do this, for .pdf files, is to include the line
matplotlib.rcParams['pdf.fonttype'] = 42
in your “rc” file (see below). For .svg files, the corresponding line is
matplotlib.rcParams['svg.fonttype'] = 'none'
Even with these lines, your art software may complain that it isn’t able to access (and hence to edit) some of the fonts used in the graphics file. The following step may be needed:
Duplicate all the folders in
~/anaconda/lib/python3.4/site-packages/matplotlib/mpl-data/fonts
and put the copies in a system font folder. In MacOSX, it’s
~/Library/Fonts
(Troubleshooting tips for Mac OS X can be found here.) In Windows, it’s
c:/windows/fonts
For our installation, the folders in question were called afm/
,
pdfcorefonts/
, and ttf/
.
Finally, you can find other advice on fonts here and here. To implement their suggestions, use the following commands:
matplotlib.rcParams['ps.useafm'] = True
matplotlib.rcParams['pdf.use14corefonts'] = True
matplotlib.rcParams['text.usetex'] = True
These commands force the use of Type 1 fonts in saved figures.
Typesetting Labels with LaTeX
You can ask Matplotlib to render all your axis labels etc. using the LaTeX typesetting system. If you know that system, this option can be especially nice for graphics that you intend to embed in a bigger LaTeX document. To choose this option, use these two lines prior to creating any graph:
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
Note that these lines may make your code run slowly. You may wish to leave them commented out until your graph nears its final form.
Even with the above lines, you may find that some labels come out in non-LaTeX fonts. You can try setting them in LaTeX math mode, like this:
ax.set_xlabel(r'$\mathrm{wavelength,\ \ [}\mathsf{nm}\mathrm{]}$')
ax.set_ylabel(r'$\mathrm{reflectance}$')
Notice the “raw string” syntax
r'stuff'
Placing the letter ‘r
’ in front of a string means that we don’t need to escape
the backslashes, which in this context will be sent to LaTeX for processing.
Other matplotlibrc
Settings
A vast number of style settings have defaults that can be changed. For details, visit http://matplotlib.org/users/customizing.html.
Briefly, alternatives to the default settings are maintained in an
initialization file called matplotlibrc
. You can download a copy of this file
here.
Alternatively, proceed as follows. At the IPython prompt, type
import matplotlib as mpl
mpl.get_configdir()
Python will give you a path to a folder containing your initialization file. If that folder’s name, or any component of its path, begins with a period, it may be “hidden” (invisible to your computer’s regular file finder). However, you can copy the path from the IPython console, open a terminal window, and change directory to it, for example
$ cd <<paste path to your folder here>>
$ cp matplotlibrc ~/
$ cp matplotlibrc backup_matplotlibrc
The first line above changes directory (cd) to the hidden folder. The second
line duplicates (copies, “cp
”) the initialization file and puts the new copy
in your home directory (abbreviated “~/
”), where you can see it. The third
line makes a backup, just in case. (The dollar signs are command prompts; you
don’t type them.)
Whichever of these methods you use to obtain matplotlibrc
, it’s a plain-text
file that you can examine in your text editor. It is well documented, but most
of it is commented out. If you see a default setting that you’d like to change,
you have two options:
You can uncomment lines, change values to what you’d like, save the file, and copy it back to where Python expects to find it:
$ cp ~/matplotlibrc <
> You may want to use this option if you have a big project and want to enforce uniform graph style throughout it. Restart IPython after this step.
You can instead leave the
matplotlibrc
file alone and issue override commands within your individual Python scripts. For example,import matplotlib as mpl mpl.rcParams['lines.linewidth'] = 2
Some other useful overrides were mentioned in “Typesetting labels with LaTeX” and “Saving graphs for modification in other art software” above. In addition, for publication you probably will want to override the default font size for labels, and so on.
CMYK Color
There are various ways to specify color. Some publishers demand that submitted color graphics be supplied in the “CMYK” color space, because it corresponds (a bit) more closely to printer inks than the “RGB” color space (which corresponds a bit more closely to the signals sent to a monitor). Matplotlib does not seem to support CMYK color directly. You must postprocess your graphics with some art program, for example Adobe Illustrator for vector graphics like those discussed in this post. Other postprocessing recipes can be found via a web search.
Exporting Raster Images
You may wish to visualize a matrix of numbers as a grayscale image. Chapter 7 of
the book recommends using the function plt.imshow
for this purpose. You may
then wish to draw additional things on your image, for example by using
plt.plot
, and then save it to a pdf file with plt.savefig
. A problem arises,
however, if (as often happens with CCD camera data) your pixel grid is very
coarse. The figure will look fine in the Python figure window, and it may even
look fine when you save it to a file and open it in certain applications, such
as Adobe Illustrator. Nevertheless, when embedded into a document, for example
using LaTeX, it may look terrible: A very obvious new grid, finer than your
pixels but much coarser than the standard 300 pixels per inch, has been imposed
on the image.
Here is one method to address this problem. In Illustrator, create a new layer
behind the main one. Delete the pixel part of your image from the main layer
and paste it (<shift-cmd-V>
) to the new layer. Lock the main layer. Now select
the image and choose Edit > Rasterize
. Choose an appropriate resolution (at
least 300 ppi). Then save the image.
Comments
Where can I find the SGPniceGraphics module?
Thank you very much.
If not, you can access it here:
https://drive.google.com/open?id=0B2xzR6o-pol_N0lVaE5ZbHZ4UGM