Python Matplotlib.pyplot

Matplotlib库是一个面向对象的绘图库。绘图界面由pyplot模块提供。该模块提供了许多绘图函数,以下记录的是饼状图/甜甜圈图的相关参数和绘图过程,官方资料详见文末链接。

# 导入相关模块
import numpy as np
import matplotlib.pyplot as plt
# 使中文正常显示的参数设置
plt.rcParams['font.sans_serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

plt.subplot()plt.subplots()创建绘图环境

这两个函数都是用于创建绘图环境,但有所差异。由于参数较多,这里只对比主要的区别。

type(plt.subplot())      # matplotlib.axes._subplots.AxesSubplot

type(plt.subplots())     # tuple
type(plt.subplots()[0])  # matplotlib.figure.Figure
type(plt.subplots()[1])  # matplotlib.axes._subplots.AxesSubplot

"""
默认情况下(nrows=1,ncols=1),两个函数均准备了如下的绘图窗口。但二者返回的类型不同:
1. plt.subplot()直接返回AxesSubplot对象
2. plt.subplots()返回一个元组,且元组的第1个元素是Figure对象,第2个元素是AxesSubplot对象
"""



python 饼形图设置颜色 python做饼状图_python 饼形图设置颜色


plt.subplot(3, 1, 1)            # 缩写为plt.subplot(311),表示绘图子窗口被设定为3行1列,当前在第1个窗口
plt.plot([1, 2, 3], [2, 4, 6])  # 在第1个子窗口绘图

plt.subplot(3, 1, 2)            # 缩写为plt.subplot(312),表示绘图子窗口被设定为3行1列,当前在第2个窗口
plt.plot([1, 2, 3], [2, 4, 6])  # 在第2个子窗口绘图

plt.subplot(3, 1, 3)            # 缩写为plt.subplot(313),表示绘图子窗口被设定为3行1列,当前在第3个窗口
plt.plot([1, 2, 3], [2, 4, 6])  # 在第3个子窗口绘图

"""
绘图过程见如下动图
plt.subplot()设定了子窗口的行、列后,每次绘图才生成一个子窗口
随后可用plt.plot()、plt.scatter()、plt.pie()等命令在各个子窗口中绘图
"""



python 饼形图设置颜色 python做饼状图_python 饼形图设置颜色_02


fig, ax = plt.subplots(figsize=(12, 8), nrows=3, ncols=1)  # figsize可设定子图的长宽  
ax[0].plot([1,2,3], [2,4,6])                               # 在第1个子窗口绘图
ax[1].plot([1,2,3], [2,4,6])                               # 在第2个子窗口绘图
ax[2].plot([1,2,3], [2,4,6])                               # 在第3个子窗口绘图

"""
绘图过程见如下动图
plt.subplot()s设定了子窗口的行、列后,一次性生成所有子窗口
随后可用ax[i].plot()、ax[i].scatter()、ax[i].pie()等命令在第i+1个子窗口中绘图
当只创建了一个窗口时,则直接用ax.plot()、ax.scatter()、ax.pie()等命令,无需索引
"""



python 饼形图设置颜色 python做饼状图_python 饼形图设置颜色_03



plt.pie()绘制饼状图

饼状图的应用场景通常是比较不同类别的占比,图中每一块扇形对应着一个类别的百分比。pie() 函数的输入数据 x 可能有以下几种形式:

  1. 已经计算好的、各类别对应的百分比(其和等于1),例如:

类别1

类别2

类别3

20%

50%

30%

  1. 未经百分比计算的、直接的统计数据(其和通常大于1),例如:

类别1

类别2

类别3

20

50

30

比较常见的是第2种类型的统计数据,即当python 饼形图设置颜色 python做饼状图_Text_04时,pie() 函数会进行归一化,以python 饼形图设置颜色 python做饼状图_饼图_05形成饼状图的各个扇形部分。

  1. 一种特殊的情况是,当python 饼形图设置颜色 python做饼状图_Text_06时,例如:

类别1

类别2

类别3

0.1

0.5

0.2

此时,pie() 不会进行归一化,而是直接绘制出缺失一个类别的饼状图(除了python 饼形图设置颜色 python做饼状图_饼图_07python 饼形图设置颜色 python做饼状图_Text_08python 饼形图设置颜色 python做饼状图_饼图_09三个类别外,应剩余一个python 饼形图设置颜色 python做饼状图_饼图_09的类别,以空白区绘制):



python 饼形图设置颜色 python做饼状图_子窗口_11


此外,各个类别的扇形默认从x轴开始,以逆时针的顺序绘制。

【plt.pie()的参数】

# 饼状图函数
plt.pie(x, explode=None, labels=None, colors=None, 
        autopct=None, pctdistance=0.6, shadow=False, 
        labeldistance=1.1, startangle=None, 
        radius=None, counterclock=True, wedgeprops=None, 
        textprops=None, center=(0, 0), frame=False)

【参数含义】

参数

含义

类型

默认

x

用于绘图的数值,决定扇形大小

array-like

explode

指定饼图某些类别(远离圆心)突出显示

array-like, optional

None

labels

各个数值对应的类别标签

list, optional

None

colors

饼图的填充色

array-like, optional

None

autopct

自动添加百分比显示,可以采用格式化的方法显示

string, or function, optional

None

pctdistance

百分比标签与圆心的距离

float, optional

0.6

shadow

是否添加饼图的阴影效果

bool, optional

False

labeldistance

各扇形标签(图例)与圆心的距离

float, optional

1.1

startangle

饼图的初始摆放角度

float, optional

None

radius

饼图的半径大小

float, optional

None

counterclock

是否让饼图按逆时针顺序呈现

bool, optional

True

wedgeprops

饼图内外边界的属性,如边界线的粗细、颜色等

dict, optional

None

textprops

饼图中文本的属性,如字体大小、颜色等

dict, optional

None

center

指定饼图的中心点位置,默认为原点

list of float, optional

(0, 0)

frame

是否要显示饼图背后的图框,如果设置为True的话,需要同时控制图框x轴、y轴的范围和饼图的中心位置

bool, optional

False

由于饼状图是圆形的,所以绘图尺寸一般设置为正方形或圆形最佳,可以通过参数aspect="equal"实现。

【官网示例】

# plt.subplots定义画布和图型;figsize设置画布尺寸;aspect="equal"设置坐标轴的方正
fig, ax = plt.subplots(figsize=(6, 3), subplot_kw=dict(aspect="equal"))

recipe = ["375 g flour",
          "75 g sugar",
          "250 g butter",
          "300 g berries"]

data = [float(x.split()[0]) for x in recipe]           # 输入数值:375、75、250、300
ingredients = [x.split()[-1] for x in recipe]          # 对应标签:flour、sugar、butter、berries


"""
pct是各类别百分比的整数部分(不含百分号):[37.5, 7.5, 25, 30]
allvals是统计绝对值列表:[375, 75, 250, 300]
fuc函数自定义百分比标签的摆放形式:百分数占一行,统计绝对值占一行
"""
def func(pct, allvals):
    absolute = int(pct/100.*np.sum(allvals))
    return "{:.1f}%\n({:d} g)".format(pct, absolute)


"""
参数autopct以函数形式传递,指定百分比标签(以及绝对值标签)的摆放形式
参数textprops以字典形式传递,设置字体颜色、字体大小等

ax.pie(data)返回一个元组

wedges是一个列表,其中包含4个matplotlib.patches.Wedge实例:
[<matplotlib.patches.Wedge at 0x2ec2b835860>, 
<matplotlib.patches.Wedge at 0x2ec2b835d68>, 
<matplotlib.patches.Wedge at 0x2ec2b60f240>, 
<matplotlib.patches.Wedge at 0x2ec2b60f9b0>]

texts是一个列表,其中包含4个matplotlib.text.Text实例:
[Text(0.420952,1.01627,''),
 Text(-0.937904,0.574748,''),
 Text(-0.980107,-0.49939,''),
 Text(0.646564,-0.889919,'')]

autotexts是一个列表,其中包含4个matplotlib.text.Text实例:
[Text(0.22961,0.554328,'37.5%\n(375 g)'),
 Text(-0.511584,0.313499,'7.5%\n(75 g)'),
 Text(-0.534604,-0.272394,'25.0%\n(250 g)'),
 Text(0.352671,-0.48541,'30.0%\n(300 g)')]
"""
wedges, texts, autotexts = ax.pie(data, autopct=lambda pct: func(pct, data),
                                  textprops=dict(color="w"))

# ax.legend()指定各扇形(wedges)的图例标签(ingredients)、图例标题(title)、图例位置(loc)、图例坐标(bbox_to_anchor)
ax.legend(wedges, ingredients,
          title="Ingredients",
          loc="center left",
          bbox_to_anchor=(1, 0, 0.5, 1))

# 设置文本标签的样式
plt.setp(autotexts, size=8, weight="bold")

ax.set_title("Matplotlib bakery: A pie")

plt.show()



python 饼形图设置颜色 python做饼状图_子窗口_12



plt.pie()绘制甜甜圈

fig, ax = plt.subplots(figsize=(6, 3), subplot_kw=dict(aspect="equal"))

recipe = ["225 g flour",
          "90 g sugar",
          "1 egg",
          "60 g butter",
          "100 ml milk",
          "1/2 package of yeast"]

data = [225, 90, 50, 60, 100, 5]

"""
参数wedgeprops以字典形式传递,设置饼图边界的相关属性,例如圆环宽度0.5
饼状图默认从x轴正向沿逆时针绘图,参数startangle可指定新的角(例如负40度)度起画
"""
wedges, texts = ax.pie(data, wedgeprops=dict(width=0.5), startangle=-40)

# 创建字典bbox_props,设置文本框的边框样式(boxstyle:方框,pad设置方框尺寸)、前景色(fc)为白色(w)、边框颜色(ec)为黑色(k)、线粗(lw)为0.72
bbox_props = dict(boxstyle="square,pad=0.3", fc="w", ec="k", lw=0.72)

"""
参数集kw以字典形式传递,包含一系列用于绘图标注的指定参数
xycoords用于指定点xy的坐标环境,xycoords='data'表示沿用被注释的对象所采用的坐标系(默认设置)
textcoords用于指定点xytext的坐标环境,textcoords='data'表示沿用被注释的对象所采用的坐标系(默认设置)
参数arrowprops以字典形式传递,用于控制箭头的诸多属性,如箭头类型(arrowstyle)、箭头连接时的弯曲程度(connectionstyle)
"""
kw = dict(xycoords='data', textcoords='data', arrowprops=dict(arrowstyle="-"),
          bbox=bbox_props, zorder=0, va="center")

for i, p in enumerate(wedges):                                            # 遍历每一个扇形

    ang = (p.theta2 - p.theta1)/2. + p.theta1                             # 锁定扇形夹角的中间位置,对应的度数为ang

	# np.deg2rad(x)将度数x转为弧度(x*pi)/180
    y = np.sin(np.deg2rad(ang))                                           # np.sin()求正弦
    x = np.cos(np.deg2rad(ang))                                           # np.cos()求余弦
    
    """
    np.sign()符号函数:大于0返回1.0,小于0返回-1.0,等于0返回0.0
    参数horizontalalignment用于设置垂直对齐方式,可选参数:left、right、center
    当余弦值x大于0(即标签在饼图右侧时,按框左侧对齐)时,horizontalalignment="left"
    当余弦值x小于0(即标签在饼图左侧时,按框右侧对齐)时,horizontalalignment="right" 
    """
    horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
	
    connectionstyle = "angle,angleA=0,angleB={}".format(ang)             # 参数connectionstyle用于控制箭头连接时的弯曲程度
    kw["arrowprops"].update({"connectionstyle": connectionstyle})        # 将connectionstyle更新至参数集kw的参数arrowprops中
    
    """
    用一个箭头/横线指向要注释的地方,再写上一段话的行为,叫做annotate
    ax.annotate()用于对已绘制的图形做标注
    recipe[i]是第i个注释文本
    size设置字体大小
    xy=(x1, y1)表示在给定的xycoords中,被注释对象的坐标点
    xytext=(x2, y2)表示在给定的textcoords中,注释文本的坐标点
    """
    ax.annotate(recipe[i], size=10, xy=(x, y), xytext=(1.35*np.sign(x), 1.4*y),
                 horizontalalignment=horizontalalignment, **kw)

ax.set_title("Matplotlib bakery: A donut")

plt.show()

创建bbox_props字典参数时,有许多类型的选项,可在Annotating Axes查看。



python 饼形图设置颜色 python做饼状图_Text_13


用实际数据绘图

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
df = pd.read_csv('all.csv', encoding='utf-8')

# 【直方图+折线】
year = df['year'].value_counts().sort_index()
plt.figure(figsize=(11, 11*0.618))
plt.bar(range(len(year)), list(year), width=0.8, align='center', color='steelblue')
# plt.title('title', fontsize=20)
plt.ylabel('x', fontsize=18)
plt.xlabel('y', fontsize=18)
plt.xticks(range(len(year)), list(year.index), fontsize=15, rotation=90)
plt.yticks(fontsize=15)
plt.plot(range(len(year)), list(year), color='black', linewidth=0.8)
plt.tight_layout()
for x, y in enumerate(list(year)):
    plt.text(x, y+10, '%s' % y, ha='center', fontsize=12)
plt.savefig('直方图+折线.png')

# 甜甜圈
area = df['area'].value_counts()
pct = [format(i/sum(list(area)), '.1%') for i in list(area)]
text_label = ['{}({})'.format(i[0], i[1]) for i in zip(list(area.index), pct)]
fig, ax = plt.subplots(figsize=(11, 11*0.618), subplot_kw=dict(aspect="equal"))
# ax.set_title("title", fontsize=20)
explode = [0.02] * len(area)
wedges, texts = ax.pie(list(area), wedgeprops=dict(width=0.6),
                       startangle=0, explode=explode)
for i, p in enumerate(wedges):
    ang = (p.theta2 - p.theta1)/2. + p.theta1
    y = np.sin(np.deg2rad(ang))
    x = np.cos(np.deg2rad(ang))
    if i < 7:
        connectionstyle = "angle,angleA=0,angleB={}".format(ang)
        bbox_props = dict(boxstyle="square,pad=0.65", fc="w", ec="k", lw=1)
        kw = dict(xycoords='data', textcoords='data',
                  arrowprops=dict(arrowstyle="-", connectionstyle=connectionstyle),
                  bbox=bbox_props, zorder=0, va="center")
        horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
        ax.annotate(text_label[i], size=14, xy=(x, y), xytext=(1.2*np.sign(x), 1.35*y),
                    horizontalalignment=horizontalalignment, **kw)
    else:
        bbox_props = dict(boxstyle="square,pad=0.18", fc="w", ec="k", lw=1)
        kw = dict(xycoords='data', textcoords='data',
                  arrowprops=dict(arrowstyle="-"),
                  bbox=bbox_props, zorder=0, va="center")
        dynamic_y = [1.5*y, 1.3*y, -1.5*y, -25*y]
        ax.annotate(text_label[i], size=10, xy=(x, y), xytext=(1.2*np.sign(x)+0.03*i, dynamic_y[i-7]),
                    horizontalalignment=horizontalalignment, **kw)
plt.savefig('圆环图.png')

# 词云图
import jieba
from collections import Counter
from pyecharts import WordCloud
str = ''.join(list(df['经营范围']))
seg_list = jieba.lcut(str)
stop = []  # 自备停用词表
cloud_data = [word for word in seg_list if word not in stop]
count = Counter(cloud_data)
wordcloud = WordCloud(width=1300, height=620)
wordcloud.add('', count.keys(), count.values(), word_size_range=[10, 100], shape='circle', rotate_step=30)
wordcloud.render('wordcloud.html')



python 饼形图设置颜色 python做饼状图_python 饼形图设置颜色_14


python 饼形图设置颜色 python做饼状图_python 饼形图设置颜色_15


python 饼形图设置颜色 python做饼状图_python 饼形图设置颜色_16


参考资料
官方文档:matplotlib.pyplot.subplot官方文档:matplotlib.pyplot.subplots官方文档:matplotlib.pyplot.pie官方文档:Labeling a pie and a donut官方文档:Annotating Axes从0开始学Python系列11–饼图的绘制