matplotlib advanced bar plot
I gotta run, but here's something to get you started:
import numpy as np
import matplotlib
matplotlib.rcParams['text.usetex'] = False
import matplotlib.pyplot as plt
import pandas
df = pandas.DataFrame(np.random.uniform(size=37)*100, columns=['A'])
threshold = 75
fig, ax = plt.subplots(figsize=(8,3))
good = df['A'][df['A'] >= threshold]
bad = df['A'][df['A'] < threshold]
ax.bar(left=good.index, height=good, align='center', color='ForestGreen', zorder=5)
ax.bar(left=bad.index, height=bad, align='center', color='Firebrick', zorder=5)
ax.axhline(y=threshold, linewidth=2, color='ForestGreen', zorder=0)
ax.set_xticks(df.index)
ax.set_xlim(left=df.index[0]-0.75, right=df.index[-1]+0.75)
def annotateBars(row, ax=ax):
if row['A'] < 20:
color = 'black'
vertalign = 'bottom'
vertpad = 2
else:
color = 'white'
vertalign = 'top'
vertpad = -2
ax.text(row.name, row['A'] + vertpad, "{:.1f}%".format(row['A']),
zorder=10, rotation=90, color=color,
horizontalalignment='center',
verticalalignment=vertalign,
fontsize=8, weight='heavy')
junk = df.apply(annotateBars, ax=ax, axis=1)
And that gives me:How to plot a barplot with different hatch and edge color with legends using matplotlib?
Your can combine the line1
and line2
with a tuple in the handle lists.
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
# draw hatch
line1 = ax.bar(range(1, 5), range(1, 5), color='none', edgecolor='r', hatch="/", lw=1., zorder = 0)
# draw edge
line2 = ax.bar(range(1, 5), range(1, 5), color='none', edgecolor='k', zorder=1, lw=2.)
ax.set_xticks([1.5, 2.5, 3.5, 4.5])
ax.legend([(line1, line2)],['hatch'])
plt.show()
You can see the doc.
Single Stacked Bar Chart Matplotlib
First transpose one column DataFrame:
df.T.plot.barh(stacked=True, legend=False)
If 2 or more columns:df[['Percentage']].T.plot.barh(stacked=True, legend=False)
How to create grouped bar plots in a single figure from a wide dataframe
- This can be done with
seaborn.barplot
, or with just usingpandas.DataFrame.plot
, which avoids the additional import. - Annotate as shown in How to plot and annotate a grouped bar chart
- Add annotations with
.bar_label
, which is available withmatplotlib 3.4.2
. - The link also shows how to add annotations if using a previous version of
matplotlib
.
- Add annotations with
- Using
pandas 1.3.0
,matplotlib 3.4.2
, andseaborn 0.11.1
With pandas.DataFrame.plot
- This option requires setting
x='name'
, orres1
andres2
as the index.
import pandas as pd
test_df = pd.DataFrame({'name': ['a', 'b', 'c'], 'res1': [1,2,3], 'res2': [4,5,6]})
# display(test_df)
name res1 res2
0 a 1 4
1 b 2 5
2 c 3 6
# plot with 'name' as the x-axis
p1 = test_df.plot(kind='bar', x='name', rot=0)
# annotate each group of bars
for p in p1.containers:
p1.bar_label(p, fmt='%.1f', label_type='edge')
import pandas as pd
test_df = pd.DataFrame({'name': ['a', 'b', 'c'], 'res1': [1,2,3], 'res2': [4,5,6]})
# set name as the index and then Transpose the dataframe
test_df = test_df.set_index('name').T
# display(test_df)
name a b c
res1 1 2 3
res2 4 5 6
# plot and annotate
p1 = test_df.plot(kind='bar', rot=0)
for p in p1.containers:
p1.bar_label(p, fmt='%.1f', label_type='edge')
With seaborn.barplot
- Convert the dataframe from a wide to long format with
pandas.DataFrame.melt
, and then use thehue
parameter.
import pandas as pd
import seaborn as sns
test_df = pd.DataFrame({'name': ['a', 'b', 'c'], 'res1': [1,2,3], 'res2': [4,5,6]})
# melt the dataframe into a long form
test_df = test_df.melt(id_vars='name')
# display(test_df.head())
name variable value
0 a res1 1
1 b res1 2
2 c res1 3
3 a res2 4
4 b res2 5
# plot the barplot using hue; switch the columns assigned to x and hue if you want a, b, and c on the x-axis.
p1 = sns.barplot(data=test_df, x='variable', y='value', hue='name')
# add annotations
for p in p1.containers:
p1.bar_label(p, fmt='%.1f', label_type='edge')
- With
x='variable', hue='name'
- With
x='name', hue='variable'
plotting multiple stacked bar chart
IIUC, try:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 5, figsize=(20, 8))
iax = iter(ax.flatten())
for n, g in df.groupby('Business Unit'):
g.loc[n, :].plot.bar(ax=next(iax), title=f'{n}', stacked=True)
How do I plot a categorical bar chart with different classes for each category in Matplotlib?
Supposing the data resides in a dataframe, the bars can be generated by looping through the categories:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# first create some test data, similar in structure to the question's
categories = ['Subject', 'Illumination', 'Location', 'Daytime']
df = pd.DataFrame(columns=['Category', 'Class', 'Value'])
for cat in categories:
for _ in range(np.random.randint(2, 7)):
df = df.append({'Category': cat,
'Class': "".join(np.random.choice([*'tuvwxyz'], 10)),
'Value': np.random.uniform(10, 17)}, ignore_index=True)
fig, ax = plt.subplots()
start = 0 # position for first label
gap = 1 # gap between labels
labels = [] # list for all the labels
label_pos = np.array([]) # list for all the label positions
# loop through the categories of the dataframe
# provide a list of colors (at least as long as the expected number of categories)
for (cat, df_cat), color in zip(df.groupby('Category', sort=False), ['navy', 'orange'] * len(df)):
num_in_cat = len(df_cat)
# add a text for the category, using "axes coordinates" for the y-axis
ax.text(start + num_in_cat / 2, 0.95, cat, ha='center', va='top', transform=ax.get_xaxis_transform())
# positions for the labels of the current category
this_label_pos = np.arange(start, start + num_in_cat)
# create bars at the desired positions
ax.bar(this_label_pos, df_cat['Value'], color=color)
# store labels and their positions
labels += df_cat['Class'].to_list()
label_pos = np.append(label_pos, this_label_pos)
start += num_in_cat + gap
# set the positions for the labels
ax.set_xticks(label_pos)
# set the labels
ax.set_xticklabels(labels, rotation=30)
# optionally set a new lower position for the y-axis
ax.set_ylim(ymin=9)
# optionally reduce the margin left and right
ax.margins(x=0.01)
plt.tight_layout()
plt.show()
Unexpected behavior from matplotlib using bar plots for floating values
You need to adjust the width of the bars (by default, the width is set to 0.8; with values as small as yours you can see why this becomes a problem).
Your data plotted with width set to 0.01 (plt.bar(a,b, width = 0.01)
) looks like:
Both issues you mention are due to this width parameter. The bars in barplot are centered around their x-values, thus 0.1 is the center of the first bar (with witdh of 0.8, it spans from -0.3 to 0.5). Also, since this first bar is the tallest, it covers anything within that range (so all except the last bar are at least partially covered, due to overlap).
How to make bar plot of a list in Python
I believe you want something like this:
ax = sns.barplot(x=np.arange(len(lii)), y=lii)
ax.bar_label(ax.containers[0])
plt.axis('off')
plt.show()
Related Topics
How to Exit from Python Without Traceback
How to Combine Multiple Rows into a Single Row with Pandas
Scipy Curve_Fit Doesn't Like Math Module
Print to the Same Line and Not a New Line
How to Set Opacity of Background Colour of Graph with Matplotlib
Fitting a Closed Curve to a Set of Points
Writing Unit Tests in Python: How to Start
Disable or Lock Mouse and Keyboard in Python
In Python, Is It Better to Use List Comprehensions or For-Each Loops
Make Part of a Matplotlib Title Bold and a Different Color
Representing and Solving a Maze Given an Image
Destructuring-Bind Dictionary Contents
Pandas Number Rows Within Group in Increasing Order
How to Use Asyncio with Existing Blocking Library
Building a Minimal Plugin Architecture in Python
Detect File Change Without Polling
Is There a Library Function for Root Mean Square Error (Rmse) in Python