views:

334

answers:

2

I am experimenting with matplotlib at the moment. Some time ago I used Excel VBA code to produce images such as the one attached.

You will notice it is not presented in a scientific/research style but rather as if produced by a school-student on graph paper - with three different grid-line styles.

Is there a fairly straightforward way to achieve this sort of thing with matplotlib?

alt text

+7  A: 

Yes, you can use spines for this.

import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import numpy as np

fig = plt.figure(1)
ax = fig.add_subplot(111)

# set up axis
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')

# draw curve
x = np.arange(-2.5,2.5,0.01)
line, = ax.plot(x, x**2)

#set bounds
ax.set_ybound(-1,7)

# create grid
#ax.xaxis.set_major_locator(MultipleLocator(1))
#ax.xaxis.set_minor_locator(MultipleLocator(0.2))
#ax.yaxis.set_major_locator(MultipleLocator(1))
#ax.yaxis.set_minor_locator(MultipleLocator(0.2))
#ax.xaxis.grid(True,'minor')
#ax.yaxis.grid(True,'minor')
#ax.xaxis.grid(True,'major',linewidth=2)
#ax.yaxis.grid(True,'major',linewidth=2)

#adjust grid on the 2s
#for idx,loc in enumerate(ax.xaxis.get_majorticklocs()):
    #if loc !=0 and loc % 2 == 0: ax.get_xgridlines()[idx].set_c('r')
#for idx,loc in enumerate(ax.yaxis.get_majorticklocs()):
    #if loc !=0 and loc % 2 == 0: ax.get_ygridlines()[idx].set_c('r')

## THIS IS THE EDIT
ax.xaxis.set_minor_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.2))
ax.xaxis.grid(True,'minor',linewidth=2)
ax.yaxis.grid(True,'minor',linewidth=2)

minor_grid_lines = [tick.gridline for tick in ax.xaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.xaxis.get_minorticklocs()):
    if loc % 2.0 == 0: minor_grid_lines[idx].set_c('r' )
    elif loc % 1.0 == 0: minor_grid_lines[idx].set_c('g' )
    else: minor_grid_lines[idx].set_c( 'b' )

plt.show()

alt text

Mark
Superb!!! That looks to be just what I was after. Many, many thanks!
Geddes
My final question would be: is there any way to get the three different grid line styles? I want one style for *0.2, another for *1 and yet another for *2 (as in graph-paper). This seems difficult as matplotlib seems to impose only major/minor ticks. Thanks again!
Geddes
@Geddes, see edits above. I think the easiest way would be to just adjust the gridlines based on their position (ie on the multiples of 2).
Mark
Thanks again Mark. I'll have to get my head around this now - some pretty advanced stuff going on! All the best.
Geddes
+1 for typing out all that
George
A: 

Just another thought - I have also tried to do it all with the minor gridlines (apart from anything else it will help my understanding), but it's not enumerating properly, no doubt due to the get_minorticklocs and ax.get_xgridlines. Sorry, and thanks in advance...

Geddes

import matplotlib.pyplot as plt 
from matplotlib.ticker import MultipleLocator, FormatStrFormatter 
import numpy as np 

fig = plt.figure(1) 
ax = fig.add_subplot(111) 

# set up axis 
ax.spines['left'].set_position('zero') 
ax.spines['right'].set_color('none') 
ax.spines['bottom'].set_position('zero') 
ax.spines['top'].set_color('none') 
ax.xaxis.set_ticks_position('bottom') 
ax.yaxis.set_ticks_position('left') 

# draw curve 
x = np.arange(-2.5,2.5,0.01) 
line, = ax.plot(x, x**2) 

#set bounds 
ax.set_ybound(-1,7) 

# create grid 
ax.xaxis.set_minor_locator(MultipleLocator(0.2)) 
ax.yaxis.set_minor_locator(MultipleLocator(0.2)) 
ax.xaxis.grid(True,'minor',linewidth=2) 
ax.yaxis.grid(True,'minor',linewidth=2) 

#adjust grid on the 2s 
for idx,loc in enumerate(ax.xaxis.get_minorticklocs()):
    if loc % 2 == 0: ax.get_xgridlines()[idx].set_color('r')
    if loc % 1 == 0: ax.get_xgridlines()[idx].set_color('g')
    if loc % 0.2 == 0: ax.get_xgridlines()[idx].set_color('b')

for idx,loc in enumerate(ax.yaxis.get_majorticklocs()): 
    if loc % 2 == 0: ax.get_ygridlines()[idx].set_c('b') 

plt.savefig('spines3.png',dpi=300)
Geddes
@Geddes, the ax.get_xgridlines() only returns the major gridlines. See edits to my answer above.
Mark
Fantastic - thank you so much for all your help today Mark - I know I'm a demanding customer!All my best wishes,Geddes
Geddes