matplotlib pyplot: subplot size - python

If I plot a single graph as below, it will be of size (x * y).
import matplotlib.pyplot as plt
plt.plot([1, 2], [1, 2])
However, if I plot 3 sub-graphs in the same row, each of them will be of size ((x / 3) * y).
fig, ax = plt.subplots(1, 3, sharey = True)
for i in range(3):
ax[i].plot([1, 2], [1, 2])
How can I obtain these 3 subplots, each of which is of size (x * y)?

The figure object has a default size that does not know about the number of subplots. You can change the figure size when you make the figure to suit your needs though.
import matplotlib.pyplot as plt
nx = 3
ny = 1
dxs = 8.0
dys = 6.0
fig, ax = plt.subplots(ny, nx, sharey = True, figsize=(dxs*nx, dys*ny) )
for i in range(nx):
ax[i].plot([1, 2], [1, 2])

Related

Matplotlib align uneven number of subplots

I want to plot 11 figures using subplots. My idea is to have 2 rows: 6 plots on the first, 5 on the second. I use the following code.
import matplotlib.pyplot as plt
import pandas as pd
fig, axes = plt.subplots(2, 6, figsize=(30, 8))
fig.tight_layout(h_pad=6, w_pad=6)
x = 0
y = 0
for i in range(0, 11):
data = [[1, i*1], [2, i*2*2], [3, i*3*3]]
df = pd.DataFrame(data, columns = ['x', 'y'])
df.plot('x', ['y'], ax=axes[x,y])
y += 1
if y > 5:
y = 0
x += 1
fig.delaxes(ax=axes[1,5])
This works, but the bottom row is not aligned to the center, which makes the result a bit ugly. I want the figures to all be of the same size, so I cannot extend the last one to make everything even.
My question: how do I align the second row to be centered such that the full picture is symmetrical?
You could use gridspec dividing each row into 12 partitions and recombining them pairswise:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import pandas as pd
fig = plt.figure(figsize=(12, 5))
gs = gridspec.GridSpec(2, 12)
for i in range(0, 11):
if i < 6:
ax = plt.subplot(gs[0, 2 * i:2 * i + 2])
else:
ax = plt.subplot(gs[1, 2 * i - 11:2 * i + 2 - 11])
data = [[1, i * 1], [2, i * 2 * 2], [3, i * 3 * 3]]
df = pd.DataFrame(data, columns=['x', 'y'])
df.plot('x', 'y', ax=ax)
plt.tight_layout()
plt.show()

Separate bar in chart

I would like to show in every bin of the histogram, the 3 bars separated, so that it does not overlap. My code is this:
face = io.imread('images/face.png')
red_chanel = face[:,:,0]
green_chanel = face[:,:,1]
blue_chanel = face[:,:,2]
red_chanel = red_chanel.astype('float')
green_chanel = green_chanel.astype('float')
blue_chanel = blue_chanel.astype('float')
face = face.astype('float')
fig, ax1 = plt.subplots(ncols = 1, figsize = (20, 5))
hstred=exposure.histogram(red_chanel, nbins=28)
hstgreen=exposure.histogram(green_chanel, nbins=28)
hstblue=exposure.histogram(blue_chanel, nbins=28)
ax1.bar(list(range(28)), hstred[0], align='edge')
ax1.bar(list(range(28)), hstgreen[0], align='edge')
ax1.bar(list(range(28)), hstblue[0], align='edge')
plt.show()
How can I separate the bars?
I think you can shift the x-axis for 2nd and 3rd barplot and play with bar width a little. In the end, change the xticks.
import numpy as np
ax1.bar(np.arange(28), hstred[0], align='edge', width=0.3)
#shifting the xaxis
ax1.bar(np.arange(28)+0.3, hstgreen[0], align='edge', width=0.3)
ax1.bar(np.arange(28)+0.6, hstblue[0], align='edge', width=0.3)
plt.xticks(np.arange(0,28)+0.3, np.arange(0,28)) #resetting the ticks
Here is an example:
x1 = [1, 2, 3, 4, 5]
y1 = [1, 2, 3, 5, 6]
y2 = [4, 4, 2, 2, 2]
y3 = [3, 4, 6, 7, 8]
fig,ax = plt.subplots()
ax.bar(x1,y1,width=0.3)
ax.bar(np.array(x1)+0.3,y2,width=0.3)
ax.bar(np.array(x1)+0.6,y3,width=0.3)
plt.xticks(np.arange(0,6)+0.3, np.arange(0,6))
plt.show()
Output:

layover plots in one figure in Python

I can layover two curves in 1 plot like so
X = np.array([1, 5, 8])
y = np.array([2, 10, 3])
x_max = np.array([5])
y_max = np.array([10])
fig, ax = plt.subplots(figsize=(8,6));
ax.plot(X, y, 'k--', label="savitzky")
ax.scatter(x_max, y_max, s=200, c='k', marker='*');
Then I will get the following:
Lets say I have a data frame and I want to plot all of its columns at once. I can do that like so:
df_2 = pd.DataFrame(data = {'col_1':np.array([2, 10, 3]), 'col_2':np.array([3, 4, 7])},
index = np.array([1, 5, 8]))
df_2.plot()
to get:
My question is how can I combine these two so I can plot the whole dataframe at once
and then lay over my vectors of maximum points?(my real data frame is bigger than this, and so are the vectors of maximums)
Thanks
The following is one way to do it:
Create an axis object ax
Plot the DataFrame on this axis
Get the maximum element and the corresponding index for each column
Make a scatter plot on the same axis ax
fig, ax = plt.subplots()
df_2 = pd.DataFrame(data = {'col_1':np.array([2, 10, 3]),
'col_2':np.array([3, 4, 7])},
index = np.array([1, 5, 8]))
df_2.plot(ax=ax) # Plot the DataFrame on ax object
max_points = [(df_2[col].idxmax(), df_2[col].max()) for col in df_2.columns]
ax.plot(*zip(*max_points), 'b*', ms=10) # Unpack the list of (x, y) tuples
ax.set_xlim(None, 8.2)
You can do it like this:
Here I have assigned the axis object given by the df_2.plot to ax and plotted the further graph on it (ax)
X = np.array([1, 5, 8])
y = np.array([2, 10, 3])
x_max = np.array([5])
y_max = np.array([10])
df_2 = pd.DataFrame(data = {'col_1':np.array([2, 10, 3]), 'col_2':np.array([3, 4, 7])}, index = np.array([1, 5, 8]))
ax=df_2.plot(figsize=(8,6))
ax.plot(X, y, 'k--', label="savitzky")
ax.scatter(x_max, y_max, s=200, c='k', marker='*');
plt.show()

Best way to plot a 2d contour plot with a numpy meshgrid

i'm looking for the best way to create a contour plot using a numpy meshgrid.
I have excel data in columns simplyfied looking like this:
x data values: -3, -2, -1, 0, 1, 2 ,3, -3, -2, -1, 0, 1, 2, 3
y data values: 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2
z data values: 7 , 5, 6, 5, 1, 0, 9, 5, 3, 8, 3, 1, 0, 4
The x and y values define a 2d plane with the length (x-Axis) of 7 values and depth (y-Axis) of 2 values. The z values define the colour at the corresponing points (more or less a z-Axis).
I've tried:
import matplotlib.pyplot as plt
import numpy as np
x = [-3,-2,-1,0,1,2,3]
y = [1,2]
z = [7,5,6,5,1,0,9,5,3,8,3,1,0,4]
x, y = np.meshgrid(x, y)
A = np.array(z)
B = np.reshape(A, (-1, 2))
fig = plt.figure()
ax1 = plt.contourf(x, y, B)
plt.show()
I'm pretty sure i'm not getting how the meshgrid works. Do i have to use the whole List of x and y values for it to work?
How do i create a rectangular 2d plot with the length (x) of 7 and the depth (y) of 2 and the z values defining the shading/colour at the x and y values?
Thanks in advance guys!
Try
x_, y_ = np.meshgrid(x, y)
z_grid = np.array(z).reshape(2,7)
fig = plt.figure()
ax1 = plt.contourf(x_,y_,z_grid)
plt.show()
Edit: If you would like to smooth, as per your comment, you can try something like scipy.ndimage.zoom() as described here, i.e., in your case
from scipy import ndimage
z_grid = np.array(z).reshape(2,7)
z_grid_interp = ndimage.zoom(z_grid, 100)
x_, y_ = np.meshgrid(np.linspace(-3,3,z_grid_interp.shape[1]),np.linspace(1,2,z_grid_interp.shape[0]))
and then plot as before:
fig = plt.figure()
ax1 = plt.contourf(x_,y_,z_grid_interp)
plt.show()
This is one way where you use the shape of the meshgrid (X or Y) to reshape your z array. You can, moreover, add a color bar using plt.colorbar()
import matplotlib.pyplot as plt
import numpy as np
x = [-3,-2,-1,0,1,2,3]
y = [1,2]
z = np.array([7,5,6,5,1,0,9,5,3,8,3,1,0,4])
X, Y = np.meshgrid(x, y)
print (X.shape, Y.shape)
# (2, 7) (2, 7) Both have same shape
Z = z.reshape(X.shape) # Use either X or Y to define shape
fig = plt.figure()
ax1 = plt.contourf(X, Y, Z)
plt.colorbar(ax1)
plt.show()
def f(x, y):
return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2, 3 )
y = np.linspace(0, 3, 4)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
plt.contour(X, Y, Z, cmap='RdGy');

Plot multiple stacked bar in the same figure

i would like to multiple stacked bar in the same plot. This is my code:
file_to_plot = file_to_plot.set_index(['user'])
fig, ax = plt.subplots()
fontP = FontProperties()
fontP.set_size('small')
file_to_plot[[" mean_accuracy_all_classes_normal", " delta_all_classes"]].plot(ax=ax, kind='bar', color= ['g', 'r'], width = 0.65, align="center", stacked=True)
file_to_plot[[" mean_accuracy_user_classes_normal", " delta_user_classes"]].plot(ax=ax, kind='bar', color=['y', 'b'], width=0.65, align="center", stacked = True)
lgd = ax.legend(['Tutte le classi (normale)', 'Tutte le classi (incrementale)', 'Classi utente (normale)', 'Classi utente (incrementale)'], prop=fontP, loc=9, bbox_to_anchor=(0.5, -0.15), ncol=4,borderaxespad=0.)
ax.set_ylabel('% Accuratezza')
ax.set_xlabel('Utenti')
This is the results:
The second plot overwhelms me when I want to plot them together. How can I do?
This should work the way you want:
import pandas as pd
df = pd.DataFrame(dict(
A=[1, 2, 3, 4],
B=[2, 3, 4, 5],
C=[3, 4, 5, 6],
D=[4, 5, 6, 7]))
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize=(20, 10))
ab_bar_list = [plt.bar([0, 1, 2, 3], df.B, align='edge', width= 0.2),
plt.bar([0, 1, 2, 3], df.A, align='edge', width= 0.2)]
cd_bar_list = [plt.bar([0, 1, 2, 3], df.D, align='edge',width= -0.2),
plt.bar([0, 1, 2, 3], df.C, align='edge',width= -0.2)]
Just keep in mind, the width value for one group must be positive, and negative for the second one. Use align by edge as well.
You have to place the bar with the biggest values before the bar with the lowest values, and if you want the bars to appear stacked above one another rather than one in front of another, change df.B and df.D to df.B + df.A and df.D + df.C, respectively. If there's no apparent or consisting pattern, use the align by edge and width method with the one suggested by #piRSquared.
Another alternative would be to access each value from a green bar and compare it to the corresponding value from the red bar, and plot accordingly (too much unnecessary work in this one).
I thought this would be straightforward. Hopefully someone else will chime in with a better solution. What I did was to take the diff's of the columns and run a stacked chart.
df = pd.DataFrame(dict(
A=[1, 2, 3, 4],
B=[2, 3, 4, 5],
C=[3, 4, 5, 6]
))
df.diff(axis=1).fillna(df).astype(df.dtypes).plot.bar(stacked=True)
For comparison
fig, axes = plt.subplots(1, 2, figsize=(10, 4), sharey=True)
df.plot.bar(ax=axes[0])
df.diff(axis=1).fillna(df).astype(df.dtypes).plot.bar(ax=axes[1], stacked=True)
there is in fact a direct way of stacking the bars via the bottom keyword
(if you plot a horizontal barplot with plt.barh use left instead of bottom)!
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(dict(A=[1, 2, 3, 4], B=[2, 3, 4, 5], C=[3, 4, 5, 6]))
df2 = df / 2
f, ax = plt.subplots()
ax.bar(df.index, df.A, align='edge', width=0.2)
ax.bar(df.index, df.B, align='edge', width=0.2, bottom=df.A)
ax.bar(df.index, df.C, align='edge', width=0.2, bottom=df.A + df.B)
ax.bar(df2.index, df2.A, align='edge', width=-0.2)
ax.bar(df2.index, df2.B, align='edge', width=-0.2, bottom=df2.A)
ax.bar(df2.index, df2.C, align='edge', width=-0.2, bottom=df2.A + df2.B)
I used numpy to add the arrays together. Not sure if its exactly what you wanted, but its what I needed when I stumbled on this question. Thought it might help others.
import matplotlib.pyplot as plt
import numpy as np
dates = ['22/10/21', '23/10/21', '24/10/21', '25/10/21', '26/10/21']
z1 = np.array([20, 35, 30, 35, 27])
z2 = np.array([25, 32, 34, 20, 25])
z3 = np.array([20, 35, 30, 35, 27])
z4 = np.array([25, 32, 34, 20, 25])
z5 = np.array([20, 35, 30, 35, 27])
width = 0.35 # the width of the bars: can also be len(x) sequence
fig, ax = plt.subplots()
ax.bar(dates, z1, width, color='0.8', label='Z1')
ax.bar(dates, z2, width, color='b', label='Z2',bottom=z1)
ax.bar(dates, z3, width, color='g', label='Z3',bottom=z1 + z2)
ax.bar(dates, z4, width, color='tab:orange', label='Z4',bottom=z1 + z2 + z3)
ax.bar(dates, z5, width, color='r', bottom=z1 + z2 + z3 + z4,
label='Z5')
ax.set_ylabel('Time in HR Zones')
ax.set_title('HR Zones')
ax.legend()
plt.show()
Stacked Bar Graph

Categories