[Python] Matplotlib 图表的绘制和美化技巧

在一张画布中绘制多个图表

Matplotlib模块在绘制图表时,默认先建立一张画布,然后在画布中显示绘制的图表。

如果想要在一张画布中绘制多个图表,可以使用subplot()函数将画布划分为几个区域,然后在各个区域中分别绘制不同的图表。

subplot()函数的参数为3个整型数字:

  • 第1个数字代表将整张画布划分为几行;
  • 第2个数字代表将整张画布划分为几列;
  • 第3个数字代表要在第几个区域中绘制图表,区域的编号规则是按照从左到右、从上到下的顺序,从1开始编号。

演示代码如下:

import matplotlib.pyplot as plt

# 如果值中有中文字符,则必须在绘制图表前加上这两行代码
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y = [50, 45, 65, 76, 75, 85, 55, 78, 86, 89, 94, 90]
plt.subplot(2, 2, 1)
plt.pie(y, labels = x, labeldistance = 1.1, startangle = 90, counterclock = False)
plt.subplot(2, 2, 2)

# 参数width用于设置柱子的宽度,默认值为0.8。如果设置为1,则各个柱子会紧密相连;如果设置为大于1的数,则各个柱子会相互交叠
plt.bar(x, y, width = 0.5, color = 'r')
plt.subplot(2, 2, 3)

# 参数color用于设置柱子的填充颜色,具体取值见后面的说明
plt.stackplot(x, y, color = 'r')
plt.subplot(2, 2, 4)
plt.plot(x, y, color = 'r', linestyle = 'solid', linewidth = 2, marker = 'o', markersize = 10)
plt.show()

输出结果:

用颜色名的英文单词或其简写定义的8种基础颜色,具体见:

加图表元素

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y = [50, 45, 65, 76, 75, 85, 55, 78, 86, 89, 94, 90]

# 这里加了标签
plt.bar(x, y, width=0.6, color='r', label='销售额(万元)')

# 这里加了标题,loc还可以是right和left
plt.title(label='销售额对比图', fontdict={'family': 'KaiTi', 'color': 'k', 'size': 30}, loc='center')

# 坐标上的标签
plt.xlabel('月份', fontdict={'family': 'SimSun', 'color': 'k', 'size': 20}, labelpad=20)  
plt.ylabel('销售额', fontdict={'family': 'SimSun', 'color': 'k', 'size': 20}, labelpad=20)  

# legend()函数用于添加图例
plt.legend(loc='upper left', fontsize=15)

# zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
for a,b in zip(x, y):
    # text()函数的功能是在图表坐标系的指定位置添加文本。参数ha是horizontalalignment的简称,相对应有va
    plt.text(x=a, y=b, s=b, ha='center', va='bottom', fontdict={'family': 'KaiTi', 'color': 'k', 'size': 20})
plt.show()

输出结果

气泡图

气泡图是一种展示三个变量之间关系的图表,它其实是在散点图的基础上升级改造而成的,在原有的x坐标和y坐标两个变量的基础上,引入第三个变量,并用气泡的大小表示。

pip install openpyxl

产品销售统计.xls 内容

产品名称 销售量(件) 销售额(元) 毛利率(%)
牛仔裤 125 6800 30
连衣裙 278 5600 20
运动裤 366 7800 35
短裤 452 5800 10
短裙 365 5400 50
背带裤 258 10000 22
半身裙 369 3600 15
阔腿裤 566 7800 8

代码如下:

import matplotlib.pyplot as plt
import pandas as pd
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_excel('产品销售统计.xls')
n = data['产品名称']
x = data['销售量(件)']
y = data['销售额(元)']
z = data['毛利率(%)']
plt.scatter(x, y, s=z * 300, color='r', marker='o')
plt.xlabel('销售量(件)', fontdict={'family': 'Microsoft YaHei', 'color': 'k', 'size': 20}, labelpad=20)
plt.ylabel('销售额(元)', fontdict={'family': 'Microsoft YaHei', 'color': 'k', 'size': 20}, labelpad=20)
plt.title('销售量、销售额与毛利率关系图', fontdict={'family': 'Microsoft YaHei', 'color': 'k', 'size': 30}, loc='center')
for a, b, c in zip(x, y, n):
    plt.text(x=a, y=b, s=c, ha='center', va='center', fontsize=15, color='w')
plt.xlim(50, 600)
plt.ylim(2900, 11000)
plt.show()

输出结果:

组合图

组合图是指在一个坐标系中绘制多张图表,其实现方式也很简单,在使用Matplotlib模块中的函数绘制图表时设置多组y坐标值即可。

销售业绩表.xls

月份 销售额(万元) 同比增长率
1月 ¥36.00 10%
2月 ¥25.00 8%
3月 ¥36.12 20%
4月 ¥69.30 50%
5月 ¥26.90 15%
6月 ¥32.00 11%
7月 ¥45.00 26%
8月 ¥56.00 13%
9月 ¥25.60 4%
10月 ¥36.21 5%
11月 ¥25.00 7%
12月 ¥59.00 30%
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_excel('销售业绩表.xlsx')
x = data['月份']
y1 = data['销售额(万元)']
y2 = data['同比增长率'] 
plt.bar(x, y1, color = 'c', label = '销售额(万元)')  
plt.legend(loc = 'upper left', fontsize = 15)  

# 使用twinx()函数为图表添加次坐标轴
plt.twinx()  
plt.plot(x, y2, color = 'r', linewidth = 3, label = '同比增长率')  
plt.legend(loc = 'upper right', fontsize = 15)  
plt.show()

输出结果:

直方图

直方图用于展示数据的分布情况,使用Matplotlib模块中的hist()函数可以绘制直方图

客户年龄统计表.zip

import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_excel('客户年龄统计表.xlsx')
x = data['年龄']
plt.hist(x, bins = 9)
plt.xlim(15, 60)
plt.ylim(0, 40)
plt.title('年龄分布直方图', fontsize = 20)
plt.xlabel('年龄')
plt.ylabel('人数')
plt.grid(b = True, linestyle = 'dotted', linewidth = 1)
plt.show()

输出结果

雷达图

雷达图可以同时比较和分析多个指标。该图表可以看成一条或多条闭合的折线,因此,使用绘制折线图的plot()函数也可以绘制雷达图。

汽车性能指标分值统计表.xlsx

性能评价指标 A品牌 B品牌 C品牌
动力性 1 3 10
燃油经济性 2 6 7
制动性 1 10 5
操控稳定性 3 10 2
行驶平顺性 2 6 1
通过性 4 7 2
安全性 8 2 1
环保性 9 1 3
方便性 10 3 0
舒适性 8 2 1
经济性 4 1 10
容量性 2 2 8

代码如下:

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 
data = pd.read_excel('汽车性能指标分值统计表.xlsx')

data = data.dropna(axis=1)
data = data.set_index('性能评价指标')
data = data.T
data.index.name = '品牌'

def plot_radar(data, feature):  
    columns = ['动力性', '燃油经济性', '制动性', '操控稳定性', '行驶平顺性', '通过性', '安全性', '环保性', '方便性', '舒适性', '经济性', '容量性'] 
    colors = ['r', 'g', 'y']

    # 设置雷达图的角度,用于平分切开一个平面
    # linspace(1,10,x) 创建1-10的等差数组,个数为 x,默认50个;endpoint参数指定是否包含终值,默认值为True,即包含终值。
    angles = np.linspace(0.1 * np.pi, 2.1 * np.pi, len(columns), endpoint = False)

    # 使雷达图封闭起来
    angles = np.concatenate((angles, [angles[0]]))

    # figsize:指定figure的宽和高,单位为英寸;    
    figure = plt.figure(figsize = (6, 6))
    
    # 设置为极坐标格式;subplot(nrows,ncols,sharex,sharey,subplot_kw,**fig_kw)创建单个子图,下面两句效果相同
    ax = figure.add_subplot(111, polar=True)
   # ax = figure.add_subplot(1, 1, 1, projection = 'polar')
    
    for i, c in enumerate(feature):
        stats = data.loc[c]

        stats = np.concatenate((stats, [stats[0]]))

        ax.plot(angles, stats, '-', linewidth = 2, c = colors[i], label = str(c))
        ax.fill(angles, stats, color = colors[i], alpha = 0.75)

    # bbox_to_anchor这个参数,可以把图例放在图外面
    # bbox_to_anchor:表示legend的位置,前一个表示左右,后一个表示上下。
    # 当使用这个参数时。loc将不再起正常的作用,ncol=3表示图例三列显示。
    ax.legend(loc = 4, bbox_to_anchor = (1.15, -0.07))

    
    #设置极轴范围
    ax.set_ylim(0,10)
    # ax.set_yticklabels([2, 4, 6, 8, 10])

    # 添加每个特质的标签
    columns = np.concatenate((columns, [columns[0]]))
    ax.set_thetagrids(angles*180/np.pi, columns, fontsize = 12)

    #添加标题
    plt.title('汽车性能指标雷达图')

    plt.show()
    return figure
figure = plot_radar(data, ['A品牌', 'B品牌', 'C品牌'])
# figure = plot_radar(data, ['B品牌'])

树状图

树状图通过矩形的面积、排列和颜色直观地展示多个项目的数据比例关系。要绘制该图表,需结合使用Matplotlib模块与squarify模块。

import squarify as sf
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
x = ['上海', '北京', '重庆', '成都', '南京', '青岛', '长沙', '武汉', '深圳']  
y = [260, 45, 69, 800, 290, 360, 450, 120, 50] 
colors = ['lightgreen', 'pink', 'yellow', 'skyblue', 'cyan', 'silver', 'lightcoral', 'orange', 'violet']
percent = ['11%', '2%', '3%', '33%', '12%', '15%', '18%', '5%', '2%']
chart = sf.plot(sizes = y, label = x, color = colors, value = percent, edgecolor = 'white', linewidth = 2)
plt.title(label = '城市销售额分布及占比图',fontdict = {'family' : 'KaiTi', 'color' : 'k', 'size' : 25})
plt.axis('off')
plt.show()

箱形图

箱形图是一种用于展示数据的分布情况的统计图,因形状如箱子而得名。使用Matplotlib模块中的boxplot()函数可以绘制箱形图。

数据

日期 成都 上海 北京 重庆 南京
1月1日 25 50 52 25 50
1月2日 12 58 56 26 56
1月3日 26 60 100 78 58
1月4日 23 78 125 45 87
1月5日 18 36 108 46 50
1月6日 15 69 100 50 60
1月7日 19 41 85 53 26
1月8日 20 52 85 61 36
1月9日 26 53 87 87 69
1月10日 27 69 86 25 78
1月11日 28 78 45 16 75
1月12日 54 80 78 69 80
1月13日 50 52 73 68 81
1月14日 51 26 62 45 45
1月15日 52 28 65 40 65
1月16日 36 57 90 50 63
1月17日 38 56 96 60 69
1月18日 45 89 94 36 64
1月19日 40 84 25 52 65
1月20日 41 85 36 54 45
1月21日 26 80 68 58 52
1月22日 29 75 78 56 59
1月23日 36 50 70 52 80
1月24日 33 25 52 57 29
1月25日 31 36 51 69 36
1月26日 15 64 58 54 29
1月27日 18 56 68 25 90
1月28日 25 54 78 36 78
1月29日 14 50 90 78 71
1月30日 39 44 95 56 75
1月31日 48 49 84 25 76
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_excel('1月销售统计表.xlsx')
x1 = data['成都']
x2 = data['上海']
x3 = data['北京']
x4 = data['重庆']
x5 = data['南京']
x = [x1, x2, x3, x4, x5]
labels = ['成都', '上海', '北京', '重庆', '南京']

# 参数vert用于设置箱形图的方向,True表示纵向展示,False表示横向展示;参数showmeans用于设置是否显示均值,True表示显示均值,False表示不显示均值。
plt.boxplot(x, vert = True, widths = 0.5, labels = labels, showmeans = True )
plt.title('各地区1月销售额箱形图', fontsize = 20)
plt.ylabel('销售额(万元)')
plt.show()

箱形图中的5条横线和1个点所代表的含义如下:

  • 下限:指所有数据中的最小值;
  • 下四分位数:又称“第一四分位数”,指将所有数据从小到大排列后第25%的值;
  • 中位数:又称“第二四分位数”,指将所有数据从小到大排列后第50%的值;
  • 上四分位数:又称“第三四分位数”,指将所有数据从小到大排列后第75%的值;
  • 上限:指所有数据中的最大值;
  • 点:指所有数据的平均值。

玫瑰图

玫瑰图可反映多个维度的数据,它将柱形图转化为饼图,在圆心角相同的情况下,以扇面长度展示指标大小。要绘制玫瑰图,也要用到绘制柱形图的bar()函数。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']   
plt.rcParams['axes.unicode_minus'] = False

# 将风速的分布设置为4个区间
index = ['0~0.5', '0.6~2.0', '2.1~4.0', '4.1~6.0']

# 设置了16个方向
columns = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']

# seed()函数用于产生相同的随机数
np.random.seed(0)

# 创建一个4行16列的DataFrame,其中的数据是30~300范围内的随机数,行标签为第6行代码设置的风速分布区间,列标签为第7行代码设置的方向。
data = pd.DataFrame(np.random.randint(30, 300, (4, 16)), index = index, columns = columns)
N = 16

# 生成16个方向的角度值
theta = np.linspace(0, 2 * np.pi, N, endpoint = False)

# 用于计算扇面的宽度
width = np.pi / N 
labels = list(data.columns) 
plt.figure(figsize = (6, 6))
ax = plt.subplot(1, 1, 1, projection = 'polar')
for i in data.index:
    radius = data.loc[i] 
    # 使用bar()函数绘制玫瑰图中的16根柱子,也就是扇面,参数bottom用于设置每根柱子底部的位置,这里设置为0.0,表示从圆心开始绘制。
    ax.bar(theta, radius, width = width, bottom = 0.0, label = i, tick_label = labels)

# 设置0°的方向为“N”,即北方
ax.set_theta_zero_location('N') 

# 设置按逆时针方向排列各个柱子
ax.set_theta_direction(-1)    
plt.title('各方向风速频数玫瑰图', fontsize = 20)
plt.legend(loc = 4, bbox_to_anchor = (1.3, 0.2)) 
plt.show()

更多可参考:
[Python] 茎叶图和复合饼图的画法 https://www.cnblogs.com/feily/p/14429244.html

posted @ 2021-02-20 19:43  哆啦梦乐园  阅读(4527)  评论(3编辑  收藏  举报