I am trying to clip data to within the axes bounds when using subplots to create multiple plots.
By setting clip_on = True the data is clipped to the figure but still is shown in the neighboring plot above, but I don't want this to happen. The code below reproducers the issue where the blue line appears in the first plot overtop of the red line.
import matplotlib as mpl
import numpy as np
fig, ax = mpl.pyplot.subplots(2,1)
x = np.linspace(-10, 10, 1000)
y1 = x**2 + 2*x + 2
y2 = x**2 + 2*x + 3
ax[0].set_ylim(0, 5)
ax[0].plot(x, y1, color = 'red', clip_on = True)
ax[1].set_ylim(0, 5)
ax[1].plot(x, y2, clip_on = True)
Related
I'd like to make a stacked area chart but it would increase stepwise, like the stairs plot.
It is a cumulative chart, so a stepwise increase would make more sense.
How can it be done?
plt.stackplot accepts extra kwargs which are sent to plt.fill_between. One of those is step='post', creating a horizontal line starting with the given value. (In contrast, step='pre' has the horizontal lines at the height of the ending positions.)
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(1, 6)
y1 = np.random.rand(5) + 1
y2 = np.random.rand(5) + 2
y3 = np.random.rand(5) + 3
plt.stackplot(x, y1, y2, y3, step='post', labels=['A', 'B', 'C'])
plt.xticks(x)
plt.legend()
plt.show()
I'd like to invert the bars in this diagram when they are below 1, not when they are negative. Additionally I'd like to have even spacing between the ticks/steps on the y-axis
Here is my current code
import matplotlib.pyplot as plt
import numpy as np
labels = ['A','B','C']
Vals1 = [28.3232, 12.232, 9.6132]
Vals2 = [0.00456, 17.868, 13.453]
Vals3 = [0.0032, 1.234, 0.08214]
x = np.arange(len(labels))
width = 0.2
fig, ax = plt.subplots()
rects1 = ax.bar(x - width, Vals1, width, label='V1')
rects2 = ax.bar(x, Vals2, width, label='V2')
rects3 = ax.bar(x + width, Vals3, width, label='V3')
ax.set_xticks(x)
ax.set_xticklabels(labels)
plt.xticks(rotation=90)
ax.legend()
yScale = [0.0019531,0.0039063,0.0078125,0.015625,0.03125,0.0625,0.125,0.25,0.5,1,2,4,8,16,32]
ax.set_yticks(yScale)
plt.show()
I believe I've stumbled upon the answer, here it is for anyone else looking for the solution. Add the argument bottom='1' to ax.bar instantiation, and then flip the values in the array.
for i in range(len(Vals1)):
Vals1[i] = (1 - Vals1[i]) * -1
As you mentioned, the key is the bottom param of Axes.bar:
bottom (default: 0): The y coordinate(s) of the bars bases.
But beyond that, you can simplify your plotting code using pandas:
Put your data into a DataFrame:
import pandas as pd
df = pd.DataFrame({'V1': Vals1, 'V2': Vals2, 'V3': Vals3}, index=labels)
# V1 V2 V3
# A 28.3232 0.00456 0.00320
# B 12.2320 17.86800 1.23400
# C 9.6132 13.45300 0.08214
Then use DataFrame.sub to subtract the offset and DataFrame.plot.bar with the bottom param:
bottom = 1
ax = df.sub(bottom).plot.bar(bottom=bottom)
I have the code below to plot circles add them to an ax.
I color the circles with respect to a colorbar.
However, to add the colorbar to my plot, I'm using sc=plot.scatter(...) and putting the colorbar using this dummy sc. Because plt.colorbar(sc,...) requires a mappable argument. How can I get rid of this dummy sc and still draw my colorbar?
import matplotlib
import numpy as np
import os
import matplotlib as mpl
from matplotlib.colors import Normalize
import matplotlib.cm as matplotlib_cm
from matplotlib import pyplot as plt
print(matplotlib.__version__)
row_list=['row1', 'row2', 'row3']
column_list=[2]
maxProcessiveGroupLength=2
index = column_list.index(maxProcessiveGroupLength)
plot1,panel1 = plt.subplots(figsize=(20+1.5*len(column_list), 10+1.5*len(row_list)))
plt.rc('axes', edgecolor='lightgray')
#make aspect ratio square
panel1.set_aspect(1.0)
panel1.text(0.1, 1.2, 'DEBUG', horizontalalignment='center', verticalalignment='top', fontsize=60, fontweight='bold', fontname='Arial',transform=panel1.transAxes)
if (len(column_list) > 1):
panel1.set_xlim([1, index + 1])
panel1.set_xticks(np.arange(0, index + 2, 1))
else:
panel1.set_xlim([0, len(column_list)])
panel1.set_xticks(np.arange(0, len(column_list)+1, 1))
if (len(row_list) > 1):
panel1.set_ylim([1, len(row_list)])
else:
panel1.set_ylim([0, len(row_list)])
panel1.set_yticks(np.arange(0, len(row_list) + 1, 1))
panel1.set_facecolor('white')
panel1.grid(color='black')
for edge, spine in panel1.spines.items():
spine.set_visible(True)
spine.set_color('black')
xlabels = None
if (index is not None):
xlabels = column_list[0:index + 1]
ylabels = row_list
cmap = matplotlib_cm.get_cmap('Blues') # Looks better
v_min = 2
v_max = 20
norm = Normalize(v_min, v_max)
bounds = np.arange(v_min, v_max+1, 2)
# Plot the circles with color
for row_index, row in enumerate(row_list):
for column_index, processive_group_length in enumerate(column_list):
radius=0.35
color=10+column_index*3+row_index*3
circle = plt.Circle((column_index + 0.5, row_index + 0.5), radius,color=cmap(norm(color)), fill=True)
panel1.add_patch(circle)
# Used for scatter plot
x = []
y = []
c = []
for row_index, processiveGroupLength in enumerate(row_list):
x.append(row_index)
y.append(row_index)
c.append(0.5)
# This code defines the ticks on the color bar
# plot the scatter plot
sc = plt.scatter(x, y, s=0, c=c, cmap=cmap, vmin=v_min, vmax=v_max, edgecolors='black')
# colorbar to the bottom
cb = plt.colorbar(sc ,orientation='horizontal') # this works because of the scatter
cb.ax.set_xlabel("colorbar label", fontsize=50, labelpad=25)
# common for horizontal colorbar and vertical colorbar
cbax = cb.ax
cbax.tick_params(labelsize=40)
text_x = cbax.xaxis.label
text_y = cbax.yaxis.label
font = mpl.font_manager.FontProperties(size=40)
text_x.set_font_properties(font)
text_y.set_font_properties(font)
# CODE GOES HERE TO CENTER X-AXIS LABELS...
panel1.set_xticklabels([])
mticks = panel1.get_xticks()
panel1.set_xticks((mticks[:-1] + mticks[1:]) / 2, minor=True)
panel1.tick_params(axis='x', which='minor', length=0, labelsize=50)
if xlabels is not None:
panel1.set_xticklabels(xlabels,minor=True)
panel1.xaxis.set_ticks_position('top')
plt.tick_params(
axis='x', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False) # labels along the bottom edge are off
# CODE GOES HERE TO CENTER Y-AXIS LABELS...
panel1.set_yticklabels([])
mticks = panel1.get_yticks()
panel1.set_yticks((mticks[:-1] + mticks[1:]) / 2, minor=True)
panel1.tick_params(axis='y', which='minor', length=0, labelsize=50)
panel1.set_yticklabels(ylabels, minor=True) # fontsize
plt.tick_params(
axis='y', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
left=False) # labels along the bottom edge are off
plt.show()
From the documentation of colorbar:
Note that one can create a ScalarMappable "on-the-fly" to generate
colorbars not attached to a previously drawn artist
In your example, the following allows for creating the same colorbar without the scatter plot:
cb = plt.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap), orientation='horizontal')
I have data sets like (x,y,(z1,z2,z3..)). I am trying
plt.pcolor(x,y,z1)
plt.pcolor(x,y,z2)
plt.pcolor(x,y,z3)
plt.colorbar()
plt.show()
This is showing only the pcolor plot of the last data set. How can I plot all in same plot and same colorbar scale?
You could try with subplots, and make sure all the images with the same intensity scale (use the same vmin and vmax arguments of pcolor() for all your images). Below is an example:
import numpy as np
import matplotlib.pyplot as plt
dx, dy = 0.15, 0.05
y, x = np.mgrid[slice(-3, 3 + dy, dy),
slice(-3, 3 + dx, dx)]
z = (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2)
z1 = z[:-1, :-1]
z2 = z[:-1, :-1]
z3 = z[:-1, :-1]
z_min, z_max = -np.abs(z).max(), np.abs(z).max()
data = [[x,y,z1],[x,y,z2],[x,y,z3]]
# Plot each slice as an independent subplot
fig, axes = plt.subplots(nrows=1, ncols=3)
for dat, ax in zip(data, axes.flat):
# The vmin and vmax arguments specify the color limits
pc = ax.pcolor(dat[0],dat[1],dat[2], vmin=z_min, vmax=z_max)
# Make an axis for the colorbar on the right side
cax = fig.add_axes([0.9, 0.1, 0.03, 0.8])
fig.colorbar(pc, cax=cax)
plt.show()
It will show like this:
Right now there're some statistics plotted in 3d bar over (x, y). each bar height represents the density of the points in side the square grid of (x,y) plane. Right now, i can put different color on each bar. However, I want to put progressive color on the 3d bar, similar as the cmap, so the bar will be gradient filled depending on the density.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# height of the bars
z = np.ones((4, 4)) * np.arange(4)
# position of the bars
xpos, ypos = np.meshgrid(np.arange(4), np.arange(4))
xpos = xpos.flatten('F')
ypos = ypos.flatten('F')
zpos = np.zeros_like(xpos)
dx = 0.5 * np.ones_like(zpos)
dy = dx.copy()
dz = z.flatten()
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b', zsort='average')
plt.show()
Output the above code:
Let me first say that matplotlib may not be the tool of choice when it comes to sophisticated 3D plots.
That said, there is no built-in method to produce bar plots with differing colors over the extend of the bar.
We therefore need to mimic the bar somehow. A possible solution can be found below. Here, we use a plot_surface plot to create a bar that contains a gradient.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.colors
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection= Axes3D.name)
def make_bar(ax, x0=0, y0=0, width = 0.5, height=1 , cmap="viridis",
norm=matplotlib.colors.Normalize(vmin=0, vmax=1), **kwargs ):
# Make data
u = np.linspace(0, 2*np.pi, 4+1)+np.pi/4.
v_ = np.linspace(np.pi/4., 3./4*np.pi, 100)
v = np.linspace(0, np.pi, len(v_)+2 )
v[0] = 0 ; v[-1] = np.pi; v[1:-1] = v_
x = np.outer(np.cos(u), np.sin(v))
y = np.outer(np.sin(u), np.sin(v))
z = np.outer(np.ones(np.size(u)), np.cos(v))
xthr = np.sin(np.pi/4.)**2 ; zthr = np.sin(np.pi/4.)
x[x > xthr] = xthr; x[x < -xthr] = -xthr
y[y > xthr] = xthr; y[y < -xthr] = -xthr
z[z > zthr] = zthr ; z[z < -zthr] = -zthr
x *= 1./xthr*width; y *= 1./xthr*width
z += zthr
z *= height/(2.*zthr)
#translate
x += x0; y += y0
#plot
ax.plot_surface(x, y, z, cmap=cmap, norm=norm, **kwargs)
def make_bars(ax, x, y, height, width=1):
widths = np.array(width)*np.ones_like(x)
x = np.array(x).flatten()
y = np.array(y).flatten()
h = np.array(height).flatten()
w = np.array(widths).flatten()
norm = matplotlib.colors.Normalize(vmin=0, vmax=h.max())
for i in range(len(x.flatten())):
make_bar(ax, x0=x[i], y0=y[i], width = w[i] , height=h[i], norm=norm)
X, Y = np.meshgrid([1,2,3], [2,3,4])
Z = np.sin(X*Y)+1.5
make_bars(ax, X,Y,Z, width=0.2, )
plt.show()