2D figures

In most cases, the most simple figures are the best. In what follows, we are going to cover some simple plotting methods that include the most common plot types. The module matplotlib offers several different way to create the same figure, we'll try to do our best in introducing only the simplest concepts. We are only going to go through some of the keyword arguments of matplotlib's functions, though. Therefore, look for more parameters in the matplotlib example galleries, or in the docstrings of plot, hist, pcolor, contour and contourf functions.

In [1]:
# import libraries
%pylab inline 
Populating the interactive namespace from numpy and matplotlib

Simple function and data plot

In many cases, we would like to plot some data or an analytic function. If we want to plot a function, then first we have to create some points that we evaulate later with the function. In the next example, we are going to evaulate the function $\sin(x)$ on the $[-\pi,\pi]$ interval in 25 points.

In [2]:
x=linspace(-pi,pi,25);
y=sin(x);

The plotting is done by the plot function.

In [3]:
plot(x,y)
Out[3]:
[<matplotlib.lines.Line2D at 0x7f181a6130f0>]

Let us examine some keyword arguments, that alter the output of the plot command. The keyword color changes the colour of the plotted data. This figure contains all the colours used in matplotlib. Let us change the color of the curve in the next figure.

In [4]:
plot(x,sin(x),color='red')
Out[4]:
[<matplotlib.lines.Line2D at 0x7f1812025400>]

With the help of the keyword linewidth, we can change the width of the plotted line.

In [5]:
plot(x,sin(x),linewidth=3)
Out[5]:
[<matplotlib.lines.Line2D at 0x7f1811f91710>]

The keyword linestyle sets the style of the plotted line. Its value can be either a string with a meaning, like 'dashed', or some symbols.

In [6]:
plot(x,sin(x),linestyle='dashed') # dashed line
Out[6]:
[<matplotlib.lines.Line2D at 0x7f1811efd630>]

If we give it an empty string, and we use the keyword marker, then the figure is only going to displey points. This way, we can also plot unordered data.

In [7]:
plot(x,sin(x),linestyle='',marker='o')
Out[7]:
[<matplotlib.lines.Line2D at 0x7f1811ee84e0>]

By using both keywords at once, the markers are going to be connected by a line in the given style.

In [8]:
plot(x,sin(x),linestyle='dashed',marker='s')
Out[8]:
[<matplotlib.lines.Line2D at 0x7f1811e50438>]

Of course, we can set many more keyword arguments. What do they do?

In [9]:
props=dict(color='green', linestyle='dashed', marker='o', markerfacecolor='blue',
               markeredgecolor='red',markeredgewidth=2, markersize=12 )

plot(x, sin(x), **props)
Out[9]:
[<matplotlib.lines.Line2D at 0x7f1811db6be0>]

We can set the axis limits with the xlim() and ylim() commands, which have to be called after the plot function.

In [10]:
plot(x,sin(x))
xlim(-pi,pi);

The plot function has many more keyword arguments. In its docstring, these are very well documented.

In [11]:
?plot

If we give two or more plot commands after each other in one cell, then two or more functions are going to be plotted in the figure.

In [12]:
plot(x,sin(x))
plot(x,cos(x))
Out[12]:
[<matplotlib.lines.Line2D at 0x7f1811db0400>]

A special case is when one plot command only contains a single point. With this method, we can mark interesing points on the function graph.

In [13]:
plot(x,sin(x))
plot(1,sin(1),'o')
Out[13]:
[<matplotlib.lines.Line2D at 0x7f1811cd6a20>]

If we plot more functions, then the label keyword and the legend() function help in matching the functions to the plotting styles.

In [14]:
plot(x,sin(x),label='sin(x)',color='red',linestyle='-',linewidth=3)
plot(x,cos(x),label='cos(x)',color='blue',linestyle='--',linewidth=3)
legend()
Out[14]:
<matplotlib.legend.Legend at 0x7f1811c07240>

The functions xlabel() and ylabel() create axis labels.

In [15]:
plot(x,sin(x))
xlabel(r'ido',fontsize=20)
ylabel('kiteres',fontsize=20)
Out[15]:
Text(0,0.5,'kiteres')

The functions xticks() and yticks() format the axis ticks. Have a look at their docstrings!

In [16]:
plot(x,sin(x))
xticks([-pi,-pi/2,0,pi/2,pi],[r'$-\pi$',r'$-\pi/2$',r'$0$',r'$\pi/2$',r'$\pi$'],fontsize=20);
yticks(linspace(-1,1,9)); 
# what has changed?

Finally, let us look at an example, that uses almost all of the above tricks, and that creates a publication-quality figure.

In [17]:
plot(x,sin(x),label='sin(x)',color='red',linestyle='-',linewidth=3)
plot(x,cos(x),label='cos(x)',color='blue',linestyle='--',linewidth=3)
xticks([-pi,-pi/2,0,pi/2,pi],[r'$-\pi$',r'$-\pi/2$',r'$0$',r'$\pi/2$',r'$\pi$'],fontsize=20);
yticks(linspace(-1,1,3),fontsize=20);
xlabel('Time',fontsize=20)
ylabel('Desplacement',fontsize=20)
legend(loc='upper left',fontsize=20)
xlim(-pi,pi)
grid(True) # what does this function do?

Many other plotting functions inherit the same keyword arguments from the original plot function. For example, we can use the same styling arguments for the 3D plotting as well. Labelling and formatting the axes is also general in matplotlib, not just for the plot() command.

Plotting measurement data with error

We can even plot measurement data with the plot() function. But measurement data is often loaded with error. Let us see a simple example! In the following, we are going to use a real sunspot measurement datafile for the sample commands. The datafile can be founs in the data subdirectory as SN_m_tot_V2.0.txt. First, we have to load the content of the file into Python. We can do that by using the loadtxt function of the numpy module. This function loads simply structured data into an array.

In [18]:
dat=loadtxt('data/SN_m_tot_V2.0.txt'); # loading sunspot datafile

The above command loaded into the dat array the data from the file. The third column of the file contains the time of the observation in years, the fourth contains the number of sunspots observed. Let's plot the last hunfred points from the datafile.

In [19]:
plot(dat[-100:,2],dat[-100:,3],linestyle='',marker='o')
Out[19]:
[<matplotlib.lines.Line2D at 0x7f18119ff240>]

The fifth column contains the statistical errors of the measurements. If we want to see the datapoints and their error on the same figure, we can do it by using the errorbar() function.

In [20]:
errorbar(dat[-100:,2],dat[-100:,3],dat[-100:,4],linestyle='',marker='o')
Out[20]:
<Container object of 3 artists>

The errorbar() function expects three columns, the first two for the position of the datapoints, and the third for the error. Similary to plot(), we can control its appearance through keyword arguments. The next example illustrates some of them:

In [21]:
props=dict(linestyle='',marker='o',ecolor='green',capsize=4,capthick=2)
errorbar(dat[-100:,2],dat[-100:,3],dat[-100:,4],**props)
Out[21]:
<Container object of 3 artists>

We can get further information on the options from the docstring:

In [22]:
?errorbar

We can put the two types of plots onto one figure as well. The enxt example shows the result of the simultaneous usage of the plot() and errorbar() functions.

In [23]:
errorbar(dat[-300:,2],dat[-300:,3],dat[-300:,4],linestyle='',marker='o')
plot(dat[-300:,2],70*cos(2*pi/11*dat[-300:,2]-pi*0.25)+70,color='red',linewidth=3)
Out[23]:
[<matplotlib.lines.Line2D at 0x7f1811b6e518>]

Histograms

Histograms are important tools for statistical analysis. Last time we already saw a simple example for the creation of a histogram with the function hist(). Let's see further examples for keyword arguments of the hist function! First, let us generate some random numnbers.

In [24]:
measurement1=randn(10000);
measurement2=random.normal(2,0.5,10000);

As we;ve already seen, the most simple way of creating a histogram is:

In [25]:
hist(measurement1)
Out[25]:
(array([  13.,   96.,  463., 1452., 2548., 2731., 1817.,  703.,  159.,
          18.]),
 array([-3.75021444, -3.02388996, -2.29756549, -1.57124101, -0.84491653,
        -0.11859205,  0.60773243,  1.33405691,  2.06038139,  2.78670587,
         3.51303035]),
 <a list of 10 Patch objects>)

If we want to increase the histogram's resolution, we can achive it through the bins argument. If bins receives a number as an input, then the number of 'categories' will be equal to bins on the histogram.

In [26]:
hist(measurement1,bins=100);

But we can give the edges of the bins arbitrarily with the help of a list!

In [27]:
hist(measurement1,bins=[-2,0,1,2,3]);

If we would like to use a continuous line instead of bars, then the keyword argument histtype can be used.

In [28]:
hist(measurement1,histtype='step');

More histograms can be put onto one figure.

In [29]:
hist(measurement1,bins=100,linewidth=0);
hist(measurement2,bins=100,linewidth=0);

If two distributions would cover each other by too much, the keyword alpha helps in making them transparent to a certain degree.

In [30]:
hist(measurement1,bins=100,linewidth=0,alpha=0.5);
hist(measurement2,bins=100,linewidth=0,alpha=0.5);

Bivariate plotting, contour plots, heatmaps

The display of bivariate functions is very similar to that of univariate functions, and begins with sampling or data collection. The already known linspace() function combined with the meshgrid() function can sample a 2D parameter space:

In [31]:
x2,y2 = meshgrid(linspace(-4,4,50),linspace(-3,3,50)) # sampling points
z2 = sin(x2) ** 10 + cos(10 + y2 * x2) * cos(x2)          # function evaluation

The above code thus generated three arrays. The first two contain the $x$ and $y$ coordinates of sampling points in a ford of two 2D arrays. The variable z2 contains the value of the function at those points. We only have to plot now! This is done by the pcolor() function.

In [32]:
pcolor(x2,y2,z2)
Out[32]:
<matplotlib.collections.PolyCollection at 0x7f18117d96d8>

The meaning of the colour code can be visualized with the help of the colorbar() function.

In [33]:
pcolor(x2,y2,z2)
colorbar()
Out[33]:
<matplotlib.colorbar.Colorbar at 0x7f18115b6908>

There are many colour scales. Each has its own advantages and disadvantages. The colour scales of matplotlib can be evoked by the keyword cmap using their names.

In [34]:
pcolor(x2,y2,z2,cmap='magma')
colorbar()
Out[34]:
<matplotlib.colorbar.Colorbar at 0x7f1811366c18>

Bivariate functions can be visualized using contour lines. A countour line consists of points, where the given bivariate function has the same value. The function contour() generates these contour lines for us:

In [35]:
contour(x2,y2,z2)
Out[35]:
<matplotlib.contour.QuadContourSet at 0x7f18110bb160>

If we are only interested in given contour values, we can address them by using the levels keyword.

In [36]:
contour(x2,y2,z2,levels=[-0.5,0,0.5])
Out[36]:
<matplotlib.contour.QuadContourSet at 0x7f18110b1ef0>

Uding the clabel() function, the values are displayed on the lines.

In [37]:
cs=contour(x2,y2,z2,levels=[-0.5,0,0.5])
clabel(cs)
Out[37]:
<a list of 28 text.Text objects>

The function contourf unites the good properties of the pcolor() and contour() functions. Its coloured figures fit eh shape of the visualized function better.

In [38]:
contourf(x2,y2,z2)
Out[38]:
<matplotlib.contour.QuadContourSet at 0x7f180b701b00>

The keyword levels can increase the resolution.

In [39]:
contourf(x2,y2,z2,levels=linspace(-1.5,1.5,100))
colorbar()
Out[39]:
<matplotlib.colorbar.Colorbar at 0x7f1811555da0>

It may occur, that the sampling is not uniform. Then, we can visualize datapoints using triangulation. Let us create some random points on the plane!

In [40]:
tx,ty = [8*rand(50*50)-4,6*rand(50*50)-3]                 # sampling points

Let us evaulate the function in these random points!

In [41]:
tz = sin(tx) ** 10 + cos(10 + ty * tx) * cos(tx)          # function evaluation

If the data points are unordered, then we have to use the functions tripcolor(), tricontour() and tricontourf() instead of the functions pcolor(), contour() and contourf() in the same manner as before.

In [42]:
tripcolor(tx,ty,tz)
Out[42]:
<matplotlib.collections.PolyCollection at 0x7f181150e898>
In [43]:
tricontourf(tx,ty,tz,linspace(-1.5,1.5,100))
Out[43]:
<matplotlib.tri.tricontour.TriContourSet at 0x7f180b398e48>

Vector fields, arrows and field lines

In physics, we use vector fields quite often. Let us think of meteorology or electrodynamics. Let us create the gradient of the previously plotted function. The gradient vector in the plane is given by the following:

In [44]:
u=-y2*sin(x2*y2 + 10)*cos(x2) + 10*sin(x2)**9*cos(x2) - sin(x2)*cos(x2*y2 + 10)
v=-x2*sin(x2*y2 + 10)*cos(x2)

The funciton quiver() assigns a vector given by the arrays u and v to every point defined on the plane by the arrays x2 and y2. Thus, in every point (x2[i],y2[i]), there is a vector (u[i],v[i])!

In [45]:
quiver(x2,y2,u,v)
Out[45]:
<matplotlib.quiver.Quiver at 0x7f180b24aa90>

Let us draw only every third vector in red and a bit thicker.

In [46]:
quiver(x2[::3, ::3], y2[::3, ::3], u[::3, ::3], v[::3, ::3],
    color='red',width=0.005)
Out[46]:
<matplotlib.quiver.Quiver at 0x7f180b172550>

For further details, see the documentation.

In [47]:
?quiver

An alternative to quiver() is the plotting of the field lines, or streamplot().

In [48]:
streamplot(x2[::3, ::3], y2[::3, ::3], u[::3, ::3], v[::3, ::3])
Out[48]:
<matplotlib.streamplot.StreamplotSet at 0x7f180adab470>

For further details, see the documentation.

In [49]:
?streamplot

streamplot() and quiver() may be used together with pcolor() and contour-making routines.

In [50]:
pcolor(x2,y2,z2)
colorbar()
quiver(x2[::2,::2],y2[::2,::2],u[::2,::2],v[::2,::2],color='white',width=0.005)
Out[50]:
<matplotlib.quiver.Quiver at 0x7f180abdfeb8>
In [51]:
contourf(x2,y2,z2,levels=linspace(-1.5,1.5,100))
colorbar()
streamplot(x2[::3, ::3], y2[::3, ::3], u[::3, ::3], v[::3, ::3],color='white')
Out[51]:
<matplotlib.streamplot.StreamplotSet at 0x7f180a6902b0>

Labelling, arrows and figure arrays

When finishing a figure, we may be in need of an annotation here and there, or we'd like to highlight certain parts of the figure. We can do that by using the text() and the annotation() functions. The function text() has three input arguments, the first two being coordinates, the thrid a string. Let us see an example!

In [52]:
plot(x,y);
text(1,0,'This is a label.')
text(-3,0,'This is another label.',fontsize=13,color='red')
Out[52]:
Text(-3,0,'This is another label.')

If we want to emphasize a certain part, then the best option is the function annotate(). This puts a pointing arrow and an explanation text onto the figure. The first input argument is a string, that is the explanation, and apart from that, we can control the behaviour of the function using keyword arguments. The keyword xy is the position of the point we want to highlight. The keyword xytext contains the explanation itself, and arrowprops is a dictionary that defined the properties of the arrow.

In [53]:
plot(x,y)
annotate('local minimum', xy=(-pi/2, -1), xytext=(-pi, 0.5),arrowprops=dict(color='red',width=3),fontsize=20)
Out[53]:
Text(-3.14159,0.5,'local minimum')
In [54]:
?annotate

Finally, let us see some examples for figure arrays. The function subplot() can create an array or grid of figures. If we put more subplot() commands into one code cell, then the plotting routines after every subplot() are going to plot into new figures. The meaning of the notation subplot(n,m,i) is the following: what comes next, put it into the ith subplot of an n$\times$m figure grid. i cannot be greater than n*m!

In [55]:
figsize(12,4) # longer horizontal figure dimensions
subplot(1,2,1)
plot(x,y)
subplot(1,2,2)
pcolor(x2,y2,z2)
Out[55]:
<matplotlib.collections.PolyCollection at 0x7f180a54df60>
In [56]:
figsize(6,8) # longer vertical figure dimensions
subplot(2,1,1)
plot(x,y)
subplot(2,1,2)
pcolor(x2,y2,z2)
Out[56]:
<matplotlib.collections.PolyCollection at 0x7f180a37aac8>

Saving a figure

We can save our figures to image files using the savefig() command.

In [57]:
figsize(6,4) # setting the usual figure dimensions
plot(x,y)
savefig('my_figure.png')