Separate bar in chart - python

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:

Related

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()

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])

Python pyplot legend scatter

I've got 5 classes and some features that I want to plot. This is the code
x_pts = X_test.iloc[:,col_1]
y_pts = X_test.iloc[:,col_2]
color_seq = y_test
plt.scatter(x_pts, y_pts, c=color_seq, cmap='viridis')
plt.xlabel(X_test.columns[col_1])
plt.ylabel(X_test.columns[col_2])
plt.show()
and this results in the following image
I now want a legend for each color (e.g. yellow = 'class a' , blue = 'class b', ...)
The only documentation I can find is of people plotting each color differently, which is quite hard in my specific case. Isn't there a simple way to display a legend like the example here
Hope this helps:
x = [1, 3, 4, 6, 7, 9]
y = [0, 0, 5, 8, 8, 8]
labels = ['A', 'B', 'C']
colors = [0, 0, 1, 2, 2, 2]
scatter = plt.scatter(x, y,c=colors, cmap='viridis')
plt.legend(handles=scatter.legend_elements()[0], labels=labels)
plt.show()
Output:

How to add a unique horizontal bar marker in Bar Chart for each group

I want to create the graph bellow, but I want to add a horizontal line marker to each group as shown bellow, do you know how to add it based on the code I currently have?
data = np.array([
[5, 3, 2 ],
[2, -3, 5 ],
[ -4, 4, -6],
[-5, -3, -1],
[2, 6, 6]
])
bar_markers = np.array([4, 3, -2, 2, -1])
fig, axs = plt.subplots()
index = np.arange(len(data[:, 0]))
width = 0.25
p1 = plt.bar(index, data[:,0], width, bottom = 0, color = 'yellowgreen')
p2 = plt.bar(index+width, data[:, 1], width, bottom = 0, color = 'purple')
p3 = plt.bar(index+2*width, data[:, 2], width, bottom = 0, color = 'pink')
axs.set_xticks(index + width / 2)
plt.show()
You can "cheat" and make the height of each bar 0 but start the bottom of each bar at a different height, i.e. do this:
p4 = plt.bar(index+width, [0]*len(bar_markers), width*3, bottom=bar_markers, edgecolor='k')

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