Move graph position within plot (matplotlib) - python

I am trying to create a horizontal bar graph with a table in matplotlib. I am almost there, but fail to align the table with the graph. What I got so far:
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
# Example data
appsol = ['llolLl', 'nnM', 'lllld bbbblnl', 'x2x', 'foobar', 'EXZ', 'Flups', 'Flaps', 'Foobar Barfooment', 'ABC', 'FABAS', 'common', 'AQT', 'Faberjak', 'simsalsa', 'LESS', 'Wermut']
y_pos = np.arange(len(appsol)) - .3
y_pos_2 = np.arange(len(appsol)) - .1
y_pos_3 = np.arange(len(appsol)) + .1
y_pos_4 = np.arange(len(appsol)) + .3
num_tickets = [4, 4,3,2,6,7,8,1,4,4,3,2,6,7,8,1,9]
num_tickets_2 = [7,6,5,4,3,4,2,1,2,4,1,0,3,0,2,1,0]
num_tickets_3 = [1,2,1,1,1,2,2,3,1,1,2,1,3,1,1,2,3]
num_tickets_4 = [8,7,6,2,13,6,8,9,7,6,5,4,3,6,8,9,12]
bar_width = .2
fig = plt.figure(figsize=(20,20))
ax = fig.add_subplot(111)
# correct yticks
plt.yticks(y_pos_2, appsol)
plt.barh(y_pos, num_tickets, bar_width, align='center', alpha=0.4, color='r')
plt.barh(y_pos_2, num_tickets_2, bar_width, align='center', alpha=0.4, color='b')
plt.barh(y_pos_3, num_tickets_3, bar_width, align='center', alpha=0.4, color='y')
plt.barh(y_pos_4, num_tickets_4, bar_width, align='center', alpha=0.4, color='g')
plt.yticks(y_pos, appsol)
plt.xlabel('Numbers')
plt.title('Horizontal Bar Chart with table')
# Table
empty_labels = ['' for a in appsol ]
plt.yticks(y_pos_2, empty_labels)
plt.tick_params(\
axis='y', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
left='off', # ticks along the bottom edge are off
right='off', # ticks along the top edge are off
labelbottom='off')
# Adjust layout to make room for the table:
plt.subplots_adjust(left=0.4, bottom=0.2)
cell_text = []
i = len(num_tickets) - 1
for j in num_tickets:
cell_text.append([num_tickets[i], num_tickets_2[i], num_tickets_3[i], num_tickets_4[i]])
i -= 1
row_lables = appsol
column_labels = ['So Huge\nMice', 'Elephants', 'Reptiles', 'Germs']
the_table = ax.table(cellText=cell_text,
rowLabels=row_lables,
colLabels=column_labels,
loc='left')
the_table.set_fontsize(15)
the_table.scale(.5,5.0)
plt.savefig('barh_graph.png')
plt.close('all')
This produces almost what I want, except that the table rows are not aligned with the bars of the graph. So I need a way to either move the graph down half a table row, or the table up half a table row. How can I do this?

I think its easier if you create two subplots and add the table to the left subplot, instead of deriving a new subplot from the single subplot you have now. If you add the table to an existing subplot, you can use the bbox to stretch it from 0 to 1 (so fully) in the y-direction. Since the table has a header, setting the ylim of the right plot to (0, n_items), will make both align properly, and adding a slight offset because the bars are also given an offset of 0.4 (offset of the outer bar + half a barwidth). This should work automatically if the number of elements changes.
bar_width = .2
fig, axs = plt.subplots(1,2, figsize=(12,6))
fig.subplots_adjust(wspace=0, top=1, right=1, left=0, bottom=0)
axs[1].barh(y_pos[::-1], num_tickets[::-1], bar_width, align='center', alpha=0.4, color='r')
axs[1].barh(y_pos_2[::-1], num_tickets_2[::-1], bar_width, align='center', alpha=0.4, color='b')
axs[1].barh(y_pos_3[::-1], num_tickets_3[::-1], bar_width, align='center', alpha=0.4, color='y')
axs[1].barh(y_pos_4[::-1], num_tickets_4[::-1], bar_width, align='center', alpha=0.4, color='g')
axs[1].set_yticks([])
axs[1].set_xlabel('Numbers')
axs[1].set_title('Horizontal Bar Chart with table')
axs[1].set_ylim(0 - .4, (len(appsol)) + .4)
cell_text = list(zip(num_tickets, num_tickets_2, num_tickets_3, num_tickets_4))
row_lables = appsol
column_labels = ['So Huge\nMice', 'Elephants', 'Reptiles', 'Germs']
axs[0].axis('off')
the_table = axs[0].table(cellText=cell_text,
rowLabels=row_lables,
colLabels=column_labels,
bbox=[0.4, 0.0, 0.6, 1.0])
the_table.set_fontsize(15)
plt.savefig('barh_graph.png')
plt.close('all')
If you look closely you might notice that the bars are ranging from the top of the table to the bottom, you could tweak them a bit to make them start at the center of the upper and lower cell of the table.

I found a workaround: I adjust the y-boundaries of the graph:
ax.set_ylim([-.5,17.5])
Of course these numbers only work with these data dimensions.
So still, if someone has a better soltution I would like to see it.
For completness, here is the enhanced version (also changed font size and added a legend):
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
# set font and size
font = {'family' : 'Bitstream Vera Sans',
'size' : 18}
matplotlib.rc('font', **font)
# Example data
appsol = ['llolLl', 'nnM', 'lllld bbbblnl', 'x2x', 'foobar', 'EXZ', 'Flups', 'Flaps', 'Foobar Barfooment', 'ABC', 'FABAS', 'common', 'AQT', 'Faberjak', 'simsalsa', 'LESS', 'Wermut']
y_pos = np.arange(len(appsol)) - .3
y_pos_2 = np.arange(len(appsol)) - .1
y_pos_3 = np.arange(len(appsol)) + .1
y_pos_4 = np.arange(len(appsol)) + .3
num_tickets = [4, 4,3,2,6,7,8,1,4,4,3,2,6,7,8,1,9]
num_tickets_2 = [7,6,5,4,3,4,2,1,2,4,1,0,3,0,2,1,0]
num_tickets_3 = [1,2,1,1,1,2,2,3,1,1,2,1,3,1,1,2,3]
num_tickets_4 = [8,7,6,2,13,6,8,9,7,6,5,4,3,6,8,9,12]
fig = plt.figure(figsize=(20,20))
ax = fig.add_subplot(111)
# correct yticks
plt.yticks(y_pos_2, appsol)
# this aligns table and graph!!!
ax.set_ylim([-.5,17.5])
labels = ['So Huge Mice', 'Elephants', 'Reptiles', 'Germs']
bar_width = .2
plt.barh(y_pos, num_tickets, bar_width, align='center', alpha=0.4, color='r', label=labels[0])
plt.barh(y_pos_2, num_tickets_2, bar_width, align='center', alpha=0.4, color='b', label=labels[1])
plt.barh(y_pos_3, num_tickets_3, bar_width, align='center', alpha=0.4, color='y', label=labels[2])
plt.barh(y_pos_4, num_tickets_4, bar_width, align='center', alpha=0.4, color='g', label=labels[3])
plt.yticks(y_pos, appsol)
plt.xlabel('Numbers')
plt.title('Horizontal Bar Chart with table')
# Legend
plt.legend(loc='lower center', shadow=True)
num_plots = 4
x_legend = 0.3
y_legend = -0.1
ax.legend(loc='lower center',
bbox_to_anchor=(x_legend, y_legend),
ncol=num_plots, # we want the legend on just one line
shadow=True)
# Table
empty_labels = ['' for a in appsol ]
plt.yticks(y_pos_2, empty_labels)
plt.tick_params(\
axis='y', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
left='off', # ticks along the bottom edge are off
right='off', # ticks along the top edge are off
labelbottom='off')
# Adjust layout to make room for the table:
plt.subplots_adjust(left=0.4, bottom=0.1)
cell_text = []
i = len(num_tickets) - 1
for j in num_tickets:
cell_text.append([num_tickets[i], num_tickets_2[i], num_tickets_3[i], num_tickets_4[i]])
i -= 1
row_lables = appsol
column_labels = ['So Huge\nMice', 'Elephants', 'Reptiles', 'Germs']
the_table = ax.table(cellText=cell_text,
rowLabels=row_lables,
colLabels=column_labels,
loc='left')
the_table.set_fontsize(18)
the_table.scale(.5,5.34)
plt.savefig('barh_graph.png')
plt.close('all')
And this is what it looks like:

Related

Adding count plot totals and removing specific labels

Hi I have the following code. The code is in a for loop, and it makes over 300 plots.
sns.set(style='white', palette='cubehelix', font='sans-serif')
fig, axs = plt.subplots(2, 3, dpi =200);
fig.subplots_adjust(hspace=0.5, wspace=1)
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
#tmppath = 'path/{0}'.format(key);
##
sns.countplot(y='Ethnicity', data=value, orient='h', ax=axs[0,0]);
sns.despine(top=True, right=True, left=True, bottom=True,offset=True)
sns.countplot(y='Program Ratio', data=value,orient='v',ax=axs[1,0]);
sns.despine(offset=True)
sns.countplot(y='Site', data = value, ax=axs[0,1]);
sns.despine(offset=True)
sns.countplot(y='HOUSING_STATUS', data = value, ax = axs[1,1])
sns.despine(offset=True)
sns.countplot(y='Alt. Assessment', data = value, ax = axs[0,2])
sns.despine(offset=True)
pth = os.path.join(tmppath, '{0}'.format(key))
for p in axs.patches:
ax.text(p.get_x() + p.get_width()/2., p.get_width(), '%d' %
int(p.get_width()),
fontsize=12, color='red', ha='center', va='bottom')
#plt.tight_layout(pad=2.0, w_pad=1.0, h_pad=2.0);
plt.set_title('{0}'.format(key)+'Summary')
sns.despine()
axs[0,0].set_xticklabels('','Ethnicity')
axs[1,0].set_axis_labels('','Program Ratio')
axs[0,1].set_axis_labels('','Students by Site')
axs[1,1].set_axis_labels('','Housing Status')
axs[0,2].set_axis_labels('','Alt Assessment')
fig.tight_layout()
fig.subplots_adjust(top=0.88)
fig.suptitle('{0}'.format(key)+' Summary')
plt.suptitle('{0}'.format(key)+' Summary')
plt.savefig("path/{0}/{1}.pdf".format(key,key), bbox_inches = 'tight');
plt.clf()
plt.suptitle('{0} Summary'.format(key))
plt.savefig("path/{0}/{1}.pdf".format(key,key), bbox_inches = 'tight');
plt.clf()
I've checked out the links below ( and more):
Remove xticks in a matplotlib plot?
https://datascience.stackexchange.com/questions/48035/how-to-show-percentage-text-next-to-the-horizontal-bars-in-matplotlib
When I try the method from the second link. I end up with graphs like so
Without that the graph looks something like so
I want to get rid of the words count and the ticks on each subplot xaxis.
#ImportanceOfBeingErnest
Thanks, I followed your advice and this post.
Here is what is a compact version of what I ended up with
sns.set(style='white', palette=sns.palplot(sns.color_palette(ui)), font='sans-serif')
plt.figure(figsize=(20,20))
fig, axs2 = plt.subplots(2, 3, dpi =300);
fig.subplots_adjust(top=.8)
fig.subplots_adjust(hspace=1, wspace=1.5)
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
sns.countplot(y='column',palette = ui,order = df.value_counts().index, data=df,
orient='h', ax=axs2[0,0]);
axs2[0,0].set_xlabel('')
axs2[0,0].set_xticks([])
axs2[0,0].set_ylabel('')
axs2[0,0].set_title('label',size = 'small')
axs2[0,0].tick_params(axis='y', which='major', labelsize=8)
sns.despine(top=True, right=True, left=True, bottom=True,offset=True)
for p in axs2[0,0].patches:
axs2[0,0].annotate(int(p.get_width()),((p.get_x() + p.get_width()), p.get_y()), xytext=(15, -10), fontsize=8,color='#000000',textcoords='offset points'
,horizontalalignment='center')
fig.suptitle('{0}#{1}'.format(dur,key)+' Summary', va = 'top', ha= 'center') #size = 'small')
props = dict(boxstyle='square', facecolor='white', alpha=0.5)
fig.text(0.85, 0.925, dt.date.today().strftime("%b %d, %Y"), fontsize=9, verticalalignment='top', bbox=props)
fig.text(0.15, 0.925, 'No. of stuff'+ str(len(value['column'].unique())),fontsize = 10, va = 'top', ha = 'center')
plt.savefig("path/{0}/{1} # {2}.pdf".format(dur,dur,key), bbox_inches = 'tight');
plt.clf()
plt.close('all')
Excuse the black marks, didn't want to show the info

How to make a bar chart with only a height indicator not showing the full bar?

This chart almost looks good but is probably not the way to model this in matplotlib. How to have two horizontal bars that extend to the left and right of vertical line at an x-point to show the change of the two datasets eg SDR from 0.7 to 0.25.
Currently i patch things together with '$-$' markers which make misaligned legends and i am not able to place properly. If i change the figsize the markers start misaligning from the vertical bar at their x-point, eg SDR.
How to model this kind of chart proberly?
layer0 = np.random.random(10)
fig, ax = plt.subplots(1,1, figsize=(15/2,1.5*2.5),)
ind = np.arange(10, dtype=np.float64)*1#cordx
ax.plot(ind[0::2]+0.05, layer0[0::2]-0.04, ls='None', marker='$-$', markersize=40)
ax.plot(ind[1::2]-0.15, layer0[1::2]-0.04, ls='None', marker='$-$', markersize=40)
ax.set_ylim(0,1.05)
ax.set_yticks(np.arange(0, 1.1, step=0.1))
ax.set_xticks(ind[0::2]+0.5)
ax.set_xticklabels( ('SDR', 'SSR', 'SCR', 'RCR', 'GUR') )
plt.grid(b=True)
plt.grid(color='black', which='major', axis='y', linestyle='--', lw=0.2)
plt.show()
Alternatively, you can use a horizontal bar chart barh which is more intuitive in this case. Here the key parameter is left which will shift your horizontal bar charts to left/right.
Following is a complete answer:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2)
layer0 = np.random.random(10)
fig, ax = plt.subplots(1,1, figsize=(15/2,1.5*2.5),)
n = 10
width = 0.5
ind = np.arange(n, dtype=np.float64)*1#cordx
ax.barh(layer0[0::2], [width]*int(n/2), height=0.01, left = ind[0::2])
ax.barh(layer0[1::2], [width]*int(n/2), height=0.01, left = ind[0::2]+width)
ax.set_ylim(0,1.05)
ax.set_yticks(np.arange(0, 1.1, step=0.1))
ax.set_xticks(ind[0::2]+0.5)
ax.set_xticklabels( ('SDR', 'SSR', 'SCR', 'RCR', 'GUR') )
plt.grid(b=True)
plt.grid(color='black', which='major', axis='y', linestyle='--', lw=0.2)
plt.show()
up until now i havent thought of bar charts with bottom offset, which seems to be ok:
layer0 = np.random.random(10)
fig, ax = plt.subplots(1,1, figsize=(15/1.3,1.5*2.5),)# sharey=True)
ind = np.arange(10, dtype=np.float64)*1#cordx
height=0.03
width=0.8
ax.bar(ind[0::2]-width/2, height, width=width, bottom=layer0[0::2]-height)
ax.bar(ind[0::2]+width/2, height, width=width, bottom=layer0[1::2]-height)
ax.set_ylim(-0.,1.05)
plt.grid(color='black', which='major', axis='x', linestyle='-', lw=0.8)

Make patches bigger used as legend inside matplotlib

I am adding patches in a plot inside matplotlib using from matplotlib.patches import Patch class. Please see the sample code below-
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
n = 5
hatch_1 = 'o'
hatch_2 = '.'
opacity = 0.4
bar_width = 0.4
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
bars = plt.bar(x, y, bar_width, align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_1)
y = np.random.randint(low=0, high=10, size=n)
bars = plt.bar(x + bar_width, y, bar_width,
align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_2)
patch_1 = Patch(fill=False, label='Hatch 1', hatch=hatch_1, alpha=opacity)
patch_2 = Patch(fill=False, label='Hatch 2', hatch=hatch_2, alpha=opacity)
# add legends
plt.legend(handles=[patch_1, patch_2], loc='upper right')
plt.show()
Below is the generated plot-
The hatches used for legends aren't visisble properly. I guess if I make the patches bigger, it will be visible.
How to make patches bigger?
You can change the size of the legend patches in a couple of ways.
First, you can increase the width using the handlelength option to plt.legend.
However, there is no way to increase their height using kwargs. So we need to loop over the patches after creating the legend. If we keep a reference to the legend as we create it leg = plt.legend(...), then we can loop over the patches using for patch in leg.get_patches():.
Then you can change the height of the patch using patch.set_height().
However, all this tinkering means they won't be aligned quite right. So we also need to change their vertical position slightly (using patch.set_y()).
I also found it helped to increase the vertical spacing of the labels in the legend to fit things in nicely (use the labelspacing kwarg).
And finally, I added a new line at the beginning of the legend labels to make it all look nice (label='\nHatch 1').
A complete script is below. You may wish to play around with the values of labelspacing, handlelength, patch.set_height() and patch.set_y() to suit your needs.
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
n = 5
hatch_1 = 'o'
hatch_2 = '.'
opacity = 0.4
bar_width = 0.4
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
bars = plt.bar(x, y, bar_width, align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_1)
y = np.random.randint(low=0, high=10, size=n)
bars = plt.bar(x + bar_width, y, bar_width,
align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_2)
patch_1 = Patch(fill=False, label='\nHatch 1', hatch=hatch_1, alpha=opacity)
patch_2 = Patch(fill=False, label='\nHatch 2', hatch=hatch_2, alpha=opacity)
# add legends
leg = plt.legend(handles=[patch_1, patch_2], loc='upper right', labelspacing=1.5, handlelength=4)
for patch in leg.get_patches():
patch.set_height(22)
patch.set_y(-6)
plt.show()
As of 3.5.0 (and maybe earlier), handleheight and handlelength are now options to plt.legend(). Using your code but replacing the call to plt.legend() with
plt.legend(handles=[patch_1, patch_2], loc='upper right', handleheight=3, handlelength=4)
gives the following:
n = 5
hatch_1 = 'O'
hatch_2 = '.'
opacity = 0.4
bar_width = 0.4
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
bars = plt.bar(x, y, bar_width, align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_1)
y = np.random.randint(low=0, high=10, size=n)
bars = plt.bar(x + bar_width, y, bar_width,
align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_2)
patch_1 = Patch(fill=False, label='Hatch 1', hatch=hatch_1, alpha=opacity)
patch_2 = Patch(fill=False, label='Hatch 2', hatch=hatch_2, alpha=opacity)
plt.rcParams['figure.figsize'] = (25,15)
# add legends
plt.legend(handles=[patch_1, patch_2], loc='upper right')
plt.show()
Made your small o as O and increase the size of figure that will make sense i guess
While #tmdavison's solution works great, it is a bit involved.
Since the main issue here is that hatches are not easy to recognize in legends, a less ideal but much simpler workaround is to increase the hatch density, which is achieved simply by repeating the desired hatch character, ie, replacing o with ooo:
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
n = 5
hatch_1 = 'o'
hatch_2 = 'ooo'
opacity = 0.4
bar_width = 0.4
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
bars = plt.bar(x, y, bar_width, align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_1)
y = np.random.randint(low=0, high=10, size=n)
bars = plt.bar(x + bar_width, y, bar_width,
align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_2)
patch_1 = Patch(fill=False, label='Hatch 1', hatch=hatch_1, alpha=opacity)
patch_2 = Patch(fill=False, label='Hatch 2', hatch=hatch_2, alpha=opacity)
# add legends
plt.legend(handles=[patch_1, patch_2], loc='upper right')
plt.show()
The easiest way offered by matplotlib in my opinion is to define the properties of the legend using prop size to increase/decrease the legend size. You just need to do the following where you can choose the 'size' as preferred.
plt.legend(handles=[patch_1, patch_2], loc='best', prop={'size': 24})

figtext datetime function matplotlib

I am trying to create a text box within my graph in matplotlib where it gives me the date in which the graph was created.
I have created a text box in the bottom right corner of my graph using the figtext function in matplotlib, but cannot figure out how to incorporate the python datetime function within the text box so it displays the date. Any ideas?
Code and graph below:
#Stacked Bar Char- matplotlib
#Create the general blog and the "subplots" i.e. the bars
f, ax1 = plt.subplots(1, figsize=(8,5), dpi=1000)
# Set the bar width
bar_width = 0.50
# positions of the left bar-boundaries
bar_l = [i+1 for i in range(len(df4['Pandas']))]
# positions of the x-axis ticks (center of the bars as bar labels)
tick_pos = [i+(bar_width/2) for i in bar_l]
#Stack the negative bars by region
#Start bottom at 0, and then use pandas to add bars together
ax1.bar(bar_l, df4['cats1'], width=bar_width, label='cats',color='R', alpha=.4, align='center',
bottom = 0)
ax1.bar(bar_l, df4['dogs1'], width=bar_width,label='dogs',color='#ADD8E6',alpha=.4, fill=True, align='center',
bottom =(df4['cats1']))
ax1.bar(bar_l, df4['zebras1'], width=bar_width, label='zebras',color='#FFA500',alpha=.4, align='center',
bottom = np.array(df4['cats1'])+np.array(df4['dogs1']))
ax1.bar(bar_l, df4['pandas1'], width=bar_width, label='pandas', color='b',alpha=.5, fill=True, align='center',
bottom = np.array(df4['cats1'])+np.array(df4['dogs1'])+np.array(df4['zebras1']))
#Stack the positive bars by region
#Start bottom at 0, and then use pandas to add bars together
ax1.bar(bar_l, df4['cats'], width=bar_width,color='R', alpha=.4, align='center',
bottom = 0)
ax1.bar(bar_l, df4['dogs'], width=bar_width,color='#ADD8E6',alpha=.4, fill=True, align='center',
bottom =(df4['cats']))
ax1.bar(bar_l, df4['zebras'], width=bar_width ,color='#FFA500',alpha=.4, align='center',
bottom = np.array(df4['cats'])+np.array(df4['dogs']))
ax1.bar(bar_l, df4['pandas'], width=bar_width, color='b',alpha=.5, fill=True, align='center',
bottom = np.array(df4['cats'])+np.array(df4['dogs'])+np.array(df4['zebras']))
# set the x ticks with names
plt.xticks(tick_pos, df4['Year'],fontsize=10)
# Set the label and legends
plt.title('Animals on the farm', fontweight='bold')
ax1.set_ylim([-1600,1000])
ax1.set_ylabel("Count",fontsize=12)
ax1.set_xlabel("Year",fontsize=12)
plt.legend(loc='upper left', prop={'size':6})
ax1.axhline(y=0, color='k')
ax1.axvline(x=0, color='k')
plt.figtext(0, 0,"Data as of ", wrap=False,
horizontalalignment='left',verticalalignment ='bottom', fontsize=8)
plt.setp(ax1.get_yticklabels(), rotation='horizontal', fontsize=10)
plt.show()
Graph= Animals on the Farm
Here's an example with today's date:
import datetime as dt
plt.figtext(0, 0,"Data as of {}".format(dt.date.today().strftime('%Y-%m-%d')), wrap=False,
horizontalalignment='left',verticalalignment ='bottom', fontsize=8)
If you have a datetime object, you can use the strftime method to convert it to a string representation using the formatting you want:
from datetime import datetime
plt.figtext(0, 0, 'Date as of ' + datetime.now().strftime('%Y-%m-%d'))

Average line for bar chart in matplotlib

How do we draw an average line (horizontal) for a histogram in using matplotlib?
Right now, I'm able to draw the histogram without any issues.
Here is the code I'm using:
## necessary variables
ind = np.arange(N) # the x locations for the groups
width = 0.2 # the width of the bars
plt.tick_params(axis='both', which='major', labelsize=30)
plt.tick_params(axis='both', which='minor', labelsize=30)
ax2 = ax.twinx()
## the bars
rects1 = ax.bar(ind, PAAE1, width,
color='0.2',
error_kw=dict(elinewidth=2,ecolor='red'),
label='PAAE1')
rects2 = ax.bar(ind+width, PAAE2, width,
color='0.3',
error_kw=dict(elinewidth=2,ecolor='black'),
label='PAAE2')
rects3 = ax2.bar(ind+width+width, AAE1, width,
color='0.4',
error_kw=dict(elinewidth=2,ecolor='red'),
label='AAE1')
rects4 = ax2.bar(ind+3*width, AAE2, width,
color='0.5',
error_kw=dict(elinewidth=2,ecolor='black'),
label='AAE3')
maxi = max(dataset[2])
maxi1 = max(dataset[4])
f_max = max(maxi, maxi1)
lns = [rects1,rects2,rects3,rects4]
labs = [l.get_label() for l in lns]
ax.legend(lns, labs, loc='upper center', ncol=4)
# axes and labels
ax.set_xlim(-width,len(ind)+width)
ax.set_ylim(0, 100)
ax.set_ylabel('PAAE', fontsize=25)
ax2.set_ylim(0, f_max+500)
ax2.set_ylabel('AAE (mW)', fontsize=25)
xTickMarks = dataset[0]
ax.set_xticks(ind+width)
xtickNames = ax.set_xticklabels(xTickMarks)
plt.setp(xtickNames, rotation=90, fontsize=25)
I want to plot the average line for PAAE 1, 2 and AAE 1, 2.
What should I be using to plot the average line?
If you'd like a vertical line to denote the mean use axvline(x_value). This will place a vertical line that always spans the full (or specified fraction of) y-axis. There's also axhline for horizontal lines.
In other works, you might have something like this:
ax.axvline(data1.mean(), color='blue', linewidth=2)
ax.axvline(data2.mean(), color='green', linewidth=2)
As a more complete, but unnecessarily complex example (most of this is nicely annotating the means with curved arrows):
import numpy as np
import matplotlib.pyplot as plt
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(-2, 1.5, 1000)
fig, ax = plt.subplots()
bins = np.linspace(-10, 5, 50)
ax.hist(data1, bins=bins, color='blue', label='Dataset 1',
alpha=0.5, histtype='stepfilled')
ax.hist(data2, bins=bins, color='green', label='Dataset 2',
alpha=0.5, histtype='stepfilled')
ax.axvline(data1.mean(), color='blue', linewidth=2)
ax.axvline(data2.mean(), color='green', linewidth=2)
# Add arrows annotating the means:
for dat, xoff in zip([data1, data2], [15, -15]):
x0 = dat.mean()
align = 'left' if xoff > 0 else 'right'
ax.annotate('Mean: {:0.2f}'.format(x0), xy=(x0, 1), xytext=(xoff, 15),
xycoords=('data', 'axes fraction'), textcoords='offset points',
horizontalalignment=align, verticalalignment='center',
arrowprops=dict(arrowstyle='-|>', fc='black', shrinkA=0, shrinkB=0,
connectionstyle='angle,angleA=0,angleB=90,rad=10'),
)
ax.legend(loc='upper left')
ax.margins(0.05)
plt.show()

Categories