matplotlib: assigning different hatch to bars
Question:
I have a dataframe where for each index, I have to plot two bars (for two series). The following code gives the output as:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.randint(0,20,size=(5, 2)), columns=list('AB'))
fig, ax = plt.subplots()
ax = df.sort_values('B', ascending=True).plot.barh(rot=0,ax=ax,hatch="/")
plt.show()
I would like to assign individual hatching for each bar. So that if A
has ‘/’ hatching, B
should have ‘|’. What modifications do I need to make in the code?
Answers:
You can plot the two bars separately:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
df = pd.DataFrame(np.random.randint(0, 20, size=(5, 2)), columns=list('AB'))
fig, ax = plt.subplots()
ax.barh(np.arange(0, len(df)), df['A'], height=0.3, hatch='/')
ax.barh(np.arange(0.3, len(df) + 0.3), df['B'], height=0.3, hatch='|')
The matplotlib example features a solution. But I don’t really like it, since it is aiming to set a different hatch to each bar.
But imho in most cases it is more relevant to set a specific hatch to each "category" of bar. You can either do it by plotting the bars separately with a hatch, or set the hatches after plotting. Setting the hatches after plotting is imho much more flexible, thus this is my approach:
df = pd.DataFrame(np.random.randint(0,20,size=(5, 2)), columns=list('AB'))
fig, ax = plt.subplots()
ax = df.sort_values('B', ascending=True).plot.barh(rot=0,ax=ax)
# get all bars in the plot
bars = ax.patches
patterns = ['/', '|'] # set hatch patterns in the correct order
hatches = [] # list for hatches in the order of the bars
for h in patterns: # loop over patterns to create bar-ordered hatches
for i in range(int(len(bars) / len(patterns))):
hatches.append(h)
for bar, hatch in zip(bars, hatches): # loop over bars and hatches to set hatches in correct order
bar.set_hatch(hatch)
# generate legend. this is important to set explicitly, otherwise no hatches will be shown!
ax.legend()
plt.show()
The advantages of this solution over plotting the bars separately are:
- you can have an arbitrary number of bars
- works with stacked and/or unstacked bars in all possible combinations
- works with the pandas plotting interface
With the main drawback being the additional LOC especially for plotting only a few bars. But packing it into a function/module and re-using it solves this problem. 🙂
here is a test ca can help you
import numpy as np
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.randint(0,20,size=(5, 2)), columns=list('AB'))
plt.hist(df['A'], color = 'blue',
edgecolor = 'red', hatch = '/' , label = 'df.A',orientation = 'horizontal',
histtype = 'bar')
plt.hist(df['B'],color = 'YELLOW',
edgecolor = 'GREEN', hatch = 'O' , label = 'df.B',orientation = 'horizontal',
histtype = 'bar')
plt.legend()
plt.show()
I have a dataframe where for each index, I have to plot two bars (for two series). The following code gives the output as:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.randint(0,20,size=(5, 2)), columns=list('AB'))
fig, ax = plt.subplots()
ax = df.sort_values('B', ascending=True).plot.barh(rot=0,ax=ax,hatch="/")
plt.show()
I would like to assign individual hatching for each bar. So that if A
has ‘/’ hatching, B
should have ‘|’. What modifications do I need to make in the code?
You can plot the two bars separately:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
df = pd.DataFrame(np.random.randint(0, 20, size=(5, 2)), columns=list('AB'))
fig, ax = plt.subplots()
ax.barh(np.arange(0, len(df)), df['A'], height=0.3, hatch='/')
ax.barh(np.arange(0.3, len(df) + 0.3), df['B'], height=0.3, hatch='|')
The matplotlib example features a solution. But I don’t really like it, since it is aiming to set a different hatch to each bar.
But imho in most cases it is more relevant to set a specific hatch to each "category" of bar. You can either do it by plotting the bars separately with a hatch, or set the hatches after plotting. Setting the hatches after plotting is imho much more flexible, thus this is my approach:
df = pd.DataFrame(np.random.randint(0,20,size=(5, 2)), columns=list('AB'))
fig, ax = plt.subplots()
ax = df.sort_values('B', ascending=True).plot.barh(rot=0,ax=ax)
# get all bars in the plot
bars = ax.patches
patterns = ['/', '|'] # set hatch patterns in the correct order
hatches = [] # list for hatches in the order of the bars
for h in patterns: # loop over patterns to create bar-ordered hatches
for i in range(int(len(bars) / len(patterns))):
hatches.append(h)
for bar, hatch in zip(bars, hatches): # loop over bars and hatches to set hatches in correct order
bar.set_hatch(hatch)
# generate legend. this is important to set explicitly, otherwise no hatches will be shown!
ax.legend()
plt.show()
The advantages of this solution over plotting the bars separately are:
- you can have an arbitrary number of bars
- works with stacked and/or unstacked bars in all possible combinations
- works with the pandas plotting interface
With the main drawback being the additional LOC especially for plotting only a few bars. But packing it into a function/module and re-using it solves this problem. 🙂
here is a test ca can help you
import numpy as np
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.randint(0,20,size=(5, 2)), columns=list('AB'))
plt.hist(df['A'], color = 'blue',
edgecolor = 'red', hatch = '/' , label = 'df.A',orientation = 'horizontal',
histtype = 'bar')
plt.hist(df['B'],color = 'YELLOW',
edgecolor = 'GREEN', hatch = 'O' , label = 'df.B',orientation = 'horizontal',
histtype = 'bar')
plt.legend()
plt.show()