Matplotlib is both powerful and complex: being able to adjust every aspect of a plot is powerful, but it's often time-consuming and complex to create a beautiful plot. The Matplotlib 1.5 release makes it easier to achieve aesthetically pleasing results by incorporating a set of styles  .
In this post I'm going to cover setting up a style, demonstrate some of the different styles in action and show how it's easy to alter matplotlibs settings to suit your own tastes.
Each style creates a common look that can be easily applied to all the different plot types. They alter all the main visual aspects of the plot such as xticks, legends and labels. There are 21 styles in the Matplotlib 1.5.1 release, they can be listed by doing:
In : import matplotlib as plt In : plt.style.available Out: # Big list of styles
The ones with distinctive looks are:
This is a set of styles from the Seaborn project . The project is a complement to Matplotlib, providing additional features and improving the default matplotlib aesthetics. Ones I particularly like are seaborn-deep, seaborn-pastel and seaborn-white.
The dark_background style is the standard matplotlib one (e.g. classic) with colours changed for high contrast.
This style comes from Bayesian Methods for Hackers  book. I find it particularly suits scientific graphing by showing the precision of the plot.
This style comes from the plotting system of the same name for the R language : it takes on a lot of contemporary lessons on presenting data, focusing on simplicity.
This style emulates the look and feel of the famous data journalist Nate Silver's site fivethirtyeight.com.
The figures in this post show each of these main styles, plotting some data about an imaginary Product A's sales performance in a year. The first plot is a simple bar chart showing sales by financial quarter, the second plot is a histogram showing how long it takes to sell our imaginary product, and the final plot is a line chart showing how the different marketing channels are creating leads for sales.
There are two ways to set styles, at a library level or for a specific plot. If a style is set at a global level it will effect all figures and plots that are created. For example, if you create multiple plots in a jupyter notebook then they'll all be displayed using the style that's been defined. The call is:
An alternative, is to set the style for the specific plot:
with plt.style.context('ggplot'): # plot command goes here plt.bar([1, 2, 3, 4], [5, 9, 18, 7])
This latter approach is advantageous if you don't want to change every plot that you're creating. I've also found that the fivethirtyeight style changes the legend box in a way I can't revert, but using it with plt.style.context() doesn't change my legend settings.
The styles create much better looking charts, but they don't get us all the way to beautiful plots. Some further alterations, particularly around font selection and font size are necessary. I'm making fairly basic changes, but you can go much further and create your own theme .
The default is for Matplotlib to use a sans-serif font for describing the text and marking up the plot, with a different font for Maths mark-up . It's possible to change these settings by specifying the font and text properties: the common aspects to define are the font type, weight, style, size and colour. The most specific way, is to change the properties of a particular command:
plt.title("Some title", fontname='Ubuntu', fontsize=14, fontstyle='italic', fontweight='bold', fontcolor='green')
The parameters are pretty self-explanatory, with them we're telling Matplotlib to gives us a title using the Ubuntu font at 14 points with italic, bold and green text. This provides a great deal of control over the look of each command, particularly when used with the other properties that are available. However, the downside is that every command becomes quite long-winded.
The alternative to specifying the characteristics at a method level, is to define global settings.
Matplotlib can be configured through global settings which are defined in a configuration file, or at runtime . The pyplot interface to the runtime interface is through pylot.rcParams  dictionary. The common aspects I override are:
plt.rcParams['font.family'] = 'serif' plt.rcParams['font.serif'] = 'Ubuntu' plt.rcParams['font.monospace'] = 'Ubuntu Mono' plt.rcParams['font.size'] = 10 plt.rcParams['axes.labelsize'] = 10 plt.rcParams['axes.labelweight'] = 'bold' plt.rcParams['xtick.labelsize'] = 8 plt.rcParams['ytick.labelsize'] = 8 plt.rcParams['legend.fontsize'] = 10 plt.rcParams['figure.titlesize'] = 12
The font.family specifies that we're using a serif font, if no other setting was used then Matplotlib would use the default serif font that was available. The font.serif and font.monospace set which ever font we want to use, in my case 'Ubuntu' and 'Ubuntu Mono'. We've set the default font size (font.size) to be 10 points, so any size that's not set will use this. The axes commands tell matplotlib to use 10 points and bold for the axes labels (e.g. Sales and Time (FY) in our example plot). The xtick.labelsize and ytick.labelsize sets the numbers along the axis (e.g. Q1 in our example plot), it uses the monospace font that was set earlier. The figure.titlesize specifies the overall figure title.
The pyplot.rcParams interface provides extensive access to configuring matplotlib, these are just the basics, so it's worth looking through. It covers the vast majority of what I want to configure, the only item I haven't been able to alter is the style (e.g. italics) of some titles.
Styles and Fonts example
The following example is the code that was used to create the different figures scattered through this post. Nothing too complex, the only alteration is for fivethirtyeight style to work properly we have to alter the axes a bit: it's personal taste, I just don't like the axis line cutting through the marker for points that are at zero.
import matplotlib.pyplot as plt # Set the style globally # Alternatives include bmh, fivethirtyeight, ggplot, # dark_background, seaborn-deep, etc plt.style.use('seaborn-white') plt.rcParams['font.family'] = 'serif' plt.rcParams['font.serif'] = 'Ubuntu' plt.rcParams['font.monospace'] = 'Ubuntu Mono' plt.rcParams['font.size'] = 10 plt.rcParams['axes.labelsize'] = 10 plt.rcParams['axes.labelweight'] = 'bold' plt.rcParams['axes.titlesize'] = 10 plt.rcParams['xtick.labelsize'] = 8 plt.rcParams['ytick.labelsize'] = 8 plt.rcParams['legend.fontsize'] = 10 plt.rcParams['figure.titlesize'] = 12 # Set an aspect ratio width, height = plt.figaspect(1.68) fig = plt.figure(figsize=(width,height), dpi=400) # Product sales plot ax1 = plt.subplot(221) ax1.bar([1, 2, 3, 4], [125, 100, 90, 110], label="Product A", width=0.8, align='center') plt.xticks([1, 2, 3, 4], ['Q1', 'Q2', 'Q3', 'Q4']) plt.xlabel('Time (FY)') plt.ylabel('Sales') # Font style isn't accessible through rcParams ax1.set_title("Product A sales", fontstyle='italic') # Opportunities by age plot ax2 = plt.subplot(222) population_ages = [1,2, 10,11,13,14,14, 20,20,21,21,22,22,22,23,25,25,25,25,25,27,27, 30,30,30,31,32,32,32,33,33,33,33,34,34,34,34,34,34,36,37,38,39, 41,41,42,42,42,43,45,45,49, 55,57,59, 72,] bins = [0,10,20,30,40,50,60] ax2.hist(population_ages, bins, histtype='bar', rwidth=0.8) plt.xlabel('Age (days)') plt.ylabel('Closed sales') ax2.set_title('Opportunities age', fontstyle='italic') # Marketing channels line plot ax3 = plt.subplot(2,2,(3,4)) y_series = [1,2,3,4,5] x_1 = [5,9,9,12,9] x_2 = [4,3,12,8,14] x_3 = [1,3,4,2,5] ax3.plot(y_series, x_1, linewidth=2, linestyle=':', marker='o', label='web') ax3.plot(y_series, x_2, linewidth=2, linestyle='--', marker='v', label='telemarketing') ax3.plot(y_series, x_3, linewidth=2, linestyle='-.', marker='s', label='sales team') plt.xlabel('Months') plt.ylabel('Marketing leads') plt.xticks([1,2,3,4,5], ['Oct', 'Nov', 'Dec', 'Jan', 'Feb']) #ax2.tick_params(axis='x', pad=8) leg=plt.legend(loc='best', numpoints=1, fancybox=True) # Axes alteration to put zero values inside the figure Axes # Avoids axis white lines cutting through zero values - fivethirtyeight style xmin, xmax, ymin, ymax = ax3.axis() ax3.axis([xmin-0.1, xmax+0.1, ymin-0.1, ymax+0.4]) ax3.set_title('Leads by channel', fontstyle='italic') # Space plots a bit plt.subplots_adjust(hspace=0.25, wspace=0.40) fig.suptitle("Seaborn-white style example") plt.savefig('seaborn-style.svg', bbox_inches='tight')
My favourites are ggplot and fivethirtyeight as they're at the more sparse end of the scale. However, my needs aren't for scientific levels of precision and everyone has their own aesthetic sense.
|||What's new in Matplotlib 1.5|
|||Controlling figure aesthetics|
|||Bayesian Methods for Hackers|
|||For more see Customizing Matplotlib's Plotting Styles and Customizing with style sheets|
|||Writing mathematical expressions in Matplotlib|
|||See Customising Matplotlib for the section on the matplotlibrc file.|