Python Matplotlib绘制柱状图(bar和barh函数)详解

广告位

使用 Matplotlib 提供的 bar() 函数来绘制柱状图。与前面介绍的 plot() 函数类似,程序每…

使用 Matplotlib 提供的 bar() 函数来绘制柱状图。与前面介绍的 plot() 函数类似,程序每次调用 bar() 函数时都会生成一组柱状图, 如果希望生成多组柱状图,则可通过多次调用 bar() 函数来实现。

下面程序使用柱状图来展示《C语言基础》和《Java基础》两套教程历年的销量数据。

  import matplotlib.pyplot as plt  import numpy as np    # 构建数据  x_data = ['2012', '2013', '2014', '2015', '2016', '2017', '2018']  y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]  y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]  # 绘图  plt.bar(x=x_data, height=y_data, label='C语言基础', color='steelblue', alpha=0.8)  plt.bar(x=x_data, height=y_data2, label='Java基础', color='indianred', alpha=0.8)  # 在柱状图上显示具体数值, ha参数控制水平对齐方式, va控制垂直对齐方式  for x, y in enumerate(y_data):      plt.text(x, y + 100, '%s' % y, ha='center', va='bottom')  for x, y in enumerate(y_data2):      plt.text(x, y + 100, '%s' % y, ha='center', va='top')  # 设置标题  plt.title("Java与Android图书对比")  # 为两条坐标轴设置名称  plt.xlabel("年份")  plt.ylabel("销量")  # 显示图例  plt.legend()  plt.show()

上面程序中,第 9、10 两行代码用于在数据图上生成两组柱状图,程序设置了这两组柱状图的颜色和透明度。

在使用 bar() 函数绘制柱状图时,默认不会在柱状图上显示具体的数值。为了能在柱状图上显示具体的数值,程序可以调用 text() 函数在数据图上输出文字,如上面程序中第 10 行代码所示。

在使用 text() 函数输出文字时,该函数的前两个参数控制输出文字的 X、Y 坐标,第三个参数则控制输出的内容。其中 va 参数控制文字的垂直对齐方式,ha 参数控制文字的水平对齐方式。

对于上面的程序来说,由于 X 轴数据是一个字符串列表,因此 X 轴实际上是以列表元素的索引作为刻度值的。因此,当程序指定输出文字的 X 坐标为 0 时,表明将该文字输出到第一个条柱处;对于 Y 坐标而言,条柱的数值正好在条柱高度所在处,如果指定 Y 坐标为条柱的数值 +100,就是控制将文字输出到条柱略上一点的位置。

运行上面程序,可以看到如图 1 所示的效果。

Python Matplotlib绘制柱状图(bar和barh函数)详解
图 1 两组柱状图

从图 1 所示的显示效果来看,第二次绘制的性状图完全与第一次绘制的柱状图重叠,这并不是我们期望的结果,我们希望每组数据的条柱能并列显示。

为了实现条柱井列显示的效果,首先分析条柱重叠在一起的原因。使用 Matplotlib 绘制柱状图时同样也需要 X 轴数据,本程序的 X 轴数据是元素为字符串的 list 列表,因此程序实际上使用各字符串的索引作为 X 轴数据。比如 '2011' 字符串位于列表的第一个位置,因此代表该条柱的数据就被绘制在 X 轴的刻度值1处(由于两个柱状图使用了相同的 X 轴数据,因此它们的条柱完全重合在一起)。

为了将多个柱状图的条柱并列显示,程序需要为这些柱状图重新计算不同的 X 轴数据。为了精确控制条柱的宽度,程序可以在调用 bar() 函数时传入 width 参数,这样可以更好地计算条柱的并列方式。将上面程序改为如下形式:

  import matplotlib.pyplot as plt  import numpy as np    # 构建数据  x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']  y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]  y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]  bar_width=0.3  # 将X轴数据改为使用range(len(x_data), 就是0、1、2...  plt.bar(x=range(len(x_data)), height=y_data, label='C语言基础',      color='steelblue', alpha=0.8, width=bar_width)  # 将X轴数据改为使用np.arange(len(x_data))+bar_width,  # 就是bar_width、1+bar_width、2+bar_width...这样就和第一个柱状图并列了  plt.bar(x=np.arange(len(x_data))+bar_width, height=y_data2,      label='Java基础', color='indianred', alpha=0.8, width=bar_width)  # 在柱状图上显示具体数值, ha参数控制水平对齐方式, va控制垂直对齐方式  for x, y in enumerate(y_data):      plt.text(x, y + 100, '%s' % y, ha='center', va='bottom')  for x, y in enumerate(y_data2):      plt.text(x+bar_width, y + 100, '%s' % y, ha='center', va='top')  # 设置标题  plt.title("C与Java对比")  # 为两条坐标轴设置名称  plt.xlabel("年份")  plt.ylabel("销量")  # 显示图例  plt.legend()  plt.show()

该程序与前一个程序的区别就在于第 10、14 两行代码,这两行代码使用了不同的 x 参数,其中第一个柱状图的 X 轴数据为 range(len(x_data)),也就是 0、1、2…,这样第一个柱状图的各条柱恰好位于 0、1、2… 刻度值处;第二个柱状图的 X 轴数据为 np.arange(len(x_data))+bar_width,也就是 bar_width、1+bar_width、2+bar_width···,这样第二个柱状图的各条柱位于 0、1、2…刻度值的偏右一点 bar_width 处,这样就恰好与第一个柱状图的各条柱并列了。

运行上面程序,将会发现该柱状图的 X 轴的刻度值变成 0、1、2 等值,不再显示年份。为了让柱状图的 X 轴的刻度值显示年份,程序可以调用 xticks() 函数重新设置 X 轴的刻度值。

例如,在程序中添加如下代码:

# 为X轴设置刻度值
plt.xticks(np.arange(len(x_data))+bar_width/2, x_data)

上面代码使用 x_data 为 X 轴设置刻度值,第一个参数用于控制各刻度值的位置,该参数是 np.arange(len(x_data))+bar_width/2,也就是 bar_width/2、1+bar_width/2、2+bar_width/2 等,这样这些刻度值将被恰好添加在两个条柱之间。

运行上面程序可看到如图 2 所示的运行结果:

Python Matplotlib绘制柱状图(bar和barh函数)详解
图 2 并列的柱状图

有些时候,可能希望两个条柱之间有一点缝隙,那么程序只要对第二个条柱的 X 轴数据略做修改即可。例如,将上面程序中第 14 行代码改为如下形式:

plt.bar(x=np.arange(len(x_data))+bar_width+0.05, height=y_data2,
    label='Java基础', color='indianred', alpha=0.8, width=bar_width)

上面代码重新计算了 X 轴数据,使用 np.arange(len(x_data))+bar_width+0.05 作为 X 轴数据,因此两组柱状图的条柱之间会有 0.05 的距离。

Matplotlib 绘制水平柱状图

调用 Matplotlib 的 barh() 函数可以生成水平柱状图。barh() 函数的用法与 bar() 函数的用法基本一样,只是在调用 barh() 函数时使用 y参数传入 Y 轴数据,使用 width 参数传入代表条柱宽度的数据。

例如,如下程序调用 barh() 函数生成两组并列的水平柱状图,来展示两套教程历年的销量统计数据:

  import matplotlib.pyplot as plt  import numpy as np    # 构建数据  x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']  y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]  y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]  bar_width=0.3  # Y轴数据使用range(len(x_data), 就是0、1、2...  plt.barh(y=range(len(x_data)), width=y_data, label='Java基础教程',      color='steelblue', alpha=0.8, height=bar_width)  # Y轴数据使用np.arange(len(x_data))+bar_width,  # 就是bar_width、1+bar_width、2+bar_width...这样就和第一个柱状图并列了  plt.barh(y=np.arange(len(x_data))+bar_width, width=y_data2,      label='C语言基础', color='indianred', alpha=0.8, height=bar_width)    # 在柱状图上显示具体数值, ha参数控制水平对齐方式, va控制垂直对齐方式  for y, x in enumerate(y_data):      plt.text(x+5000, y-bar_width/2, '%s' % x, ha='center', va='bottom')  for y, x in enumerate(y_data2):      plt.text(x+5000, y+bar_width/2, '%s' % x, ha='center', va='bottom')  # 为Y轴设置刻度值  plt.yticks(np.arange(len(x_data))+bar_width/2, x_data)  # 设置标题  plt.title("Java与C对比")  # 为两条坐标轴设置名称  plt.xlabel("销量")  plt.ylabel("年份")  # 显示图例  plt.legend()  plt.show()

上面程序中,第 10 行代码使用 barh() 函数来创建水平柱状图,其中 y 参数为 range(len(x_data)),这意味着这些条柱将会沿着 Y 轴均匀分布;而 width 参数为 y_data,这意味着 y_data 列表所包含的数值会决定各条柱的宽度。第 14 行代码的控制方式与此类似。

运行上面程序,可以看到如图 3 所示的效果。

Python Matplotlib绘制柱状图(bar和barh函数)详解
图 3 水平柱状图

关于作者: Python基础入门教程

为您推荐

广告位

发表评论