Plotting How-To's
On this page, you can find quick, helpful tips on how to do a variety of common plotting tasks for the class.
Quick Links:
Download a library of the plotting functions below: plotfuncs.py
Resource links:
- Matplotlib
-- the main plotting library, contains the pyplot
sub-library
- Matplotlib FAQ
- Getting Started With Matplotlib's OO Class Library -- useful info on how to programmatically create multiple, simultaneously shown plots.
- Using matplotlib in a python shell -- creating and controlling plots interactively from the iPython shell.
Make a Line Plot
The mathplotlib.pyplot module has many functions that are very useful for making plots. The functions are part of the mathplotlib library that is included with an EPD installation. Here's a few commonly used functions:
- plot -- takes x and y data lists and creates a plot as per a "format string" that controls colors, line type and symbol type.
- legend - Creates a legend corresponding to the given plots.
- xlabel and ylabel -- create descriptions of the x and y axes respectively.
- title -- creates a title for the plot
- show -- shows the plot in a pop-up dialog window.
For specific information on how to use these and other plotting functions please see the matplotlib documentation.
Example:
This example plots two sets of y-data against a common set of x-data values.
# get the plotting library functions import matplotlib.pyplot as plt #import plot, legend, xlabel, ylabel, title, show xData = [] # Needs to be filled with x-data values yData1 = [] # first y-data list yData2 = [] # second y-data list # put code here to fill yData lists with values corresponding to xData values. plot1 = plt.plot(xData, yData1, 'o-' ) # circles connected by solid line plot2 = plt.plot(xData, yData2, 's:' ) # squares connected by dotted line plt.legend( (plot1, plot2), ('y-data 1', 'y-data 2'), 'best') # legend box placed in "best" location plt.xlabel('x description') # description for the x-axis plt.ylabel('y description') # description for the y--axis plt.title('Plot title') # top title of the plot plt.show() # show the plot in a pop-up dialog window
Note that the data lists could have been represented as a single list of (x, y1, y2) tuples, but that the list would have to be transposed before its elements could used used by plot. After transposing, the x-data would be the zero'th index element and the y-data lists would be the first and second index elements respectively.
Repeating the above code will cause your program to display a single plot window at a time, waiting for you to close that window before showing the next. If you'd like to make multiple plots that show simultaneously, please see the section on Make and Show Multiple Plots.
Here is a very useful encapsulation of the above plotting technique in terms of a reusable function (collapsed for readability):
import matplotlib.pyplot as plt # Needed at the top of your code to bring in the plotting functions def plotData(xData,yData1,yData2, legend1 ,legend2, xLabel, yLabel, title): """Displays a plot of two yData values over the given common xData. xData = the common x-axis points the yData corresponds to. yData1, yData2 = lists of y-axis data that corresponds with the given xData values. legend1, legend2 = the legend text for the respective yData xLabel, yLabel = the labels for the axes in the plot. title = the title of the plot """ # Prey use circles connected by solid line. plot1 = plt.plot(xData, yData1, 'o-' ) # Predators use squares connected by dotted line. plot2 = plt.plot(txData, yData2, 's:' ) # Place legend box in "best" location. plt.legend( (plot1, plot2), (legend1, legend2), 'best') plt.xlabel(xLabel) plt.ylabel(yLabel) plt.title(title) plt.show()
Make and Show Multiple Plots
The problem of in the above example for making a single line plot figure is that if you simply repeat the above code, Python will open up one plot window at a time and wait for you to close that window before showing you the next plot. This is referred to a "blocking" or a "modal" window. Somtimes however, you would like to calculate multiple plots and show them all simultaneously.
In the single line plot example, the plotting "figure" was created automatically and all the calls to make the legends, label the axes, etc. defaulted to that one figure. In a nutshell, to make multiple plots, what you need to do is to explicitly create each plot figure and explicitly add the plots, legends, labels, etc. to that figure -- technically the "axes" object from that figure.
# get the plotting library functions import matplotlib.pyplot as plt #import show, figure xDataA = [] # Needs to be filled with x-data values yDataA1 = [] # first y-data list yDataA2 = [] # second y-data list xDataB = [] # Needs to be filled with x-data values yDataB1 = [] # first y-data list yDataB2 = [] # second y-data list # put code here to fill yData lists with values corresponding to xData values. fig1 = plt.figure() # create an empty plotting figure fig2 = plt.figure() # create an empty plotting figure f1ax = fig1.add_subplot(111) # add a sub-plot to the figure (subplot #1 with 1 row and 1 col). An axes object is returned. f2ax = fig2.add_subplot(111) # add a sub-plot to the figure (subplot #1 with 1 row and 1 col). An axes object is returned. # Create one plot f1ax.plotA1 = f1ax.plot(xDataA, yDataA1, 'o-' ) # circles connected by solid line f1ax.plotA2 = f1ax.plot(xDataA, yDataA2, 's:' ) # squares connected by dotted line f1ax.legend( (plotA1, plotA2), ('y-data 1', 'y-data 2'), 'best') # legend box placed in "best" location f1ax.set_xlabel('x description') # description for the x-axis f1ax.set_ylabel('y description') # description for the y--axis f1ax.set_title('Plot title A') # top title of the plot # Create another plot f2ax.plotA1 = f1ax.plot(xDataB, yDataB1, 'o-' ) # circles connected by solid line f2ax.plotA2 = f1ax.plot(xDataB, yDataB2, 's:' ) # squares connected by dotted line f2ax.legend( (plotB1, plotB2), ('y-data 1', 'y-data 2'), 'best') # legend box placed in "best" location f2ax.set_xlabel('x description') # description for the x-axis f2ax.set_ylabel('y description') # description for the y--axis f2ax.set_title('Plot title B') # top title of the plot plt.show() # show all the plots in modal pop-up windows
Note that the set of plots is still modal -- you have to close all the plot windows before the program will continue.
The pyplot.display() function can be called to update any open plotting windows
Here are some useful plotting functions: (The code has been collapsed for easier readability.)
Note that "plt.show()
"
must be called after these functions in order to display the plotting
window(s).
Plot a list of tuples (t, y1, y2, y3, ...., yn) to create a plot with n lines corresponding to each y-vs-t plot:
import matplotlib.pyplot as plt # assumed to be at top of code def makeTimePlot(data, legendSymbols, tLabel, yLabel, title): """ Make a plot of a list of tuples of at least two elements where all elements in the tuples are plotted against the first value in the tuple data = list of tuples (time, y1, y2, y3, ...) legendSymbols = list of tuples (legend1, symbol1) corresponding to the y-data. symbolx="" means line only, no symbols tLabel, yLabel = the labels for the time and y axis respectively title = the top title for the plot Returns the plt.Figure object created. --show() MUST be called after this function to display the plots!-- """ fig = plt.figure() legSyms = zip(*legendSymbols) fax = fig.add_subplot(111) results = zip(*data) # transpose the data plots = [] for i in range(1, len(data[0])) : plots.append(fax.plot(results[0], results[i], (legSyms[1])[i-1]+'-')) fax.legend(plots, legSyms[0], 'best') # legend box placed in "best" location fax.set_xlabel(tLabel) fax.set_ylabel(yLabel) fax.set_title(title) return fig
Plot a multiple lists of tuples where the first element of the tuple is plotted against the zero'th element of that tuple.
import matplotlib.pyplot as plt # assumed to be at top of code def makeXYPlot(data, legendSymbols, xLabel, yLabel, title): """ Make a plot of multiple lists of x-y tuples data = list of lists of tuples (x, y) legendSymbols = list of tuples (legend1, symbol1) corresponding to the xy-data. symbolx="" means line only, no symbols xLabel, yLabel = the labels for the x and y axis respectively title = the top title for the plot Returns the plt.Figure object created. --show() MUST be called after this function to display the plots!-- """ fig = plt.figure() legSyms = zip(*legendSymbols) fax = fig.add_subplot(111) plots = [] for i in range(len(data)) : results = zip(*data[i]) # transpose the data plots.append(fax.plot(results[0], results[1], (legSyms[1])[i]+'-')) fax.legend(plots, legSyms[0], 'best') # legend box placed in "best" location fax.set_xlabel(xLabel) fax.set_ylabel(yLabel) fax.set_title(title) return fig
Reset the plotting windows
If your code fails during the processing of plots, the matplotlib library unfortunately makes global state changes to your Python execution environment, retaining the plots that were initiated but not shown. This means that the next time you run your code successfully, all the pending plots from previous failed run attemps will show alongside the correct plots. If you run your code again however, since the cache of pending plots has now been cleared, only the expected plots will subsequently be displayed.
To get around this rather annoying and confusing behavior, it is a useful to forcibly reset the pending plotting windows so that they won't be displayed. To do this, simply make a call to the pyplot.close function with the 'all' parameter before you begin your plotting calls. This will close all the pending (and thus invisible) plotting windows, leaving only the desired and expected plots.
import matplotlib.pyplot as plt # This line should be at the top of your code plt.close('all') # close all the pending, invisible plot windows. # Now do your plotting calls...
Creating 3-D Plots
For 3-D plots, you will need two import statements:
import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D
The Axis3D object is used to create 3-D plots. Most of the operations are very similar to those used to make 2-D plots, but with the additional z-data list.
No axis lines? Unfortunately, so far I can tell, Python does not have a feature to show axis lines to be plotted through middle of a 3-D plot. The axes are only shown on the edge of the plotting area. This makes it more difficult visualize the origin and the plotting axis in space relative to the plotted entities, such as a cluster of data. Luckily, most of the problem can be solved by simply adding 3 straight lines on the plot that correspond to the locations of the 3 axes.
The following example makes a 3-D scatter plot of blue dots with 3 straight red lines corresponding to the x, y and z axes:
# The plotting data is in pltTuples, a list of tuples of (x, y, z) plt.close('all') # close all latent plotting windows fig1 = plt.figure() # Make a plotting figure ax = Axes3D(fig1) # use the plotting figure to create a Axis3D object. pltData = zip(*pltTuples) # transpose the list of tuples to separate the x, y and z components. ax.scatter(pltData[0], pltData[1], pltData[2], 'bo') # make a scatter plot of blue dots from the data # make simple, bare axis lines through space: xAxisLine = ((min(pltData[0]), max(pltData[0])), (0, 0), (0,0)) # 2 points make the x-axis line at the data extrema along x-axis ax.plot(xAxisLine[0], xAxisLine[1], xAxisLine[2], r') # make a red line for the x-axis. yAxisLine = ((0, 0), (min(pltData[1]), max(pltData[1])), (0,0)) # 2 points make the y-axis line at the data extrema along y-axis ax.plot(yAxisLine[0], yAxisLine[1], yAxisLine[2], 'r') # make a red line for the y-axis. zAxisLine = ((0, 0), (0,0), (min(pltData[2]), max(pltData[2]))) # 2 points make the z-axis line at the data extrema along z-axis ax.plot(zAxisLine[0], zAxisLine[1], zAxisLine[2], 'r') # make a red line for the z-axis. # label the axes ax.set_xlabel("x-axis label") ax.set_ylabel("y-axis label") ax.set_zlabel("y-axis label") ax.set_title("The title of the plot") plt.show() # show the plot