Draw minor grid lines below major gridlines - python

I am trying to draw a grid using matplotlib. The zorder of the grid should be behind all other lines in the plot. My problem so far is that the
minor grid lines are always drawn in front of the major grid lines i.e.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
f = plt.figure(figsize=(4,4))
ax = f.add_subplot(111)
ax.xaxis.set_minor_locator(MultipleLocator(1))
ax.xaxis.set_major_locator(MultipleLocator(10))
ax.yaxis.set_minor_locator(MultipleLocator(1))
ax.yaxis.set_major_locator(MultipleLocator(10))
majc ="#3182bd"
minc ="#deebf7"
ax.xaxis.grid(True,'minor',color=minc, ls='-', lw=0.2)
ax.yaxis.grid(True,'minor',color=minc, ls='-', lw=0.2)
ax.xaxis.grid(True,'major',color=majc, ls='-')
ax.yaxis.grid(True,'major',color=majc,ls ='-')
ax.set_axisbelow(True)
x = np.linspace(0, 30, 100)
ax.plot(x, x, 'r-', lw=0.7)
[line.set_zorder(3) for line in ax.lines]
plt.savefig('test.pdf')
Any suggestions? Thank you.
EDIT: close-up example

Even more specifically, it looks like it draws vertical majors, vertical minors, horizontal majors, horizontal minors, and plotted lines, in that order. Probably pretty deep in the matplotlib basics.
For the colors you're using, you could work around by distinguishing major and minor by alpha, not RGB. Changing two lines of your example:
ax.xaxis.grid(True,'minor',color=majc, alpha=0.2, ls='-', lw=0.2)
ax.yaxis.grid(True,'minor',color=majc, alpha=0.2, ls='-', lw=0.2)
result:

Related

ax.grid overwrites ticks labels when spine is in centre

When using ax.grid() and moving the spines to the middle of the plot, the grid lines go over the axes labels. Any way to stop this and move the axes labels to "front"?
EDIT: It is the ticks labels (the numbers) I'm interested in fixing, not the axis label, which can be easily moved.
EDIT: made the MWE and image match exactly
EDIT: matplotlib version 2.0.0
#!/usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.gca()
ax.minorticks_on()
ax.grid(b=True, which='major', color='k', linestyle='-',alpha=1,linewidth=1)
ax.grid(b=True, which='minor', color='k', linestyle='-',alpha=1,linewidth=1)
x = np.linspace(-5,5,100)
y = np.linspace(-5,5,100)
plt.plot(x,y)
plt.yticks([-5,-4,-3,-2,-1,0,1,2,3,4,5])
ax.spines['left'].set_position(('data', 0))
plt.show()

force matplotlib to fix the plot area

I have multiple plots that have the same x-axis. I would like to stack them in a report and have everything line up. However, matplotlib seems to resize them slightly based on the y tick label length.
Is it possible to force the plot area and location to remain the same across plots, relative to the pdf canvas to which I save it?
import numpy as np
import matplotlib.pyplot as plt
xs=np.arange(0.,2.,0.00001)
ys1=np.sin(xs*10.) #makes the long yticklabels
ys2=10.*np.sin(xs*10.)+10. #makes the short yticklabels
fig=plt.figure() #this plot ends up shifted right on the canvas
plt.plot(xs,ys1,linewidth=2.0)
plt.xlabel('x')
plt.ylabel('y')
fig=plt.figure() #this plot ends up further left on the canvas
plt.plot(xs,ys2,linewidth=2.0)
plt.xlabel('x')
plt.ylabel('y')
Your problem is a little unclear, however plotting them as subplots in the same figure should gaurantee that the axes and figure size of the two subplots will be alligned with each other
import numpy as np
import matplotlib.pyplot as plt
xs=np.arange(0.,2.,0.00001)
ys1=np.sin(xs*10.) #makes the long yticklabels
ys2=10.*np.sin(xs*10.)+10. #makes the short yticklabels
fig, (ax1, ax2) = plt.subplots(2, 1)
ax1.plot(xs,ys1,linewidth=2.0)
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax2.plot(xs,ys2,linewidth=2.0)
ax2.set_xlabel('x')
ax2.set_ylabel('y')
plt.subplots_adjust(hspace=0.3) # adjust spacing between plots
plt.show()
This produces the following figure:
I had the same problem. The following works for me.
Force the same figure width for all your plots around all your python scripts, for example:
fig1 = plt.figure(figsize=(12,6))
...
fig2 = plt.figure(figsize=(12,4))
And do not use (very important!):
fig.tight_layout()
Save the figure
plt.savefig('figure.png')
Plot areas should now be the same.
using subplots with the same x-axis should do the trick.
use sharex=True when you create the subplots. The benefit of sharex is that zooming or panning on 1 subplot will also auto-update on all subplots with shared axes.
import numpy as np
import matplotlib.pyplot as plt
xs = np.arange(0., 2., 0.00001)
ys1 = np.sin(xs * 10.) # makes the long yticklabels
ys2 = 10. * np.sin(xs * 10.) + 10. # makes the short yticklabels
fig, (ax1, ax2) = plt.subplots(2, sharex=True)
ax1.plot(xs, ys1, linewidth=2.0)
ax1.xlabel('x')
ax1.ylabel('y')
ax2.plot(xs, ys2, linewidth=2.0)
ax2.xlabel('x')
ax2.ylabel('y')
plt.show()

Matplotlib scatter plot - Remove white padding

I'm working with matplotlib to plot a variable in latitude longitude coordinates. The problem is that this image cannot include axes or borders. I have been able to remove axis, but the white padding around my image has to be completely removed (see example images from code below here: http://imgur.com/a/W0vy9) .
I have tried several methods from Google searches, including these StackOverflow methodologies:
Remove padding from matplotlib plotting
How to remove padding/border in a matplotlib subplot (SOLVED)
Matplotlib plots: removing axis, legends and white spaces
but nothing has worked in removing the white space. If you have any advice (even if it is to ditch matplotlib and to try another plotting library instead) I would appreciate it!
Here is a basic form of the code I'm using that shows this behavior:
import numpy as np
import matplotlib
from mpl_toolkits.basemap import Basemap
from scipy import stats
lat = np.random.randint(-60.5, high=60.5, size=257087)
lon = np.random.randint(-179.95, high=180, size=257087)
maxnsz = np.random.randint(12, 60, size=257087)
percRange = np.arange(100,40,-1)
percStr=percRange.astype(str)
val_percentile=np.percentile(maxnsz, percRange, interpolation='nearest')
#Rank all values
all_percentiles=stats.rankdata(maxnsz)/len(maxnsz)
#Figure setup
fig = matplotlib.pyplot.figure(frameon=False, dpi=600)
#Basemap code can go here
x=lon
y=lat
cmap = matplotlib.cm.get_cmap('cool')
h=np.where(all_percentiles >= 0.999)
hl=np.where((all_percentiles < 0.999) & (all_percentiles > 0.90))
mh=np.where((all_percentiles > 0.75) & (all_percentiles < 0.90))
ml=np.where((all_percentiles >= 0.4) & (all_percentiles < 0.75))
l=np.where(all_percentiles < 0.4)
all_percentiles[h]=0
all_percentiles[hl]=0.25
all_percentiles[mh]=0.5
all_percentiles[ml]=0.75
all_percentiles[l]=1
rgba_low=cmap(1)
rgba_ml=cmap(0.75)
rgba_mh=cmap(0.51)
rgba_hl=cmap(0.25)
rgba_high=cmap(0)
matplotlib.pyplot.axis('off')
matplotlib.pyplot.scatter(x[ml],y[ml], c=rgba_ml, s=3, marker=',',edgecolor='none', alpha=0.4)
matplotlib.pyplot.scatter(x[mh],y[mh], c=rgba_mh, s=3, marker='o', edgecolor='none', alpha=0.5)
matplotlib.pyplot.scatter(x[hl],y[hl], c=rgba_hl, s=4, marker='*',edgecolor='none', alpha=0.6)
matplotlib.pyplot.scatter(x[h],y[h], c=rgba_high, s=5, marker='^', edgecolor='none',alpha=0.75)
fig.savefig('/home/usr/code/python/testfig.jpg', bbox_inches=0, nbins=0, transparent="True", pad_inches=0.0)
fig.canvas.draw()
The problem is that all the solutions given at Matplotlib plots: removing axis, legends and white spaces are actually meant to work with imshow.
So, the following clearly works
import matplotlib.pyplot as plt
fig = plt.figure()
ax=fig.add_axes([0,0,1,1])
ax.set_axis_off()
im = ax.imshow([[2,3,4,1], [2,4,4,2]], origin="lower", extent=[1,4,2,8])
ax.plot([1,2,3,4], [2,3,4,8], lw=5)
ax.set_aspect('auto')
plt.show()
and produces
But here, you are using scatter. Adding a scatter plot
import matplotlib.pyplot as plt
fig = plt.figure()
ax=fig.add_axes([0,0,1,1])
ax.set_axis_off()
im = ax.imshow([[2,3,4,1], [2,4,4,2]], origin="lower", extent=[1,4,2,8])
ax.plot([1,2,3,4], [2,3,4,8], lw=5)
ax.scatter([2,3,4,1], [2,3,4,8], c="r", s=2500)
ax.set_aspect('auto')
plt.show()
produces
Scatter has the particularity that matplotlib tries to make all points visible by default, which means that the axes limits are set such that all scatter points are visible as a whole.
To overcome this, we need to specifically set the axes limits:
import matplotlib.pyplot as plt
fig = plt.figure()
ax=fig.add_axes([0,0,1,1])
ax.set_axis_off()
im = ax.imshow([[2,3,4,1], [2,4,4,2]], origin="lower", extent=[1,4,2,8])
ax.plot([1,2,3,4], [2,3,4,8], lw=5)
ax.scatter([2,3,4,1], [2,3,4,8], c="r", s=2500)
ax.set_xlim([1,4])
ax.set_ylim([2,8])
ax.set_aspect('auto')
plt.show()
such that we will get the desired behaviour.

In a matplotlib barplot, how can I make sure very small bars are rendered with an equal width?

I'm creating a bar plot in matplotlib with many, many very narrow bars. Here's some example code:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(100)
y = np.random.poisson(1, size=100)
fig, ax = plt.subplots(figsize=(8, 1))
ax.bar(x, y, width=1, facecolor='red', edgecolor='white', linewidth=1)
ax.grid(color='white', linewidth=1, linestyle='-')
# some plot aesthetics
for spine in ['right', 'top', 'left']:
ax.spines[spine].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('none')
ax.yaxis.set_major_locator(plt.MultipleLocator(1))
ax.yaxis.set_major_formatter(plt.NullFormatter())
Notice that due to the finite pixel resolution, the bars vary noticeably in rendered width.
What is the best way to create this plot in matplotlib while ensuring that the rendered result has equal-width bars?

tick label positions for matplotlib 3D plot

I am trying to work out how to set/correct the position of tick labels for a 3D matplotlib plot. Tick labels do not align with the ticks. The issue seems to be especially prominent when many tick labels are required.
I have modified an example (http://matplotlib.org/examples/mplot3d/polys3d_demo.html) from the matplotlib documentation to illustrate my question.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(10,10))
ax = fig.gca(projection='3d')
cc = lambda arg: colorConverter.to_rgba(arg, alpha=0.6)
xs = np.arange(0, 10, 0.4)
verts = []
zs = np.arange(50)
for z in zs:
ys = np.ones(len(xs))*z
ys[0], ys[-1] = 0, 0
verts.append(list(zip(xs, ys)))
poly = PolyCollection(verts,facecolor='c')
poly.set_alpha(0.7)
ax.add_collection3d(poly, zs=zs, zdir='y')
ax.set_xlabel('X')
ax.set_xlim3d(0, 10)
ax.set_ylabel('Y')
ax.set_ylim3d(-1, len(zs))
ax.set_yticks(np.arange(len(zs)))
labels = {}
for l_c in zs:
labels[l_c] = 'This Looks Bad'
ax.set_yticklabels(labels,rotation=-15)
ax.set_zlabel('Z')
ax.set_zlim3d(0, ys.max())
plt.show()
So the question is: how can I get the tick labels to align with the tick positions?
By using these alignments, I get much better placements:
ax.set_yticklabels(labels,rotation=-15,
verticalalignment='baseline',
horizontalalignment='left')
I've modified the example with less tick markers so you can see the placement:
They do align, but with the horizontal position centered at the tick. Because of the 3D view this makes them appear a bit below where you would expect them to be. The effect is not related to the amount of ticks but to the width.
Specifically setting the alignment will help. Try adding:
ax.set_yticklabels(labels,rotation=-15, va='center', ha='left')
Play around a bit with the different alignments to see which you prefer, i think you're after ha='left'.
Reducing the padding, distance from the tick, might also help.
You can also set the pad argument as negative in the tick_params options for each axis. Like this:
ax.tick_params(axis='x', which='major', pad=-3)
This might help to adjust the distance between tick labels and axis.

Categories

Resources