python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Matplotlib柱状图、直方图和饼状图

Python利用Matplotlib绘制柱状图(竖直柱状图和水平柱状图)、直方图和饼状图

作者:虚心求知的熊

这篇文章主要给大家介绍了关于Python利用Matplotlib绘制柱状图(竖直柱状图和水平柱状图)、直方图和饼状图的相关资料,Python使用matplotlib画图是非常方便的,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在开始,我们先引入 matplotlib 和 numpy 库。

from matplotlib import pyplot as plt
import numpy as np

对基本配置进行设置,将中文字体设置为黑体,不包含中文负号,分辨率为 100,图像显示大小设置为 (5,3)。

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False​
plt.rcParams['figure.dpi'] = 100​
plt.rcParams['figure.figsize'] = (5,3)

一、柱状图

柱状图是一种用矩形柱来表示数据分类的图表。柱状图可以垂直绘制,也可以水平绘制。它的高度与其所表示的数值成正比关系。柱状图显示了不同类别之间的比较关系,图表的水平轴 X 指定被比较的类别,垂直轴 Y 则表示具体的类别值

二、竖直柱状图

matplotlib.pyplot.bar(x, height, width: float = 0.8, bottom = None, *, align: str = ‘center', data = None, **kwargs)

其参数具体如下含义:

1. 基本的柱状图

import matplotlib.pyplot as plt
x = range(5)
​data = [5, 20, 15, 25, 10]
​plt.title("基本柱状图")
plt.grid(ls="--", alpha=0.5)
plt.bar(x, data)

(1) bottom 参数。

import matplotlib.pyplot as plt
x = range(5)
​data = [5, 20, 15, 25, 10]
​plt.title("基本柱状图")
​plt.grid(ls="--", alpha=0.5)
plt.bar(x, data, bottom=[10, 20, 5, 0, 10])

(2) 柱状图颜色。

关于柱状图的颜色,我们也采用上述的数据进行操作,此时,不设置柱状图的 bottom 参数,同时,将柱状图的颜色设置为绿色。

import matplotlib.pyplot as plt
x = range(5)
data = [5, 20, 15, 25, 10]
​plt.title("设置柱状图颜色")
plt.grid(ls="--", alpha=0.5)
​plt.bar(x, data ,facecolor="green")
#plt.bar(x, data ,color="green")

那么,在某些特定的情况下,柱状图的单一颜色并不利于我们后续的观察,因此,我们可以使用 facecolor 函数,分别对每个柱状图进行颜色的设置。

import matplotlib.pyplot as plt
x = range(5)
data = [5, 20, 15, 25, 10]
plt.title("color参数设置柱状图不同颜色")
plt.grid(ls="--", alpha=0.5)
plt.bar(x, data ,color=['r', 'g', 'b'])

(3) 柱状图描边。

import matplotlib.pyplot as plt​
data = [5, 20, 15, 25, 10]​
plt.title("设置边缘线条样式")​
plt.bar(range(len(data)), data, ec='r', ls='--', lw=2)

2. 同位置多柱状图

在同一个 x 轴位置绘制多个柱状图,主要是通过调整柱状图的宽度和每个柱状图 x 轴的起始位置。

例如,我们有 2022 年冬奥会挪威、德国、中国、美国和瑞典的金银铜牌数和总奖牌数。

对此,我们需要绘制如下图形:

对该柱状图进行分析,可得:

(1) 本实例需要对 x 轴进行计算,因此需要将 x 轴转数值。

(2) 确定同一 x 轴中,每个柱状图 x 轴的起始位置。

(3) 需要设置图形的宽度。

(4) 图形 2 的起始位置 = 图形 1 起始位置 + 图形的宽度。

(5) 图形 3 的起始位置 = 图形 1 起始位置 + 2 倍图形的宽度。

(6) 需要给每个柱状图循环显示文本内容。

(7) 需要显示图例。

具体柱状图绘制过程如下:

首先,我们需要导入国家和各个国家的金银铜奖牌数。

countries = ['挪威', '德国', '中国', '美国', '瑞典']
gold_medal = [16, 12, 9, 8, 8]
silver_medal = [8, 10, 4, 10, 5]
bronze_medal = [13, 5, 2, 7, 5]

此时,如果我们直接进行绘制的话,会发现每个国家的奖牌柱状图发生了重叠,并且每个柱状图的宽度也过大。

这是因为他们都默认 y 轴的起始坐标也就是 bottom 参数为 0,宽度参数由于没有设置,默认是 0.8。

plt.bar(countries, gold_medal,color="gold")
plt.bar(countries,silver_medal,color="silver")
plt.bar(countries,bronze_medal,color="red")

针对上述在绘图过程当中出现的问题和最后结果的样图,我们需要将每个国家的金银铜牌柱状图分别画在一起,所以我们需要对 x 轴的国家参数进行坐标计算。

由于字符串不可以直接进行算术运算,因此,我们使用 np.arange 将他们转化成数组,然后在返回字符串国家,并将柱状图的宽度 width 设置为 0.2

x = np.arange(len(countries))
print(x)
width = 0.2
#[0 1 2 3 4]

随后,我们确定每个国家的金银铜牌柱状图的起始位置。

金牌呃起始位置就是每个国家对应的 x 数值,银牌的起始位置就是每个国家对应的 x 数值再加上金牌柱状图的宽度,铜牌的起始位置与银牌相似,加上两倍的金牌位置即可(这里我们将每个柱状图的宽度均设置为 0.2)。

gold_x = x​
silver_x = x + width
​bronze_x = x + 2 * width

在上述运行完成后,分别绘制图形即可。

plt.bar(gold_x,gold_medal,width=width,color="gold")
​plt.bar(silver_x,silver_medal,width=width,color="silver")
​plt.bar(bronze_x,bronze_medal,width=width, color="saddlebrown")

此时,我们注意到,绘制柱状图的横坐标是数字还没有返回我们的国家参数。

对此,我们需要将 x 轴的坐标变回来。

plt.xticks(x+width, labels=countries)​

最后,我们显示出每一个柱状图的高度参数和图例,就得到了我们需要的图像。

for i in range(len(countries)):
    plt.text(gold_x[i],gold_medal[i], gold_medal[i],va="bottom",ha="center",fontsize=8)
    plt.text(silver_x[i],silver_medal[i], gold_medal[i],va="bottom",ha="center",fontsize=8)
    plt.text(bronze_x[i],bronze_medal[i], gold_medal[i],va="bottom",ha="center",fontsize=8)  
plt.legend()

代码汇总:

#库导入
from matplotlib import pyplot as plt
import numpy as np

#参数设置
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 100
plt.rcParams['figure.figsize'] = (5,3)

#国家和奖牌数据导入
countries = ['挪威', '德国', '中国', '美国', '瑞典']
gold_medal = [16, 12, 9, 8, 8]
silver_medal = [8, 10, 4, 10, 5]
bronze_medal = [13, 5, 2, 7, 5]

#将横坐标国家转换为数值
x = np.arange(len(countries))
width = 0.2

#计算每一块的起始坐标
gold_x = x
silver_x = x + width
bronze_x = x + 2 * width

#绘图
plt.bar(gold_x,gold_medal,width=width,color="gold",label="金牌")
plt.bar(silver_x,silver_medal,width=width,color="silver",label="银牌")
plt.bar(bronze_x,bronze_medal,width=width, color="saddlebrown",label="铜牌")

#将横坐标数值转换为国家
plt.xticks(x + width,labels=countries)

#显示柱状图的高度文本
for i in range(len(countries)):
    plt.text(gold_x[i],gold_medal[i], gold_medal[i],va="bottom",ha="center",fontsize=8)
    plt.text(silver_x[i],silver_medal[i], gold_medal[i],va="bottom",ha="center",fontsize=8)
    plt.text(bronze_x[i],bronze_medal[i], gold_medal[i],va="bottom",ha="center",fontsize=8)  

#显示图例
plt.legend(loc="upper right") 

其他知识点:在 Matplotlib 中旋转 X 轴刻度标签文本。

(1) plt.xticks(rotation= ) 旋转 Xticks 标签文本。

(2) fig.autofmt_xdate(rotation= ) 旋转 Xticks 标签文本。

(3) ax.set_xticklabels(xlabels, rotation= ) 旋转 Xticks 标签文本。

(4) plt.setp(ax.get_xticklabels(), rotation=) 旋转 Xticks 标签文本。

(5) ax.tick_params(axis=‘x’, labelrotation= ) 旋转 Xticks 标签文本。

3. 堆叠柱状图

所谓堆叠柱状图就是将不同数组别的柱状图堆叠在一起,堆叠后的柱状图高度显示了两者相加的结果值。 如图:

对该图进行分析可得:

(1) 金牌榜的起始高度为:铜牌数据+银牌数据。

(2) 银牌榜的起始高度为:银牌高度。

(3) 铜牌榜的起始高度为:0。

(4) 起始位置的数据相加需要使用 numpy 的相关知识。

(6) 需要确定柱状图的颜色。

(7) 显示图例。

具体的绘制办法,跟上一个同位置多柱状图是完全类似的,区别在于我们需要注意 bottom 的数值计算,同时,金银铜牌的起始坐标是完全相同的。

#库导入
from matplotlib import pyplot as plt
import numpy as np

#参数设置
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 100
plt.rcParams['figure.figsize'] = (5,3)

#国家和奖牌数据输入、柱状图宽度设置
countries = ['挪威', '德国', '中国', '美国', '瑞典']
gold_medal = np.array([16, 12, 9, 8, 8])
silver_medal = np.array([8, 10, 4, 10, 5])
bronze_medal = np.array([13, 5, 2, 7, 5])
​width = 0.3

#绘图
plt.bar(countries, gold_medal, color='gold', label='金牌',
        bottom=silver_medal + bronze_medal,width=width)
plt.bar(countries, silver_medal, color='silver', label='银牌', bottom=bronze_medal,width=width)
​plt.bar(countries, bronze_medal, color='#A0522D', label='铜牌',width=width)

#设置y轴标签,图例和文本值
​plt.ylabel('奖牌数')
​plt.legend(loc='upper right')
​for i in range(len(countries)):
    max_y = bronze_medal[i]+silver_medal[i]+gold_medal[i]
    plt.text(countries[i], max_y, max_y, va="bottom", ha="center")​

三、水平柱状图

1. 基本的柱状图

plt.barh(y, width, height=0.8, left=None, *, align='center', **kwargs)

例如,我们以竖直柱状图当中的国家金牌数为例进行绘制。

countries = ['挪威', '德国', '中国', '美国', '瑞典']
gold_medal = np.array([16, 12, 9, 8, 8])
plt.barh(countries, width=gold_medal)

2. 同位置多柱状图

movie = ['新蝙蝠侠', '狙击手', '奇迹笨小孩']
real_day1 = [4053, 2548, 1543]
real_day2 = [7840, 4013, 2421]
real_day3 = [8080, 3673, 1342]

对此,我们需要绘制如下图像。

对该图进行分析可得:

(1) 由于牵扯高度的计算,因此先将 y 轴转换为数值型。

(2) 需要设置同图形的高度。

(3) 计算每个图形高度的起始位置。

(4) 绘制图形。

(5) 替换 y 轴数据。

由于牵扯计算,因此将数据转 numpy 数组,水平的用位置多柱状图绘制方法与竖直的完全相同,在此便不过多叙述了。

#库导入
from matplotlib import pyplot as plt
import numpy as np

#参数设置
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 100
plt.rcParams['figure.figsize'] = (5,3)

#数据的输入
movie = ['新蝙蝠侠', '狙击手', '奇迹笨小孩']
real_day1 = np.array( [4053, 2548, 1543])
​real_day2 = np.array([7840, 4013, 2421])
​real_day3 = np.array([8080, 3673, 1342])
​​
#y轴转换为数值型
num_y = np.arange(len(movie))
​
#设置同图形的高度
height = 0.2
​
#计算每个图形高度的起始位置
movie1_start_y = num_y              
movie2_start_y = num_y + height      
movie3_start_y = num_y + 2 * height  ​
​
#绘制图形​
plt.barh(movie1_start_y, real_day1, height=height)​
plt.barh(movie2_start_y, real_day2,  height=height)​
plt.barh(movie3_start_y, real_day3, height=height)
​
# 计算宽度值和y轴值,替换y轴数据
​plt.yticks(num_y + height, movie)

3. 堆叠柱状图

水平的堆叠柱状图与竖直的堆叠柱状图类似都是将不同数组别的柱状图堆叠在一起,堆叠后的柱状图高度显示了两者相加的结果值。 如图:

对该图进行分析可得:

(1) 确定图形距离左侧的位置。

(2) 设置同一宽度。

(3) 绘制图形设置 left 参数。

(4) 标注数据。

由于过程当中牵扯到计算,因此需要将数据转 numpy 数组。其他部分与绘制竖直堆叠柱状图的过程类似,在此便不过多进行叙述。

#库导入
from matplotlib import pyplot as plt
import numpy as np

#参数设置
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 100
plt.rcParams['figure.figsize'] = (5,3)

#数据的输入
movie = ['新蝙蝠侠', '狙击手', '奇迹笨小孩']
real_day1 = np.array( [4053, 2548, 1543])
real_day2 = np.array([7840, 4013, 2421])
real_day3 = np.array([8080, 3673, 1342])
​
#确定距离左侧​
left_day2 = real_day1​
left_day3 = real_day1 + real_day2 
​
# 设置线条高度
height = 0.2
​
# 绘制图形:
plt.barh(movie, real_day1, height=height)​
plt.barh(movie, real_day2, left=left_day2, height=height) ​
plt.barh(movie, real_day3, left=left_day3, height=height) 
​
# 设置数值文本,计算宽度值和y轴为值​
sum_data = real_day1 + real_day2 +real_day3
for i in range(len(movie)):
    plt.text(sum_data[i], movie[i], sum_data[i],va="center" , ha="left")

四、直方图 plt.hist()

柱状图直方图
柱状图一般用于描述离散型分类数据的对比直方图一般用于描述连续型数据的分布关系
每根柱子宽度固定,柱子之间会有间距每根柱子宽度可以不一样,且一般没有间距
横轴变量可以任意排序横轴变量有一定顺序规则
plt.hist(x, bins=None, range=None, density=None, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, normed=None, *, data=None, **kwargs)
x_value = np.random.randint(140,180,300)
plt.hist(x_value, bins=10, edgecolor='white')
plt.title("数据统计")
plt.xlabel("身高")
plt.ylabel("比率")

1. 返回值

num
#array([25., 28., 34., 39., 29., 25., 37., 34., 26., 23.])

bins_limit
#array([140. , 143.9, 147.8, 151.7, 155.6, 159.5, 163.4, 167.3, 171.2,
#       175.1, 179. ])

for i in patches:
    print(i)
    print(i.get_x())
    print(i.get_y())
    print(i.get_height())
    print(i.get_width())

patches[0].get_width()
#3.9000000000000057

2. 添加折线直方图

#创建一个画布
fig, ax = plt.subplots()
​
# 绘制直方图
num,bins_limit,patches = ax.hist(x_value, bins=10, edgecolor='white')
​
# 注意num返回的个数是10,bins_limit返回的个数为11,需要截取
print(bins_limit[:-1])

# 曲线图
ax.plot(bins_limit[:10], num, '--',marker="o")
plt.xticks(bins_limit,rotation=45)

3. 不等距分组

面的直方图都是等距的,但有时我们需要得到不等距的直方图,这个时候只需要确定分组上下限,并指定 histtype=“bar” 就可以。

fig, ax = plt.subplots()
x = np.random.normal(100,20,100)
bins = [50, 60, 70, 90, 100,110, 140, 150]
ax.hist(x, bins, color="g",rwidth=0.5)
ax.set_title('不等距分组')
plt.show()

4. 多类型直方图

n_bins=10
​fig,ax=plt.subplots(figsize=(8,5))
​x_multi = [np.random.randn(n) for n in [10000, 5000, 2000]]
​ax.hist(x_multi, n_bins, histtype='bar',label=list("ABC"))
​ax.set_title('多类型直方图')
​ax.legend()

5. 堆叠直方图

我们有时候会对吧同样数据范围情况下,对比两组不同对象群体收集的数据差异。

对此,我们准备两组数据:

x_value = np.random.randint(140,180,200)
x2_value = np.random.randint(140,180,200)

直方图属性 data:以列表的形式传入两组数据。

设置直方图 stacked:为 True,允许数据覆盖。

plt.hist([x_value,x2_value],bins=10, stacked=True)
#([array([16., 23., 27., 22., 13., 22., 18., 21., 18., 20.]),
#  array([39., 46., 44., 35., 33., 47., 41., 42., 33., 40.])],
# array([140. , 143.9, 147.8, 151.7, 155.6, 159.5, 163.4, 167.3, 171.2,
#        175.1, 179. ]),

五、饼状图 pie()

pyplot.pie(x, explode=None, labels=None, colors=None, autopct=None)

例如,我们将大小设置为 (5,5),定义饼的标签,每个标签所占的数量,绘制饼图。

plt.rcParams['figure.figsize'] = (5,5)
labels = ['娱乐','育儿','饮食','房贷','交通','其它']
​x = [200,500,1200,7000,200,900]
​plt.pie(x,labels=labels)
#[Text(1.09783,0.0690696,'娱乐'),
#  Text(1.05632,0.30689,'育儿'),
#  Text(0.753002,0.801865,'饮食'),
#  Text(-1.06544,-0.273559,'房贷'),
#  Text(0.889919,-0.646564,'交通'),
#  Text(1.05632,-0.30689,'其它')])

1. 百分比显示 percentage

labels = ['娱乐','育儿','饮食','房贷','交通','其它']
​x = [200,500,1200,7000,200,900]
​plt.title("饼图示例-8月份家庭支出")
​plt.pie(x,labels=labels,autopct='%.2f%%')
#[Text(1.09783,0.0690696,'娱乐'),
#  Text(1.05632,0.30689,'育儿'),
#  Text(0.753002,0.801865,'饮食'),
#  Text(-1.06544,-0.273559,'房贷'),
#  Text(0.889919,-0.646564,'交通'),
#  Text(1.05632,-0.30689,'其它')],
# [Text(0.598816,0.0376743,'2.00%'),
#  Text(0.576176,0.167395,'5.00%'),
#  Text(0.410728,0.437381,'12.00%'),
#  Text(-0.58115,-0.149214,'70.00%'),
#  Text(0.48541,-0.352671,'2.00%'),
#  Text(0.576176,-0.167395,'9.00%')])

2. 饼状图的分离

labels = ['娱乐','育儿','饮食','房贷','交通','其它']
x = [200,500,1200,7000,200,900]
​explode = (0.03,0.05,0.06,0.04,0.08,0.21)
​plt.pie(x,labels=labels,autopct='%3.2f%%',explode=explode)

3. 设置饼状图百分比和文本距离中心位置

labels = ['娱乐','育儿','饮食','房贷','交通','其它']
​x = [200,500,1200,7000,200,900]
​explode = (0.03,0.05,0.06,0.04,0.08,0.1)
​plt.pie(x,labels=labels,autopct='%3.2f%%',explode=explode, labeldistance=1.35, pctdistance=1.2)

4. 图例

labels = ['娱乐','育儿','饮食','房贷','交通','其它']
​x = [200,500,1200,7000,200,900]
​explode = (0.03,0.05,0.06,0.04,0.08,0.1)
​plt.pie(x,labels=labels,autopct='%3.2f%%',explode=explode, labeldistance=1.35, pctdistance=1.2)
plt.legend()

可以通过设置 x,y 的刻度一样,使其饼图为正圆 plt.axis(‘equal’)。

总结

到此这篇关于Python利用Matplotlib绘制柱状图(竖直柱状图和水平柱状图)、直方图和饼状图的文章就介绍到这了,更多相关Matplotlib柱状图、直方图和饼状图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文