7、matplotlib条形图的绘制

1、ax.bar()函数

条形图可以垂直或水平绘制。条形图显示离散类别之间的比较。图表的一根轴显示被比较的具体类别,另一根轴代表测量值。Matplotlib中,条形图用以下的函数来画:

ax.bar(x, height, width, bottom, align)

该函数制作了一个大小为(x -width=2;x+width=2;底;底+高)的约束矩形的条形图。
参数解释如下:

参数 解释
x x是 控制条形图的中心(默认)还是左边缘
height 标量或标量序列代表条形图的高度
width 标量或类数组,可选。条形图的宽度默认为0.8
bottom 标量或类数组,可选。条形图的Y坐标,默认为None
align {‘center’, ‘edge’}, 可选,默认’center’
tick_label 条形图的刻度标签。默认值。无 (使用默认的数字标签。)
更多参数 点击官方文档

2、绘制单个条形图

以下是Matplotlib条形图的一个简单例子。它显示了一个机构提供的各种课程的注册学生人数:

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
langs = ['数学', '英语', '物理', '化学', '生物']
students = [30,19,45,30,25]
ax.bar(langs,students)
plt.show()

显示结果如下:
在这里插入图片描述

3、绘制水平交错的条形图

有时候,我们还要给条形图增加图例,加入一些对比,并且还要给对比的使用不同的颜色,代码示例如下:

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号
data = [[30, 25, 50, 20],
[40, 23, 51, 17],
[35, 22, 45, 19]]
# x轴上坐标的个数,也是data列表里面的列表内的元素个数。4也可以用len(data[0])代替。
X = np.arange(4)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
'''
F1、F2、F3画柱状图,共三个,第一个参数可以认为是labels,第二个参数是各自的y坐标,如果我们想要
在某个柱状图下面设置x轴刻度值,就可以在该柱状图下面用tick_label设置。
'''
F1 = ax.bar(X + 0.00, data[0], color = 'b', width = 0.25)
F2 = ax.bar(X + 0.25, data[1], color = 'g', width = 0.25,tick_label=[2017,2018,2019,2020])
F3 = ax.bar(X + 0.50, data[2], color = 'r', width = 0.25)
# 给柱状图设置图例,第一个参数是个元组,元组中每个元素代表一个柱状图,第二个参数是对应着的图例的名字。
ax.legend((F1,F2,F3),('数学','英语','物理'))
plt.show()

显示结果如下:
在这里插入图片描述
上述代码注释有点儿多,请认真阅读。

4、多个条形图堆叠的绘制

代码与3中的大部分都一样,唯一改动的就是ax.bar中的第一个参数,讲水平位移的量给删除,就默认得到了数值方向上的堆叠,代码如下:

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号
data = [[30, 25, 50, 20],
[40, 23, 51, 17],
[35, 22, 45, 19]]
X = np.arange(len(data[0]))
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
# 唯一改动的就是ax.bar中的第一个参数。
F1 = ax.bar(X, data[0], color = 'b', width = 0.25)
F2 = ax.bar(X, data[1], color = 'g', width = 0.25,tick_label=[2017,2018,2019,2020])
F3 = ax.bar(X, data[2], color = 'r', width = 0.25)
ax.legend((F1,F2,F3),('数学','英语','物理'))
plt.show()

结果如下:
在这里插入图片描述
此外,还可以给柱状图添加一个误差条,如下代码:

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号
data = [[30, 25, 50, 20],
[40, 23, 51, 17],
[35, 22, 45, 19]]
F1_std = [2,3,4,1]
F2_std = [3,1,2,1]
F3_std = [3,1,2,1]
X = np.arange(len(data[0]))
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
# 唯一改动的就是ax.bar中的第一个参数。
F1 = ax.bar(X, data[0], color = 'b', width = 0.25,yerr=F1_std)
F2 = ax.bar(X, data[1], color = 'g', width = 0.25,
            yerr=F2_std,
            tick_label=[2017,2018,2019,2020])
F3 = ax.bar(X, data[2], color = 'r', width = 0.25,yerr=F3_std)
ax.legend((F1,F2,F3),('数学','英语','物理'))
plt.show()

上面的代码还可以写成:

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号
data = [[30, 25, 50, 20],
[40, 23, 51, 17],
[35, 22, 45, 19]]
X = ['2017','2018','2019','2020']
F1_std = [2,3,4,1]
F2_std = [3,1,2,1]
F3_std = [3,1,2,1]
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
# 参数X是x坐标轴上的标签值,label是为了显示图例的,是每个柱状图的标签。
ax.bar(X, data[0], color='b', width=0.25, label='数学', yerr=F1_std)
ax.bar(X, data[1], color='g', width=0.25, label='英语', yerr=F2_std)
ax.bar(X, data[2], color='r', width=0.25, label = '物理', yerr=F3_std)
ax.legend()
plt.show()

显示结果如下:
在这里插入图片描述

在举一个例子:

import numpy as np
import matplotlib.pyplot as plt


labels = ['G1', 'G2', 'G3', 'G4', 'G5']
men_means = [20, 35, 30, 35, 27]
women_means = [25, 32, 34, 20, 25]
men_std = [2, 3, 4, 1, 2]
women_std = [3, 5, 2, 3, 3]
width = 0.35       # the width of the bars: can also be len(x) sequence

fig, ax = plt.subplots()
# label = 'Men'显示在图例中,labels为x轴的。
ax.bar(labels, men_means, width, yerr=men_std, label='Men')
ax.bar(labels, women_means, width, yerr=women_std, bottom=men_means,
       label='Women')

ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.legend()

plt.show()

显示结果如下:
在这里插入图片描述
注意上述代码中的一些小变动,尤其注意上述代码中ax.bar()函数里面的参数所代表的含义。

5、条形图横向显示

此处放上一个官方的给的例子,涉及的知识点很多,耐心查看理解,直接上代码:

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
from collections import namedtuple

np.random.seed(42)

Student = namedtuple('Student', ['name', 'grade', 'gender'])
Score = namedtuple('Score', ['score', 'percentile'])

# GLOBAL CONSTANTS
test_names = ['Pacer Test', 'Flexed Arm\n Hang', 'Mile Run', 'Agility',
              'Push Ups']
test_meta = dict(zip(test_names, ['laps', 'sec', 'min:sec', 'sec', '']))


def attach_ordinal(num):
    """Convert an integer to an ordinal string, e.g. 2 -> '2nd'."""
    suffixes = {
    
    str(i): v
                for i, v in enumerate(['th', 'st', 'nd', 'rd', 'th',
                                       'th', 'th', 'th', 'th', 'th'])}

    v = str(num)
    # special case early teens
    if v in {
    
    '11', '12', '13'}:
        return v + 'th'
    return v + suffixes[v[-1]]


def format_score(scr, test):
    """
    Build up the score labels for the right Y-axis by first
    appending a carriage return to each string and then tacking on
    the appropriate meta information (i.e., 'laps' vs. 'seconds'). We
    want the labels centered on the ticks, so if there is no meta
    info (like for pushups) then don't add the carriage return to
    the string
    """
    md = test_meta[test]
    if md:
        return '{0}\n{1}'.format(scr, md)
    else:
        return scr


def format_ycursor(y):
    y = int(y)
    if y < 0 or y >= len(test_names):
        return ''
    else:
        return test_names[y]


def plot_student_results(student, scores, cohort_size):
    #  create the figure
    fig, ax1 = plt.subplots(figsize=(9, 7))
    fig.subplots_adjust(left=0.115, right=0.88)
    fig.canvas.set_window_title('Eldorado K-8 Fitness Chart')

    pos = np.arange(len(test_names))

    rects = ax1.barh(pos, [scores[k].percentile for k in test_names],
                     align='center',
                     height=0.5,
                     tick_label=test_names)

    ax1.set_title(student.name)

    ax1.set_xlim([0, 100])
    ax1.xaxis.set_major_locator(MaxNLocator(11))
    ax1.xaxis.grid(True, linestyle='--', which='major',
                   color='grey', alpha=.25)

    # Plot a solid vertical gridline to highlight the median position
    ax1.axvline(50, color='grey', alpha=0.25)

    # Set the right-hand Y-axis ticks and labels
    ax2 = ax1.twinx()

    scoreLabels = [format_score(scores[k].score, k) for k in test_names]

    # set the tick locations
    ax2.set_yticks(pos)
    # make sure that the limits are set equally on both yaxis so the
    # ticks line up
    ax2.set_ylim(ax1.get_ylim())

    # set the tick labels
    ax2.set_yticklabels(scoreLabels)

    ax2.set_ylabel('Test Scores')

    xlabel = ('Percentile Ranking Across {grade} Grade {gender}s\n'
              'Cohort Size: {cohort_size}')
    ax1.set_xlabel(xlabel.format(grade=attach_ordinal(student.grade),
                                 gender=student.gender.title(),
                                 cohort_size=cohort_size))

    rect_labels = []
    # Lastly, write in the ranking inside each bar to aid in interpretation
    for rect in rects:
        # Rectangle widths are already integer-valued but are floating
        # type, so it helps to remove the trailing decimal point and 0 by
        # converting width to int type
        width = int(rect.get_width())

        rankStr = attach_ordinal(width)
        # The bars aren't wide enough to print the ranking inside
        if width < 40:
            # Shift the text to the right side of the right edge
            xloc = 5
            # Black against white background
            clr = 'black'
            align = 'left'
        else:
            # Shift the text to the left side of the right edge
            xloc = -5
            # White on magenta
            clr = 'white'
            align = 'right'

        # Center the text vertically in the bar
        yloc = rect.get_y() + rect.get_height() / 2
        label = ax1.annotate(rankStr, xy=(width, yloc), xytext=(xloc, 0),
                            textcoords="offset points",
                            ha=align, va='center',
                            color=clr, weight='bold', clip_on=True)
        rect_labels.append(label)

    # make the interactive mouse over give the bar title
    ax2.fmt_ydata = format_ycursor
    # return all of the artists created
    return {
    
    'fig': fig,
            'ax': ax1,
            'ax_right': ax2,
            'bars': rects,
            'perc_labels': rect_labels}


student = Student('Johnny Doe', 2, 'boy')
scores = dict(zip(
    test_names,
    (Score(v, p) for v, p in
     zip(['7', '48', '12:52', '17', '14'],
         np.round(np.random.uniform(0, 100, len(test_names)), 0)))))
cohort_size = 62  # The number of other 2nd grade boys

arts = plot_student_results(student, scores, cohort_size)
plt.show()

显示的结果如下:在这里插入图片描述
代码详细解读以后在更。

猜你喜欢

转载自blog.csdn.net/weixin_45671036/article/details/112646889