Related
Why doesn't zorder work in this case? I've tried using it but the text still ends up being covered by the bar plot towers.
import numpy as np
from matplotlib import pyplot as plt
Percentage_Differences_1 = np.array([ [7.94*(10**-10),7.94*(10**-9),7.94*(10**-8),7.94*(10**-7),7.94*(10**-6),7.94*(10**-5)],
[7.92*(10**-12),7.92*(10**-11),7.92*(10**-10),7.92*(10**-9),7.92*(10**-8),7.92*(10**-7)],
[7.72*(10**-14),7.72*(10**-13),7.72*(10**-12),7.72*(10**-11),7.72*(10**-10),7.72*(10**-9)],
[5.66*(10**-16),5.66*(10**-15),5.66*(10**-14),5.66*(10**-13),5.66*(10**-12),5.66*(10**-11)],
[1.49*(10**-17),1.49*(10**-16),1.49*(10**-15),1.49*(10**-14),1.49*(10**-13),1.49*(10**-12)],
[2.21*(10**-18),2.21*(10**-17),2.21*(10**-16),2.21*(10**-15),2.21*(10**-14),2.21*(10**-13)] ]) # Layer 1, 12
fig1 = plt.figure(dpi = 120, tight_layout = True)
fig1.set_size_inches(10, 7)
ax1 = fig1.add_subplot(111, projection='3d')
width = depth = 0.3
column_names = ['$10^{-6} m$','$10^{-5} m$','$10^{-4} m$','$10^{-3} m$','$10^{-2} m$','$10^{-1} m$']
row_names = ['$10^{-6} g$','$10^{-5} g$','$10^{-4} g$','$10^{-3} g$','$10^{-2} g$','$10^{-1} g$']
height_names = ['$10^{-2}$','$10^{-4}$','$10^{-6}$','$10^{-8}$','$10^{-10}$','$10^{-12}$','$10^{-14}$','$10^{-16}$','$10^{-18}$']
for x in range(0,6):
for y in range(0,6):
plot1 = ax1.bar3d(x, y, 0, width, depth, np.log10(Percentage_Differences_1[x][y]), color = "#0040bf", alpha=0.3, zorder = 1)
txt1 = ax1.text(x,y,1.15*np.log10(Percentage_Differences_1[x][y]),'{:.2e}'.format(Percentage_Differences_1[y][x]), verticalalignment='top', bbox=dict(facecolor='grey', alpha=0.5), zorder = 2)
ax1.view_init(-140, -30)
ax1.set_xticks(np.linspace(0, 6, num = 6))
ax1.set_yticks(np.linspace(0, 6, num = 6))
ax1.set_xticklabels(column_names)
ax1.set_yticklabels(row_names)
ax1.set_zticklabels(height_names)
ax1.set_xlabel("Mass", labelpad = 13, rotation = 45)
ax1.set_ylabel("Radius", labelpad = 10, rotation = 45)
ax1.set_zlabel("Deviation $\Delta$")
ax1.set_title("1st Initial Condition: $r(0)$ and $r'(0)$ of $\Theta(12) = 2.18 \\times 10^{7} m$", pad = 40)
plt.show()
I've tried using both set_zorder and zorder but the plot still ends up covering the majority of the text labels.
Change your zorder for a number larger than the number of bar objects, 100 for example:
I am trying to plot a figure consisting of 5 x 6 subplots, all of which I want to be adjacent, i.e. share their x and y axes.
I also want to add a colorbar to the rightmost plot in each row, which is normalized for all the subplots in that row.
I add the colorbar using:
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.15)
fig.colorbar(im, cax=cax)
However, adding the colorbar changes the size of the subplot, and it's not sticking to the other subplots any more. Here is a sample output:
How can I get it to not change dimensions when I'm adding a colorbar?
Here is the example for the code that generates the image above:
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
# border limits for plots
lowlim = 0.43
uplim = 0.52
nx = 10
kernels = ['cubic_spline', 'quintic_spline',
'wendland_C2', 'wendland_C4', 'wendland_C6']
#========================
def main():
#========================
eta_facts = [ 0, 1, 2, 3, 4, 5 ]
nrows = len(eta_facts)
ncols = len(kernels)
Ay_list = [[None for c in range(ncols)] for r in range(nrows)]
#--------------------------------
# Loop and compute As
#--------------------------------
dx = (uplim - lowlim)/nx
for row, eta in enumerate(eta_facts):
for col, kernel in enumerate(kernels):
A = np.zeros((nx, nx), dtype=np.float)
for i in range(nx):
for j in range(nx):
A[j,i] = row + np.random.random()/10 # not a typo: need A[j,i] for imshow
Ay_list[row][col] = A
#------------------------------------
# Now plot it
#------------------------------------
fig = plt.figure(figsize=(3.5*ncols, 3.5*nrows))
axrows = []
i = 1
for r in range(nrows):
axcols = []
for c in range(ncols):
if r > 0:
if c > 0:
axcols.append(fig.add_subplot(nrows, ncols, i,
aspect='equal', sharex=axrows[r-1][c], sharey=axcols[c-1]))
else:
axcols.append(fig.add_subplot(nrows, ncols, i,
aspect='equal', sharex=axrows[r-1][c]))
else:
if c > 0:
axcols.append(fig.add_subplot(nrows, ncols, i,
aspect='equal', sharey=axcols[c-1]))
else:
axcols.append(fig.add_subplot(nrows, ncols, i, aspect='equal'))
i+=1
axrows.append(axcols)
cmap = 'YlGnBu_r'
lw = 2
for row in range(nrows):
axcols = axrows[row]
minval = min([np.min(Ay_list[row][c]) for c in range(ncols)])
maxval = max([np.max(Ay_list[row][c]) for c in range(ncols)])
for col, ax in enumerate(axcols):
im = ax.imshow(Ay_list[row][col], origin='lower',
vmin=minval, vmax=maxval, cmap=cmap,
extent=(lowlim, uplim, lowlim, uplim),
# norm=matplotlib.colors.SymLogNorm(1e-3),
zorder=1)
# only plot colorbar for last column
if col==len(kernels)-1:
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.15)
fig.colorbar(im, cax=cax)
ax.set_xlim((lowlim,uplim))
ax.set_ylim((lowlim,uplim))
# cosmetics
if col > 0:
left = False
else:
left = True
if row == len(eta_facts)-1 :
bottom = True
else:
bottom = False
ax.tick_params(
axis='both', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=bottom, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
left=left, # ticks along the left edge are off
right=False, # ticks along the rigt edge are off
labelbottom=bottom, # labels along the bottom edge are off
labeltop=False, # labels along the top edge are off
labelleft=left, # labels along the left edge are off
labelright=False) # labels along the right edge are off
if row==0:
ax.set_title(kernels[col] + ' kernel', fontsize=14)
if col==0:
ax.set_ylabel(r"$\eta = $ "+str(eta_facts[row])+r"$\eta_0$")
fig.suptitle(r"Some title", fontsize=18)
plt.tight_layout(rect=(0, 0, 1, 0.97))
plt.subplots_adjust(wspace=0, hspace=0)
plt.savefig('for_stackexchange.png', dpi=150)
plt.close()
print('finished.')
return
if __name__ == '__main__':
main()
Indeed, the following the comments from user ImportanceOfBeingErnest and using axes_grid1, I could make it work.
The main difference: For each row, I define a ImageGrid object:
axrows = [[] for r in range(nrows)]
i = 0
for r in range(nrows):
axcols = [None for c in range(ncols)]
axcols = ImageGrid(fig, (nrows, 1, r+1),
nrows_ncols=(1, ncols),
axes_pad = 0.0,
share_all = True,
label_mode = 'L',
cbar_mode = 'edge',
cbar_location = 'right',
cbar_size = "7%",
cbar_pad = "2%")
axrows[r] = axcols
And then, at the right place in the code, I add the colorbar with
axcols.cbar_axes[0].colorbar(im)
Here is the full code:
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
from mpl_toolkits.axes_grid1 import ImageGrid
# border limits for plots
lowlim = 0.43
uplim = 0.52
nx = 10
kernels = ['cubic_spline', 'quintic_spline',
'wendland_C2', 'wendland_C4', 'wendland_C6']
#========================
def main():
#========================
eta_facts = [ 0, 1, 2, 3, 4, 5 ]
nrows = len(eta_facts)
ncols = len(kernels)
Ay_list = [[None for c in range(ncols)] for r in range(nrows)]
#--------------------------------
# Loop and compute As
#--------------------------------
dx = (uplim - lowlim)/nx
for row, eta in enumerate(eta_facts):
for col, kernel in enumerate(kernels):
A = np.zeros((nx, nx), dtype=np.float)
for i in range(nx):
for j in range(nx):
A[j,i] = row + np.random.random()/10 # not a typo: need A[j,i] for imshow
Ay_list[row][col] = A
#------------------------------------
# Now plot it
#------------------------------------
fig = plt.figure(figsize=(3.5*ncols+1, 3.5*nrows))
axrows = [[] for r in range(nrows)]
i = 0
for r in range(nrows):
axcols = [None for c in range(ncols)]
axcols = ImageGrid(fig, (nrows, 1, r+1),
nrows_ncols=(1, ncols),
axes_pad = 0.0,
share_all = True,
label_mode = 'L',
cbar_mode = 'edge',
cbar_location = 'right',
cbar_size = "7%",
cbar_pad = "2%")
axrows[r] = axcols
cmap = 'YlGnBu_r'
lw = 2
for row in range(nrows):
axcols = axrows[row]
minval = min([np.min(Ay_list[row][c]) for c in range(ncols)])
maxval = max([np.max(Ay_list[row][c]) for c in range(ncols)])
for col, ax in enumerate(axcols):
im = ax.imshow(Ay_list[row][col], origin='lower',
vmin=minval, vmax=maxval, cmap=cmap,
extent=(lowlim, uplim, lowlim, uplim),
# norm=matplotlib.colors.SymLogNorm(1e-3),
zorder=1)
ax.set_xlim((lowlim,uplim))
ax.set_ylim((lowlim,uplim))
# cosmetics
if col > 0:
left = False
else:
left = True
if row == len(eta_facts)-1 :
bottom = True
else:
bottom = False
ax.tick_params(
axis='both', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=bottom, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
left=left, # ticks along the left edge are off
right=False, # ticks along the rigt edge are off
labelbottom=bottom, # labels along the bottom edge are off
labeltop=False, # labels along the top edge are off
labelleft=left, # labels along the left edge are off
labelright=False) # labels along the right edge are off
if row==0:
ax.set_title(kernels[col] + ' kernel', fontsize=14)
if col==0:
ax.set_ylabel(r"$\eta = $ "+str(eta_facts[row])+r"$\eta_0$")
axcols.cbar_axes[0].colorbar(im)
fig.suptitle(r"Some title", fontsize=18)
plt.tight_layout(rect=(0, 0, 1, 0.97))
plt.subplots_adjust(wspace=0.0, hspace=0.0)
plt.savefig('for_stackexchange.png', dpi=150)
plt.close()
print('finished.')
return
if __name__ == '__main__':
main()
Which produces this image:
I have a series of boxplots that I want to be centered around xticks (2 per xtick specifically). Consider the following:
# fake up some more data
spread= rand(50) * 100
center = ones(25) * 40
flier_high = rand(10) * 100 + 100
flier_low = rand(10) * -100
d2 = concatenate( (spread, center, flier_high, flier_low), 0 )
data.shape = (-1, 1)
d2.shape = (-1, 1)
#data = concatenate( (data, d2), 1 )
# Making a 2-D array only works if all the columns are the
# same length. If they are not, then use a list instead.
# This is actually more efficient because boxplot converts
# a 2-D array into a list of vectors internally anyway.
data = [data, d2, d2[::2,0]]
# multiple box plots on one figure
figure()
boxplot(data)
Which produces
However I would like to have 6 boxplots, with 2 centered around 1, 2 around 2, etc... If I add in three more it simply adds them to 4,5,6... Any help would be appreciated
EDIT To be clear by what I mean by "centered". I would want one boxplot just to the left of the xtick labled "1", and another just to the right. They would likely overlap in the y range so I don't want them to be drawn on top of each other.
To control the x-position of the boxplots, use the positions kwarg.
For example:
import numpy as np
import matplotlib.pyplot as plt
dists = [np.random.normal(i, 1, 100) for i in range(0, 10, 2)]
fig, ax = plt.subplots()
ax.boxplot(dists, positions=[0, 1, 2, 0, 1])
plt.show()
If you'd prefer to have the groups side-by-side, you'll need to calculate the positions yourself. One approach might be something like this:
def grouped_boxplots(data_groups, ax=None, max_width=0.8, pad=0.05, **kwargs):
if ax is None:
ax = plt.gca()
max_group_size = max(len(item) for item in data_groups)
total_padding = pad * (max_group_size - 1)
width = (max_width - total_padding) / max_group_size
kwargs['widths'] = width
def positions(group, i):
span = width * len(group) + pad * (len(group) - 1)
ends = (span - width) / 2
x = np.linspace(-ends, ends, len(group))
return x + i
artists = []
for i, group in enumerate(data_groups, start=1):
artist = ax.boxplot(group, positions=positions(group, i), **kwargs)
artists.append(artist)
ax.margins(0.05)
ax.set(xticks=np.arange(len(data_groups)) + 1)
ax.autoscale()
return artists
And as a quick example of using it:
data = [[np.random.normal(i, 1, 30) for i in range(2)],
[np.random.normal(i, 1.5, 30) for i in range(3)],
[np.random.normal(i, 2, 30) for i in range(4)]]
grouped_boxplots(data)
plt.show()
...And just for the sake of showing an excessively fancy example:
import numpy as np
import matplotlib.pyplot as plt
def main():
data = [[np.random.normal(i, 1, 30) for i in range(2)],
[np.random.normal(i, 1.5, 30) for i in range(3)],
[np.random.normal(i, 2, 30) for i in range(4)]]
fig, ax = plt.subplots()
groups = grouped_boxplots(data, ax, max_width=0.9,
patch_artist=True, notch=True)
colors = ['lavender', 'lightblue', 'bisque', 'lightgreen']
for item in groups:
for color, patch in zip(colors, item['boxes']):
patch.set(facecolor=color)
proxy_artists = groups[-1]['boxes']
ax.legend(proxy_artists, ['Group A', 'Group B', 'Group C', 'Group D'],
loc='best')
ax.set(xlabel='Year', ylabel='Performance', axisbelow=True,
xticklabels=['2012', '2013', '2014'])
ax.grid(axis='y', ls='-', color='white', lw=2)
ax.patch.set(facecolor='0.95')
plt.show()
def grouped_boxplots(data_groups, ax=None, max_width=0.8, pad=0.05, **kwargs):
if ax is None:
ax = plt.gca()
max_group_size = max(len(item) for item in data_groups)
total_padding = pad * (max_group_size - 1)
width = (max_width - total_padding) / max_group_size
kwargs['widths'] = width
def positions(group, i):
span = width * len(group) + pad * (len(group) - 1)
ends = (span - width) / 2
x = np.linspace(-ends, ends, len(group))
return x + i
artists = []
for i, group in enumerate(data_groups, start=1):
artist = ax.boxplot(group, positions=positions(group, i), **kwargs)
artists.append(artist)
ax.margins(0.05)
ax.set(xticks=np.arange(len(data_groups)) + 1)
ax.autoscale()
return artists
main()
It seems that PCOLOR is chopping off the last row and column of my data set. Printing the shape of zi below reveals that it is (22,22), as I expect, but an area of 21 squares by 21 squares is shown... Any idea why the last row and column are not being plotted?
def pcolor_probs(x,y,z, x_str, y_str, t_str):
xi = np.arange(min(x),max(x)+1, 1)
yi = np.arange(min(y),max(y)+1, 1)
zi = griddata(x,y,z,xi,yi)
print np.shape(xi),np.shape(yi),np.shape(zi)
# fix NANs
zi = np.asarray(zi)
for i in range(len(zi)):
for j in range(len(zi[i])):
print i,j
if isnan(float(zi[i][j])):
zi[i][j] = 0
# plot
f = figure()
ax = f.add_subplot(111)
pc_plot = ax.pcolor(zi, cmap = cm.coolwarm, shading = 'faceted', alpha = 0.75)
# pc_plot = ax.contourf(zi, 20, cmap = cm.coolwarm, alpha = 0.75)
ax.set_xticks(np.arange(zi.shape[0])+0.5, minor=False)
ax.set_yticks(np.arange(zi.shape[1])+0.5, minor=False)
ax.set_xticklabels(np.arange(len(xi)))
ax.set_yticklabels(np.arange(len(yi)))
ax.set_xlim(min(x), max(x))
ax.set_ylim(min(y), max(y))
ax.set_xlabel(x_str)
ax.set_ylabel(y_str)
ax.set_title(t_str)
f.colorbar(pc_plot)
f.set_tight_layout(True)
font = {'family' : 'serif','weight' : 'regular','size' : 12}
matplotlib.rc('font', **font)
show()
Let's make it even more simple,
X = np.random.rand(10,10)
pcolor(X)
show()
Produces,
A bit late, but just providing an X and Y arguments whose shape is larger by just 1 (in both directions) will display the entire array.
Something like the example bellow:
import numpy as np
import matplotlib.pyplot as plt
#define the space limits:
horizontal_min = -2.
horizontal_max = 2.
horizontal_step = 0.1
vertical_min = -1.
vertical_max = 1.
vertical_step = 0.2
# create the arrays
nx = (horizontal_max - horizontal_min) / horizontal_step
ny = ( vertical_max - vertical_min ) / vertical_step
Z = np.zeros((nx,ny))
Y,X = np.meshgrid(np.arange(vertical_min,
vertical_max+vertical_step, # THIS LINE...
vertical_step),
np.arange(horizontal_min,
horizontal_max+horizontal_step, # ...& THIS LINE
horizontal_step)
)
Y2,X2 = np.meshgrid(np.arange(vertical_min,
vertical_max, # THIS LINE...
vertical_step),
np.arange(horizontal_min,
horizontal_max, # ...& THIS LINE
horizontal_step)
)
# populate the data array (Z)
i = 0
if nx > ny:
while i < ny:
Z[i,i] = i+1
Z[nx-i-1,i] = -i-1
i += 1
else:
while i < ny:
Z[i,i] = i+1
Z[i,ny-i-1] = -i-1
i += 1
# make the graph
fig,axes = plt.subplots(2,1)
pc_plot1 = axes[0].pcolor(X, Y, Z)
axes[0].set_title('X.shape == Y.shape != Z.shape')
pc_plot2 = axes[1].pcolor(X2, Y2, Z)
axes[1].set_title('X.shape == Y.shape == Z.shape')
for ax in axes:
ax.axis('equal')
ax.set_xlim(horizontal_min, horizontal_max)
ax.set_ylim(vertical_min, vertical_max)
fig.tight_layout()
fig.show()
Notice the lines marked with THIS LINE. What they mean is that:
>>> print X.shape,Y.shape,Z.shape
(41, 11) (41, 11) (40, 10)
(For the given example)
Just a small note, using Y,X = np.meshgrid... replaces having to transpose Z (see official documentation).
The reason is that pcolor counts points on vertices. There are, in fact, 22 and 10 vertices. Use imshow(...,extent[]) instead.
I am looking for a python plot on the lines of http://www.r-bloggers.com/visually-weighted-watercolor-plots-new-variants-please-vote/
This gives the equivalent of the standard deviation bands:
# generate random variables
x,y = generate_random()
# bin the values and determine the envelopes
df = bin_by(x, y, nbins=25, bins = None)
###
# Plot 1
###
# determine the colors
cols = ['#EE7550', '#F19463', '#F6B176']
with plt.style.context('fivethirtyeight'):
# plot the 3rd stdv
plt.fill_between(df.x, df['5th'], df['95th'], alpha=0.7,color = cols[2])
plt.fill_between(df.x, df['10th'], df['90th'], alpha=0.7,color = cols[1])
plt.fill_between(df.x, df['25th'], df['75th'], alpha=0.7,color = cols[0])
# plt the line
plt.plot(df.x, df['median'], color = '1', alpha = 0.7, linewidth = 1)
# plot the points
plt.scatter(x, y, facecolors='white', edgecolors='0', s = 5, lw = 0.7)
plt.savefig('fig1.png', facecolor='white', edgecolor='none')
plt.show()
def bin_by(x, y, nbins=30, bins = None):
"""
Divide the x axis into sections and return groups of y based on its x value
"""
if bins is None:
bins = np.linspace(x.min(), x.max(), nbins)
bin_space = (bins[-1] - bins[0])/(len(bins)-1)/2
indicies = np.digitize(x, bins + bin_space)
Bit of a discussion and link to my Github from my blog
cut-paste from my larger piece of code. It does not give what I want. I am posting per Evert's suggestion
fig = plt.figure(figsize=(8, 8))
plt.plot(xlist, ylist, 'b,')
plt.plot([0.0,0.8],[0.0,0.8],'y-')
data2d=zip(xlist,ylist)
bins = np.linspace(0.0, 0.2, 21)
medianlist=binpercentile(data2d,bins)
c10list=binpercentile(data2d,bins,0.1)
c90list=binpercentile(data2d,bins,0.9)
centerbins=[(x+y)/2.0 for x,y in zip(bins[:-1],bins[1:])]
centerbins.insert(0,0)
medianlist.insert(0,0)
c10list.insert(0,0)
c90list.insert(0,0)
plt.plot(centerbins,c10list,'r--')
plt.plot(centerbins,c90list,'r--')
plt.plot(centerbins,medianlist,'r-')
imagefilename='%s.%s'%('.'.join(infile.split('.')[0:-1]),'diffmed.pdf')
plt.savefig(imagefilename)