我需要绘制每所学校的年级和学期的条形图,并且需要对60所学校进行绘制。但是由于有些学校的成绩比其他学校高,所以即使我用相同的图形尺寸制作了图表,它们看起来也好像尺寸不同
下面的两个学校就是一个例子,一个学校有10个年级,另一个学校有11个年级,因此底部的图看起来比顶部的图大。
[
我的理想结果是:
[
垃圾箱宽度是否受影响都没有关系。我只希望这组图具有相同的边距。
下面是我的代码(我注释了每个步骤,以便您可以跳过不相关的行):
def plot_stacked(df, **kwargs):
n_ind = len(df.index)
figsize = (20.82, 10.57) # image oupput size in unit of 100 px, eg. 20.82 will output 2082px
img_width = 2082 # just for leftside and rightside variable caculation
bar_width = 120
fig = plt.figure(figsize=figsize)
axe = fig.add_subplot(111)
"""set color for different bars"""
# color_set = ['#b9d3f1', '#6da9dc', '#e5e5e5', '#BABABA']
color_set = ['#b9d3f1', '#6da9dc', '#e5e5e5', '#cccccc']
#set defaults for size and font
# infoFont = r"C:\Windows\Fonts\calibri.ttf"
Fontsize = 40
fontfamily = 'Arial'
fontcolor = '#4d4d4d' # dark grey
color_text = '#58585a' #(88, 88, 90) Hex code: 58585a OLD Hex code: 4A4646
colorBackground = 'white'
axe = df.plot(kind="bar",
figsize=figsize,
linewidth= 0,
stacked=True,
color= color_set,
legend=False,
grid=False,
ax=axe,
# width= bar_width/180.0,
**kwargs) # make bar plots
"""loop through to get total value of proficient and advanced percentage in CORRECT order"""
internal_counter= -0.2 # set as X position of annotate numbers
for index, row in df.iterrows():
value_list = df.loc[index].tolist()
# print value_list
if len(value_list):
if value_list[1] > 10:
axe.annotate(str(value_list[1]), xy = (internal_counter, value_list[1]/2 + value_list[0] - 4), fontsize=bar_width/3.5, family=fontfamily, color=fontcolor) # top
if value_list[0] > 10:
axe.annotate(str(value_list[0]), xy = (internal_counter, value_list[0]/2.8), fontsize=bar_width/3.5, family=fontfamily, color=fontcolor) #3rd
if abs(value_list[2]) > 10:
axe.annotate(str(value_list[2] * (-1)), xy = (internal_counter, value_list[2]/2 - 4), fontsize=bar_width/3.5, family=fontfamily, color=fontcolor) # 2nd
if abs(value_list[3]) > 10:
axe.annotate(str(value_list[3] * (-1)), xy = (internal_counter, value_list[2] + value_list[3]/2 - 4), fontsize=bar_width/3.5, family=fontfamily, color=fontcolor) # bottom
internal_counter += 1
"""rotate x-axix value, and set position""" #grades
old_index_values = df.index.values
new_index_values = map(lambda s: s.strip(), old_index_values) # Manuuly modify x axis text to make it center
axe.set_xticklabels(new_index_values, y=0, rotation = 0, ha='center', multialignment= 'center', family=fontfamily, fontsize=bar_width/3.5, color=fontcolor)
"""set top, left and right frame invisible"""
axe.spines['left'].set_visible(False)
axe.spines['right'].set_visible(False)
axe.spines['top'].set_visible(False)
axe.spines['bottom'].set_visible(False)
axe.yaxis.set_visible(False)
axe.xaxis.set_visible(True)
"""remove the small tick lines"""
for tic in axe.xaxis.get_major_ticks():
tic.tick1On = tic.tick2On = False
"""set background color"""
axe.set_axis_bgcolor(colorBackground)
"""set distance between text and axis"""
axe.tick_params(axis='x', which='major', pad=10)
"""set x axis text align position"""
# leftside = (-1)*(img_width*5.0/((n_col+1)*bar_width)-n_ind/2.0) # get left side value by variables. Constants are ARBETRARY.
# rightside = (-1)*leftside + n_ind - 0.8
# leftside = (-100)*(img_width/((n_ind+1)*(n_ind+1)*bar_width))
leftside = (-0.0075)*(img_width-(n_ind*190)-50)/2 -n_ind*0.15
rightside = (-1)*leftside + n_ind - 1
axe.set_xlim([leftside, rightside])
axe.set_ylim(-90,100)
"""add horizontal line at y=0"""
plt.axhline(y=0, color=fontcolor)
fig.tight_layout()
return axe
def graph_output_subtest(output_path, meta, df):
"""
get new_dataframe with final cleaned data
print out graph to output_path
resource: http://pandas.pydata.org/pandas-docs/version/0.18.1/visualization.html
"""
print '*'*10, 'Graphs for ', meta, '*'*10
graph = plot_stacked(df)
# graph.set_ylim(-105,1)
fig = graph.get_figure()
fig.savefig(output_path+"\\MAP R "+meta+".png")
plt.close(fig)
# Possible formats: eps, jpeg, jpg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
ef graph_output(Region_ID):
"""
Print graphs of all subtest for region
"""
raw_data = get_region_lvl_MAP(Region_ID) # get raw school level data
# print raw_data
"""get region name for file name"""
region_name = list(set(raw_data['Region_Name'][raw_data['Region_ID'] == Region_ID].tolist()))
if len(region_name) != 1:
print 'More than one name or no name found for school id:', Region_ID
else:
region_name = region_name[0]#.replace(' ', '_')
"""get subtest list"""
# subtest_id_list = list(set(raw_data['Sub_Test_ID'][raw_data['Region_ID'] == Region_ID].tolist()))
subtest_name_list = ['Math', 'Reading']
"""loop through subtest ids"""
for subtest in subtest_name_list:
"""get real subtest name for file name printing"""
# if subtest == 753: subtest_name = 'Reading'
# elif subtest ==725 : subtest_name = 'Math'
# else: subtest_name = 'Unknown'
subtest_name = subtest
meta = str(Region_ID) + ' ' + str(region_name) + ' ' + str(subtest_name) # for file name's purpose
# print 'subtest id:', subtest
df = format_data(raw_data, subtest) # get sub-dataframe for different levels with specific subtest type
if not df.empty:
graph_output_subtest(output_path, meta, df) # print and save graphs
for region in region_list:
graph_output(region)
和 region 是这样的df:
任何建议都会有所帮助,在此先感谢!
答案 0 :(得分:0)
由于您使用的是matplotlib,您是否尝试了以下方法?
plt.rcParams["figure.figsize"] = [16,9]
这在您定义时有效:
import matplotlib.pyplot as plt
另一方面,一些技巧:
同时使用这两种方法,您将获得更好,更快的答案;)
答案 1 :(得分:0)
使用以下代码,我能够重现您的错误。
import pandas as pd
import matplotlib.pyplot as plt
for k in range(8,10):
lablist=[j for j in range(k)]
vallist=[j for j in range(k)]
df = pd.DataFrame({'lab':lablist, 'val':vallist})
img_width=1540
n_ind=len(vallist)
leftside = (-0.0075)*(img_width-(n_ind*190)-50)/2 -n_ind*0.15
rightside = (-1)*leftside + n_ind - 1
ax = df.plot.bar(x='lab', y='val', rot=0,figsize=(10,5))
ax.set_xlim([leftside, rightside])
当条形数量更改您要添加的空白不一致时,错误发生在leftside
和rightside
计算中。通过获取x轴的最小值和最大值并添加一个恒定的间隙,您可以对齐图的所有条形图
for k in range(8,10):
lablist=[j for j in range(k)]
vallist=[j for j in range(k)]
df = pd.DataFrame({'lab':lablist, 'val':vallist})
leftside = df['lab'].min()-0.75
rightside = df['lab'].max()+0.75
ax = df.plot.bar(x='lab', y='val', rot=0,figsize=(10,5))
ax.set_xlim([leftside, rightside])
希望有帮助