Summary: there are lots of python libraries that you can use for plotting, but Matplotlib has become a de facto standard
You can get more information about python on the JYP's recommended steps for learning python page.
You can get more information on plotting maps in the Cartopy + Iris section and the basemap section, with examples on the JYP's map room page. Note: there will be no python3 support in basemap, and basemap is being slowly replaced by cartopy
matplotlib official website: Matplotlib web site
matplotlib help on stack overflow: matplotlib help
The matplotlib documentation is good, but not always easy to use : the package is powerful, there are lots of ways to do the same thing and it's easy to get lost.
There are lots of online tutorials that often don't show much more than a simple scatter plot with basic page setup.
This page will hopefully give you some keys to become (progressively) a matplotlib power user.
A good way to start with matplotlib is to quickly read this section, practice, and read this section again (and again)
import matplotlib.pyplot as plt
import matplotlib as mpl
my_page = plt.figure()
win_1 = plt.figure() win_2 = plt.figure()
(0, 0)
is the bottom left of the figure, and (1, 1)
is the top rightmy_page = plt.figure()
: the ratio of the default figure is landscape
, because it is 33% larger than it is high. Creating a default figure will be OK most of the time!my_page = plt.figure(figsize=(width, height))
: create a figure with a custom ratiowidth
and height
are supposed to be in inches (1 inch = 2.54 cm)my_page = plt.figure(figsize=(8.3, 11.7))
: create a figure that will theoretically fill an A4 size page in portrait mode (check Dimensions Of A Series Paper Sizes if you need more details about standard paper sizes)my_plot = my_page.add_subplot(1, 1, 1)
or my_plot = my_page.subplots()
add_subplot(nrows, ncols, index)
top_plot = my_page.add_subplot(3, 1, 1) mid_plot = my_page.add_subplot(3, 1, 2) bot_plot = my_page.add_subplot(3, 1, 3)
subplots
is more efficient than add_subplot
, when there are lots of plots on a pageplot_array = my_page.subplots(3, 1) top_plot = plot_array[0] mid_plot = plot_array[1] bot_plot = plot_array[2]
my_page, my_plot = plt.subplots()
my_page, plot_array = plt.subplots(nrows=3, ncols=1, figsize=(8.3, 11.) # A4 portrait) top_plot = plot_array[0] mid_plot = plot_array[1] bot_plot = plot_array[2]
add_subplot
function), you can use the subplot_kw
parameter. For example, if all the plots will be created with cartopy, using the Robinson projection, the example above becomes:my_page, plot_array = plt.subplots(nrows=3, ncols=1, figsize=(8.3, 11.), # A4 portrait subplot_kw=dict(projection=ccrs.Robinson()))
my_page.add_axes([left, bottom, width, height])
my_page.clear()
or my_page.clf()
or plt.clf()
: clear the (current) figuremy_plot.clear()
or my_plot.cla()
: clear the (current) axisplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
my_page.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
hspace
/wspace
is the amount of height/width between the subplotshspace=0.1
is enough for just displaying the ticks and the labels, without the axis namehspace=0
to stick the plots together verticallymy_plot.set_xticks([])
my_page.subplots_adjust(right=0.75)
will leave 25% on the right of the page for adding a legend outside of a plotpl_x_bottomleft, pl_y_bottomleft, pl_width, pl_height = my_plot.get_position().bounds
my_plot.set_position( (pl_x_bottomleft, pl_y_bottomleft, pl_width, pl_height * 0.5) )
my_page.savefig('my_plot.pdf')
: save the figure to a pdf filemy_page.savefig('my_plot.png', dpi=200, transparent=True, bbox_inches='tight')
: save the figure to a png file at a higher resolution than the default (default is 100 dots per inch), with a transparent background and no extra space around the figureplt.show()
_r
to the name, e.g., viridis_r
zorder=NN
parameter when creating objects. NN
is an integer where 0 is the lowest value (the farthest from the eye), and objects are plotted above objects with a lower zorder valuematplotlib_object.set_order(NN)
to change the order after an object has been createdalpha
parameter where 0.0
means that the object is completely transparent, and 1.0
means completely opaquemy_plot.scatter(…, alpha=0.7)
show()
) a plot, because matplotlib expects to be able to display the figure on a screen (with an X server running) by default.plot
function will be faster for scatterplots where markers don't vary in size or colormy_plot.set_xlim(x_leftmost_value, x_rightmost_value)
my_plot.set_xlabel(x_label_string, fontsize=axis_label_fontsize)
my_plot.set_xlabel('A closer label', labelpad=-20
)my_plot.set_xticks([])
, otherwise the X axis label will not be printedcartopy 0.17.0
my_plot.set_xticks(x_ticks_values, minor=False)
(set_xticks)my_plot.set_xticks([])
my_plot.set_xticklabels(x_tick_labels, minor=False, fontsize=ticklabels_fontsize)
(set_xticklabels)x_tick_labels
is a list of strings that has the same length as x_ticks_values
.>>> x_tick_values = np.arange(0, 1, 0.2) >>> x_tick_values.tolist() [0.0, 0.2, 0.4, 0.6000000000000001, 0.8] >>> x_tick_values.round(decimals=1).tolist() [0.0, 0.2, 0.4, 0.6, 0.8] >>> x_tick_labels = [ '%.1f' % (t_val,) for t_val in x_tick_values ] >>> x_tick_labels ['0.0', '0.2', '0.4', '0.6', '0.8'] >>> x_tick_labels[0] = 'START' >>> x_tick_labels[-1] = 'END' >>> x_tick_labels ['START', '0.2', '0.4', '0.6', 'END']
set_xticks
and set_yticks
my_plot.grid(True, linestyle=“--”, linewidth=0.5, color='.25',zorder=some_value)
zorder
value to determine if the grid lines should be above or below other parts of the plot!ax.yaxis.grid(True)
ax.xaxis.grid(True)
myplot.gridlines
! See Cartopy map gridlines and tick labelsmpl.rcParams['lines.markersize'] ** 2
⇒ 36mpl.rcParams['lines.linewidth']
⇒ 1.5plot
, all the markers have the same attributes, and for scatter
the attributes can be the same, or specified for each markermarker
(marker type), c
(color), s
(size), linewidths
(linewidth of the marker edges), edgecolors
_r
at the end of the colormap namemy_cmap.N
0
to my_cmap.N - 1
. Note that the index will saturate below 0
and above my_cmap.N - 1
>>> my_cmap.N 256 >>> my_cmap(-1) # Same as ano_cmap(0) (0.3686274509803922, 0.30980392156862746, 0.6352941176470588, 1.0) >>> my_cmap(0) (0.3686274509803922, 0.30980392156862746, 0.6352941176470588, 1.0) >>> my_cmap(1) (0.36186082276047676, 0.3185697808535179, 0.6394463667820068, 1.0) >>> my_cmap(255) (0.6196078431372549, 0.00392156862745098, 0.25882352941176473, 1.0) >>> my_cmap(256) # Same as ano_cmap(255) (0.6196078431372549, 0.00392156862745098, 0.25882352941176473, 1.0) >>> my_cmap(257) # Same as ano_cmap(255) (0.6196078431372549, 0.00392156862745098, 0.25882352941176473, 1.0)
my_cmap.set_bad(color='k')
: color to be used for masked valuesmy_cmap.set_over(color='k')
: color to be used for high out-of-range values if extend
is specified and is 'both' or 'max'. Default color is my_cmap(my_cmap.N - 1)
my_cmap.set_under(color='k')
: color to be used for low out-of-range values if extend
is specified and is 'both' or 'min'. Default color is my_cmap(0)
cb.ax.tick_params(labelsize='xx-large')
(where cb
is a colorbar object)my_figure.suptitle('Figure title', x=xloc_in_normalized_coordinates, y=yloc_in_normalized_coordinates, …)
my_plot.set_title('Plot title', …)
fontsize
: size in points, or (better!) string specifying a relative size (xx-small
, x-small
, small
, medium
, large
, x-large
, xx-large
)label=
keyword when creating/updating a plotlabel=
keyword for these elements, or add a _
at the front of the label stringsbbox_to_anchor
parameterbbox_to_anchor
are in normalized coordinates of the current (sub)plot:(0, 0)
is the lower left corner of the plot, and (1, 1)
the upper right cornerlegend(… bbox_to_anchor=(1.05, 1.), loc='upper left', …)
will put the upper left corner of the legend slightly right ((1.05, 1.)
) of the upper right corner ((1, 1)
) of the plotplt.subplots_adjust(right=0.75)
will make all the plots use 75% on the left of the page, and leave 25% on the right for the legendmpl.rcParams['figure.figsize']
([6.4, 4.8]
)mpl.matplotlib_fname()
You may need to create a plot offline when your network connection is not good enough, you don't have an X server running to display the plot (possibly because the script is running on a cluster), etc… This is easily done with the following code:
# offline_plot = False offline_plot = True import matplotlib as mpl if offline_plot: # Define the graphic back-end BEFORE importing pyplot mpl.use('Agg') # Import the rest of the matplotlib based modules import matplotlib.pyplot as plt [ ...your actual code... ] # Done at last! Save the result my_page.savefig(out_name, dpi=300, transparent=True, bbox_inches='tight') if not offline_plot: # Enter the interactive mode to display the plot plt.show()
Note: see also CanvasAgg demo for a pure offline plot, and How to use Matplotlib in a web application server. But the code above is much easier!
e.g. You need to plot a masked variable, but you don't want the masked areas to be white
# make the background dark gray (call this before the contourf) plt.gca().patch.set_color('.25') plt.contourf(d) plt.show()
Some useful notes and links that cannot be placed (yet) in a section of the main page
[ PMIP3 Wiki Home ] - [ Help! ] - [ Wiki syntax ]