Reputation: 45
I want the axis ticks to start and end where the axis starts and ends
I have multiple columns which needs to be plotted at once. In the for loop I cannot define the y ticks for each and every column because they have different range of values. I want a code that does the axis setting as shown in the picture for every column's plot
This is the snippet of the code that I am using
import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import openpyxl
import os
from PIL import Image
import io
x = np.random.randint( 10, 100, size = (50, 4) )
y = np.random.randint( 1, 20, size = (50, 4) )
z = np.concatenate((x,y), axis = 1)
df = pd.DataFrame( z, columns=list('ABCDEFGH') )
columns=list('ABCDEFGH')
cat = ['Cat1','Cat2','Cat3']
cat_list = random.choices(cat,k = 50)
df["Cat"] = cat_list
barWidth = 0.25
# loop over multiple colums to plot as bar graph
for i in columns[0:6]:
print(i)
# The bars classidied according to
bars0 = [ df[df['Cat'] == 'Cat1' ][i].mean(),
df[df['Cat'] == 'Cat1' ][i].mean(),
df[ df['Cat'] == 'Cat1' ][i].mean(),
df[ df['Cat'] == 'Cat1' ][i].mean(),
df[ df['Cat'] == 'Cat1' ][i].mean(),
df[ df['Cat'] == 'Cat1' ][i].mean() ]
# bars 0 represents all the Cat 1 participants
yerr0 = [
df[df['Cat'] == 'Cat1' ][i].std(),
df[df['Cat'] == 'Cat1' ][i].std(),
df[ df['Cat'] == 'Cat1' ][i].std(),
df[ df['Cat'] == 'Cat1' ][i].std(),
df[ df['Cat'] == 'Cat1' ][i].std(),
df[ df['Cat'] == 'Cat1' ][i].std() ]
bars1 = [ df[df['Cat'] == 'Cat2' ][i].mean(),
df[df['Cat'] == 'Cat2' ][i].mean(),
df[ df['Cat'] == 'Cat2' ][i].mean(),
df[ df['Cat'] == 'Cat2' ][i].mean(),
df[ df['Cat'] == 'Cat2' ][i].mean(),
df[ df['Cat'] == 'Cat2' ][i].mean() ]
# bars 1 represents all the Cat 2 participants
yerr1 = [
df[df['Cat'] == 'Cat2' ][i].std(),
df[df['Cat'] == 'Cat2' ][i].std(),
df[ df['Cat'] == 'Cat2' ][i].std(),
df[ df['Cat'] == 'Cat2' ][i].std(),
df[ df['Cat'] == 'Cat2' ][i].std(),
df[ df['Cat'] == 'Cat2' ][i].std() ]
bars8 = [ df[df['Cat'] == 'Cat3' ][i].mean(),
df[df['Cat'] == 'Cat3' ][i].mean(),
df[ df['Cat'] == 'Cat3' ][i].mean(),
df[ df['Cat'] == 'Cat3' ][i].mean(),
df[ df['Cat'] == 'Cat3' ][i].mean(),
df[ df['Cat'] == 'Cat1' ][i].mean()]
# bars 8 represents all the Cat 3 participants
yerr8 = [
df[df['Cat'] == 'Cat3' ][i].std(),
df[df['Cat'] == 'Cat3' ][i].std(),
df[ df['Cat'] == 'Cat3' ][i].std(),
df[ df['Cat'] == 'Cat3' ][i].std(),
df[ df['Cat'] == 'Cat3' ][i].std(),
df[ df['Cat'] == 'Cat3' ][i].std() ]
# standard deciation for the y error bar
r1 = np.arange(len(bars1))
r2 = [x + barWidth for x in r1]
r3 = [x + barWidth for x in r2]
fig, ax = plt.subplots()
right_side = ax.spines["right"]
right_side.set_visible(False)
top_side = ax.spines["top"]
top_side.set_visible(False)
# Cat1
plt.bar(r1 ,bars0,color='r', width=barWidth, edgecolor='white',
label='Cat1',yerr=yerr0)
# Cat2
plt.bar(r2,bars1,color='g', width=barWidth, edgecolor='white',
label='Cat2', yerr=yerr1)
# Cat3
plt.bar(r3,bars8, color='b', width=barWidth,
edgecolor='white', label='Cat3', yerr=yerr8)
plt.xlabel('columns', fontdict={'fontname': 'Arial', 'fontsize': 16,'fontweight':'bold'})
plt.ylabel('AVG '+ columns[columns.index(i)] ,fontdict={'fontname': 'Arial', 'fontsize': 16})
plt.title(columns[columns.index(i)] ,fontdict={'fontname': 'Arial', 'fontsize': 24})
plt.xticks([r + barWidth for r in range(len(bars1))],
[ 'A', 'B',
'C', 'D', 'E', 'F'],fontsize=12)
When I individually define the plt.yticks() I am able to achieve the graph on the right. I am unable to figure out how to do it in a loop
Upvotes: 1
Views: 1093
Reputation: 6642
Just add plt.ylim(top=plt.yticks()[0][-1])
at the end of your loop. This exploits the fact that the automatically generated yticks also contain the next-higher tick, even though it's not visible. For example,
print(plt.ylim())
print(plt.yticks()[0])
inside your loop gives
(0.0, 16.5362767162174)
[ 0. 2. 4. 6. 8. 10. 12. 14. 16. 18.]
So even though the y-axis goes to 16.53..., the maximum ytick (not visible, outside the axis) is already present. So all we have to do is to set the top of ylim to this maximum value to extend the y-axis just a little bit.
Of course this results in a slight extension of the axis, so it might be a bit to long for the data in the plot. But based on the example it looks ok. It also corresponds to what you show in your question. Also, to make this more optimal one would need to put in a lot more effort in terms of recreating the automatic yticks, which is probably not worth it.
Upvotes: 1