layover plots in one figure in Python - 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()

Related

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:

Two column subplot using matplotlib and seaborn

I have a requirement to add subplots with two column and with multiple rows. The rows will not be fixed but for one column I want to create seaborn line plot from one data set and for second column i want to create seaborn line plot for another data set.
I have tried the following but not working.
tips = sns.load_dataset("tips")
dataset2=tips
days = list(tips.drop_duplicates('day')['day'])
ggpec = gridspec.GridSpec(len(days ), 2)
axs = []
for i,j in zip(days,range(1,len(days)+1)):
fig = plt.figure(figsize=(20,4),dpi=200)
palette = sns.color_palette("magma", 2)
chart = sns.lineplot(x="time", y="total_bill",
hue="sex",style='sex',
palette=palette, data=tips[tips['day']==i])
chart.set_xticklabels(
chart.get_xticklabels(),
rotation=90,
minor=True,
verticalalignment=True,
horizontalalignment='right',
fontweight='light',
fontsize='large'
)
plt.title("Title 1",fontsize=18, fontweight='bold')
fig2 = plt.figure(figsize=(20,5),dpi=200)
palette = sns.color_palette("magma", 2)
chart = sns.lineplot(x="time", y="total_bill",
hue="sex",style='sex',
palette=palette, data=dataset2[dataset2['day']==i])
chart.set_xticklabels(
chart.get_xticklabels(),
rotation=90,
minor=True,
verticalalignment=True,
horizontalalignment='right',
fontweight='light',
fontsize='large'
)
plt.title("Title 2",fontsize=18, fontweight='bold')
plt.show()
for creating multiple plots with 2 columns and multiple rows, you can use subplot. Where in you define the number of rows, columns and the subplot to activate at present.
import matplotlib.pyplot as plt
plt.subplot(3, 2, 1) # Define 3 rows, 2 column, Activate subplot 1.
plt.plot([1, 2, 3, 4, 5, 6, 7], [7, 8, 6, 5, 2, 2, 4], 'b*-', label='Plot 1')
plt.subplot(3, 2, 2) # 3 rows, 2 column, Activate subplot 2.
# plot some data here
plt.plot([1, 2, 3, 4, 5, 6, 7], [7, 8, 6, 5, 2, 2, 4], 'b*-', label='Plot 2')
plt.subplot(3, 2, 3) # 3 rows, 2 column, Activate subplot 3.
# plot some data here
plt.plot([1, 2, 3, 4, 5, 6, 7], [7, 8, 6, 5, 2, 2, 4], 'b*-', label='Plot 3')
# to Prevent subplots overlap
plt.tight_layout()
plt.show()
You can build upon this concept to draw you seaborn plots as well.
f, axes = plt.subplots(3,2) # Divide the plot into 3 rows, 2 columns
# Draw the plot in first row second column
sns.lineplot(xData, yData, data=dataSource, ax=axes[0][1])

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

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