Matplotlib - Subplot not showing - python

I want to turn a normal plot into a subplot. Here's the code for the plot, which works:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
d = {'A': [1, 2, 3, 4, 5, 6], 'B': [-2.5, -1.00, .25, 1.56, .75, 1.20]}
df = pd.DataFrame(data=d)
x = np.arange(0, 999, 0.1)
y1 = -.75
y2 = .75
plt.fill_between(x, y1, y2, color='lawngreen', alpha='.6')
plt.scatter(df.A, df.B)
plt.plot(df.A, df.B)
plt.axhline(y=0, color='black')
plt.xticks(np.arange(0, 999))
plt.ylim([-4, 4])
plt.xlim([0, df.A.max() + 1])
plt.show()
Then here's what I tried to make it into a subplot. The console doesn't throw any errors, it's just not showing any plot.
fig = Figure()
ax = fig.add_subplot(111)
x = np.arange(0, 999, 0.1)
y1 = -.75
y2 = .75
ax.fill_between(x, y1, y2, color='lawngreen', alpha='.6')
ax.scatter(df.A, df.B)
ax.plot(df.A, df.B)
ax.axhline(y=0, color='black')
ax.set_xticks(np.arange(0, 999))
ax.set_ylim([-4, 4])
ax.set_xlim([0, df.A.max() + 1])
plt.show()
What am I doing wrong?

Use fig = plt.figure() instead of fig = Figure().
Your code would be:
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.arange(0, 999, 0.1)
y1 = -.75
y2 = .75
ax.fill_between(x, y1, y2, color='lawngreen', alpha='.6')
ax.scatter(df.A, df.B)
ax.plot(df.A, df.B)
ax.axhline(y=0, color='black')
ax.set_xticks(np.arange(0, 999))
ax.set_ylim([-4, 4])
ax.set_xlim([0, df.A.max() + 1])
plt.show()
Output:

Related

Is it possible to set generic legend next to four subplots matplotlib?

I have the following code:
x1 = np.linspace(0, 5, 10)
y1 = x1 + np.random.randn(10)
y2 = x1 + np.random.randn(10)
x2 = np.linspace(0, 5, 10)
y3 = x2 + np.random.randn(10)
y4 = x2 + np.random.randn(10)
x3 = np.linspace(0, 5, 10)
y5 = x3 + np.random.randn(10)
y6 = x3 + np.random.randn(10)
x4 = np.linspace(0, 5, 10)
y7 = x4 + np.random.randn(10)
y8 = x4 + np.random.randn(10)
# Set up a figure with 2 rows and 2 columns of subplots
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
x = [i for i in range(10,101,10)]
# Plot multiple line charts on each subplot
l1, = ax1.plot(x1, y1, 'o-')
l2, = ax1.plot(x1, y2, '^-')
ax1.legend((l1, l2), ('Line 1', 'Line 2'))
l3, = ax2.plot(x2, y3, 's-')
l4, = ax2.plot(x2, y4, 'd-')
ax2.legend((l3, l4), ('Line 3', 'Line 4'))
l5, = ax3.plot(x3, y5, 'x-')
l6, = ax3.plot(x3, y6, '+-')
ax3.legend((l5, l6), ('Line 5', 'Line 6'))
l7, = ax4.plot(x4, y7, '*-')
l8, = ax4.plot(x4, y8, 'p-')
ax4.legend((l7, l8), ('Line 7', 'Line 8'))
# Set the x- and y-limits and labels for each subplot
ax1.set_xlim([0, 5])
ax1.set_ylim([0, 10])
ax1.set_xlabel('X1')
ax1.set_ylabel('Y1')
ax1.set_title('Subplot 1')
ax2.set_xlim([0, 5])
ax2.set_ylim([0, 10])
ax2.set_xlabel('X2')
ax2.set_ylabel('Y2')
ax2.set_title('Subplot 2')
ax3.set_xlim([0, 5])
ax3.set_ylim([0, 10])
ax3.set_xlabel('X3')
ax3.set_ylabel('Y3')
Which yields:
With my actual datasets, the lines with the same color are the same. Hence, I only need one legend on the side of the four subplots. How can I do this?

fill space between 3 graphs in Matplotlib

I need to fill in the shaded area between my graphs.What should I write in fill_between to do this?
import numpy as np
import matplotlib.pyplot as plt
y = lambda z: (2 * z - z ** 2) ** (1 / 2)
y1 = lambda x: (6 * x - x ** 2) ** (1 / 2)
y2 = lambda c: c
x = np.linspace(0, 12, 500)
z = np.linspace(0, 12, 500)
c = np.linspace(0, 12, 500)
plt.ylim(0, 4)
plt.xlim(0, 4)
plt.plot(z, y(z), color='blue', label="$y=\\sqrt{2x-x^2}$")
plt.plot(c, y2(c), color='black', label='$y=x$')
plt.plot(x, y1(x), color='red', label='$y=\\sqrt{6x-x^2}$')
plt.plot([0, 4], [0, 0], color='yellow', label='y=0')
plt.grid(True, zorder=5)
miny = np.minimum(y2(c), y1(x))
plt.fill_between(x, y(z), miny, where=(miny > y(x)), alpha=0.5)
plt.legend()
plt.show()
Make the domain of your functions to be the same (e.g. [0, 4]). The below code does what you want:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 4, 500)
y = np.piecewise(x, [x <= 2, x > 2], [lambda x: np.sqrt(2 * x - x ** 2), 0])
y1 = np.sqrt(6 * x - x ** 2)
y2 = x
y3 = 0*x
plt.plot(x, y, color='blue', label="$y=\\sqrt{2x-x^2}$")
plt.plot(x, y1, color='red', label='$y1=\\sqrt{6x-x^2}$')
plt.plot(x, y2, color='black', label='$y2=x$')
plt.plot(x, y3, color='yellow', label='y3=0')
plt.grid(True, zorder=5)
miny = np.minimum(y2, y1)
plt.fill_between(x, y, miny, where = (miny > y), alpha=0.5)
plt.legend()
plt.show()

Fill the area between multiple curves and lines

I have 3 curves and I want to fill the area between them. How should I do this?
This is what I have so far:
import numpy as np
import matplotlib.pyplot as plt
y = lambda z: -(z ** 2)
y1 = lambda x: x ** (1 / 3)
x = np.linspace(0, 2, 100)
z = np.linspace(0, 2, 100)
plt.plot(z, y(z), color='blue', label="y=-(x^2)")
plt.ylim(-2, 2)
plt.xlim(0, 2)
plt.plot(x, y1(x), color='red', label='y=x^(1/3)')
plt.plot([1, 1, 1], [0, -2, 2], color='black', label='x=1')
plt.grid(True, zorder=5)
plt.legend()
k = np.arange(0,2)
f = [0,-0.2]
p = [0,0.2]
plt.fill_between(k,f,p,interpolate=True)
plt.show()
You can use where in fill_between to take care of x = 1 line. See below:
import numpy as np
import matplotlib.pyplot as plt
y = lambda z: -(z ** 2)
y1 = lambda x: x ** (1 / 3)
x = np.linspace(0, 2, 100)
z = np.linspace(0, 2, 100)
plt.ylim(-2, 2)
plt.xlim(0, 2)
#plt.grid(True, zorder=5)
plt.plot(z, y(z), color='blue', label="y=-(x^2)")
plt.plot(x, y1(x), color='red', label='y=x^(1/3)')
plt.plot([1, 1, 1], [0, -2, 2], color='black', label='x=1')
plt.fill_between(x, y(z), y1(x), where=x<=1)
plt.legend()
plt.show()

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

How to plot 3D surface with X, Y, Z when Z is a list of list in Python?

In my case, X is a range(0, 100), Y is a range(0, 10), Z is a list of list. Z has the same length as X, which is 100, and each element list inside of Z has the same dimension of Y.
Z = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ..., [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]].
I have the following code, but it does not work, it complains two or more arrays have incompatible dimensions on axis 1.
fig = plt.figure(figsize=(200, 6))
ax = fig.add_subplot(1, 2, 1, projection='3d')
ax.set_xticklabels(x_ax)
ax.set_yticklabels(y_ax)
ax.set_title("my title of chart")
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
ax.set_zlim(0, 100)
fig.colorbar(surf, shrink = 0.5, aspect = 5)
plt.show()
I guess the error is due to the data structure of Z, how do I make a compatible structure with X, and Y? Thanks
Here is a basic 3D surface plotting procedure. It seems that your X and Y are just 1D arrays. However, X, Y, and Z have to be 2D arrays of the same shape. numpy.meshgrid function is useful for creating 2D mesh from two 1D arrays.
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.array(np.linspace(-2,2,100))
y = np.array(np.linspace(-2,2,10))
X,Y = np.meshgrid(x,y)
Z = X * np.exp(-X**2 - Y**2);
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
fig.colorbar(surf, shrink = 0.5, aspect = 5)
plt.show()

Categories