LlamaD
LlamaD

Reputation: 442

Missing some minor gridlines in matplotlib after deleting part of data range

Executing the following code gives a plot where the last 2 minor grid lines are missing in both x and y. If I remove the section of the code that trims the data or extend the amount of data which is accepted (xylimit) then this can be obviated. Can anyone see what I'm doing wrong?

from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from pylab import *

l=201
x=linspace(-l,l,201)
y=linspace(-l,l,201)
z=np.random.rand(l,l)

xylimit=100

i=0
while i<len(x[:]):
     if abs(x[i])>xylimit:
         x=np.delete(x,i,0)
         y=np.delete(y,i,0)
     else:
         i+=1
i=0
while i<len(y[:]):
     if abs(y[i])>xylimit:
         x=np.delete(x,i,0)
         y=np.delete(y,i,0)
     else:
         i+=1

z=np.random.rand(len(x),len(x))

xgridlines = getp(gca(), 'xgridlines')
ygridlines = getp(gca(), 'ygridlines')
plt.minorticks_on()
plt.grid(b=True, which='both',linestyle='-')

l=plt.contourf(x,y,z,np.linspace(0,1,255))

plt.show()

contourplot

Upvotes: 0

Views: 1094

Answers (1)

DrV
DrV

Reputation: 23490

It seems to be a bug in matplotlib's minor tick locator (matplotlib.ticker.AutoMinorLocator). The tick at 90.0 just does not exist. If you do this:

xlim(-98.5,100.0)

The tick miraculously appears. But if you use any number which will prevent the last major line to be drawn (i.e. anything below 100.0), the tick disappears.

The lack of the tick can be verified by:

>>> gca().get_xaxis().get_minorticklocs()

array([-90., -80., -70., -60., -40., -30., -20., -10.,  10.,  20.,  30.,
    40.,  60.,  70.,  80.])

There is an ugly manual hack to get around the problem

gca().get_xaxis().set_minor_locator(matplotlib.ticker.FixedLocator(
    array([-90., -80., -70., -60., -40., -30., -20., -10.,  10.,  20.,  30.,
    40.,  60.,  70.,  80., 90.])))

This unfortunately requires setting the positions by hand.


A minimal example of the bug (namespaces omitted, I use ipython+pylab):

figure()
plot([0,100], [0,100])
axis([0,99.5,0,99.5])
minorticks_on()
grid(which='both')

And the bug... It seems to be on line 1732 of ticker.py now available at github (or line 1712 in version 1.3.1). As the version may change, I'll paste it here:

if len(majorlocs) > 0:
    t0 = majorlocs[0]
    tmin = np.ceil((vmin - t0) / minorstep) * minorstep
    tmax = np.floor((vmax - t0) / minorstep) * minorstep
    locs = np.arange(tmin, tmax, minorstep) + t0
    cond = np.abs((locs - t0) % majorstep) > minorstep / 10.0
    locs = locs.compress(cond)
else:
    locs = []

The bug itself is on the line locs = .... Actually there are two bugs:

  • the use of arange in a way shown here, because in my simple example tmin = 0.0, tmax = 95.0 and minorstep = 5.0; in general case it is sheer luck if arangewill give the 95.0 or not. (Actually with integers it works always the wrong way but with anything else is very prone to round-off errors.)
  • even if the maths went right above (they do in the example), the last sample will be missed

In my opinion this should be rewritten to use integers. As a temporary cure, one could replace the line with:

locs = np.arange(tmin, tmax + minorstep / 2., minorstep) + t0

This got the lines back at least in my matplotlib.


So, the short answer: Find the ticker.py somewhere in python package folders, make the small edit, and you are done.

Upvotes: 2

Related Questions