Python为数据展示提供了大量优秀的功能包,其中Matplotlib和Pygal是两个极具代表性的功能包。
一、使用Matplotlib生成数据图
Matplotlib是一个非常优秀的Python 2D 绘图库,只要给出符合格式的数据,通过Matplotlib就可以方便地制作折线图、柱状图、散点图等各种高质量的数据图。
(一)、安装Matplotlib包
pip安装
pip install matplotlib
(二)Matplotlib数据图入门
Matplotlib的用法非常简单,对于最简单的折线图来说, 程序只需根据需要给出对应的X 轴、Y 轴数据, 调用pyplot 子模块下的plot()函数即可生成简单的折线图。
示例
import matplotlib.pyplot as plt
# 定义两个列表分别作为X轴、Y轴数据
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
# 第一个列表代波啊横坐标的值,第二个列表代表纵坐标的值
plt.plot(x_data, y_data)
# 调用show()函数显示图形
plt.show()
运行效果:
如果在调用plot()函数时只传入一个list列表,则该列表的数据将作为y轴数据,Matplotlib会自动使用0, 1, 2, 3作为X轴数据。
效果如下图
plot()函数除了支持创建具有单挑折线的折线图,也支持创建包含多条折线的复式折线图,只要在调用plot()函数时传入多个分别代表x轴和y轴数据的list列表即可。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 传入两组分别代表X轴,Y轴的数据的list列表
plt.plot(x_data, y_data, x_data, y_data1)
# 调用show()函数显示图形
plt.show()
运行效果:
也可以将以上代码中的 `` plt.plot(x_data, y_data, x_data, y_data1) ```改为多次调用plot()的方式:
plt.plot(x_data, y_data)
plt.plot(x_data, y_data1)
同样可以在调用plot()函数时传入额外的参数来指定折线的样子、如线宽、颜色、样式等。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
plt.plot(x_data, y_data, color='red', linewidth=2.0, linestyle='--')
plt.plot(x_data, y_data1, color='blue', linewidth=3.0, linestyle='-.')
# 调用show()函数显示图形
plt.show()
运行效果:
样式字符串支持如下参数值:
参数值 | 描述 |
---|---|
- | 代表实线,默认值 |
– | 代表虚线 |
: | 代表点线 |
-. | 代表短线、点相间的虚线 |
(三)管理图例
可以通过legend()函数来为折线添加图例,为该函数传入两个list参数,其中第一个list参数(handles参数)用于引用折线图上的每条折线,第二个list参数(labels)代表为每条折线所添加的图例。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
ln1, = plt.plot(x_data, y_data, color='red', linewidth=2.0, linestyle='--')
ln2, = plt.plot(x_data, y_data1, color='blue', linewidth=3.0, linestyle='-.')
# 调用legend()函数设置图例
plt.legend(handles=[ln2, ln1],
labels=['示例2年销售量', '示例1年销售量'],
loc='lower right')
# 调用show()函数显示图形
plt.show()
运行效果:
以上代码中的loc参数指定图例添加位置,该参数支持如下参数值:
参数值 | 描述 |
---|---|
best | 自动选择最佳位置 |
upper right | 将图例放在右上角 |
upper left | 将图例放在左上角 |
lower left | 将图例放在左下角 |
lower right | 将图例放在右下角 |
right | 将图例放在右边 |
center left | 将图例放在左边居中的位置 |
center right | 将图例放在右边居中的位置 |
lower center | 将图例放在底部居中的位置 |
upper center | 将图例放在顶部居中的位置 |
center | 将图例放在中心 |
中文乱码解决方案
① 使用matplotlib.font_manager子模块下的FontProperties类加载中文字体。
② 在调用legend()函数时通过prop属性指定使用中文字体。
示例
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
ln1, = plt.plot(x_data, y_data, color='red', linewidth=2.0, linestyle='--')
ln2, = plt.plot(x_data, y_data1, color='blue', linewidth=3.0, linestyle='-.')
# 使用Matplotlib的字体管理器加载中文字体
my_font = fm.FontProperties(fname="C:\Windows\Fonts\msyh.ttc")
# 调用legend()函数设置图例
plt.legend(handles=[ln2, ln1],
labels=['示例2年销售量', '示例1年销售量'],
loc='lower right',
prop=my_font)
# 调用show()函数显示图形
plt.show()
运行效果:
以上程序使用FontProperties类加载c:\windows\Fonts\msyh.ttc文件所对应的中文字体。
legend()函数可以不指定handles参数,只传入labels参数,这样该labels参数将按顺序为直线图中的多条折线添加图例。
Matplotlib也允许在调用plot()函数时为每条折线分别传入label参数,这样程序在调用legend()函数时就无须传入labels、handles参数了。
永久改变Matplotlib的默认字体
在Python的交互解释器中输入如下命令:
编辑配置文件,找到如下行:
将此行代码修改为如下形式,并去掉前面的#号:
(四)管理坐标轴
可以调用xlable()和ylabel()函数分别设置X轴、Y轴的名称,也可以通过title()函数设置整个数据图的标题,还可以调用xticks()、yticks()函数分别改变X轴、Y轴的刻度值(允许使用文本作为刻度值)。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
plt.plot(x_data,
y_data,
color='red',
linewidth=2.0,
linestyle='--',
label='图例1年销量')
plt.plot(x_data,
y_data1,
color='blue',
linewidth=3.0,
linestyle='-.',
label='图例2年销量')
# 调用legend()函数设置图例
plt.legend(loc='best')
# 设置两个坐标轴的名称
plt.xlabel("年份")
plt.ylabel("销量")
# 设置数据图的标题
plt.title("历年销量图")
# 设置Y轴上的数值文本
# 第一个参数是点的位置,第二个参数是点的文字提示
plt.yticks([50000, 70000, 100000], [r'挺好', r'优秀', r'火爆'])
# 调用show()函数显示图形
plt.show()
运行效果:
若要对X轴、Y轴进行更细致的控制,可以调用gca()函数来获取坐标轴信息对象,然后对坐标轴进行控制。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
plt.plot(x_data,
y_data,
color='red',
linewidth=2.0,
linestyle='--',
label='图例1年销量')
plt.plot(x_data,
y_data1,
color='blue',
linewidth=3.0,
linestyle='-.',
label='图例2年销量')
# 调用legend()函数设置图例
plt.legend(loc='best')
# 设置两个坐标轴的名称
plt.xlabel("年份")
plt.ylabel("销量")
# 设置数据图的标题
plt.title("历年销量图")
# 设置Y轴上的数值文本
# 第一个参数是点的位置,第二个参数是点的文字提示
plt.yticks([50000, 70000, 100000], [r'挺好', r'优秀', r'火爆'])
ax = plt.gca()
# 设置将x轴的刻度值放在底部X轴上
ax.xaxis.set_ticks_position('bottom')
# 设置将Y轴的刻度值放在左边Y轴上
ax.yaxis.set_ticks_position('left')
# 设置右边坐标轴线的颜色(设置为none表示不显示)
ax.spines['right'].set_color('none')
# 设置顶部坐标轴线的颜色(设置为none表示不显示)
ax.spines['top'].set_color('none')
# 定义底部坐标轴线的位置(放在70000数值处)
ax.spines['bottom'].set_position(('data', 70000))
# 调用show()函数显示图形
plt.show()
运行效果:
以上代码中使用plt.gca()获取了一个AxesSubplot对象,然后调用该对象的xaxis属性的set_ticks_position()方法设置X轴刻度值的位置。通过spines属性可以访问数据图四周的坐标轴线(Spine对象)
(五)管理多个子图
使用Matplotlib 除可以生成包含多条折线的复式折线图之外,它还允许在一张数据图上包含多个子图。
调用subplot()函数可以创建一个子图,然后程序就可以在子图上进行绘制。subplot(nrows, ncols, mdex, **kwargs)函数的时ows 参数指定将数据图区域分成多少行; ncols 参数指定将数据图区域分成多少列: index参数指定获取第几个区域。
示例
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
# 定义从-pi到pi之间的数据,平均去64个数据点
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True)
# 将整个figure分成两行两列,第三个参数表示将该图形放在第1个网格中
plt.subplot(2, 2, 1)
# 绘制正弦曲线
plt.plot(x_data, np.sin(x_data))
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('正弦曲线')
# 将整个figure分成两行两列,并将该图形房子啊第2个网格中
plt.subplot(222)
# 绘制余弦曲线
plt.plot(x_data, np.cos(x_data))
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('余弦曲线')
# 将整个figure分成两行两列,并将该图形放在第3个网格中
plt.subplot(223)
# 绘制正切曲线
plt.plot(x_data, np.tan(x_data))
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('正切曲线')
plt.show()
运行效果:
还可以让某个子图占用多个网格,例如将以上代码中的plt.subplot(2, 2, 1)
改为 plt.subplot(2, 1, 1)
,然后依次修改另外两个子图的位置。
还可以使用GridSpec对绘图区域进行分割。
示例
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
plt.figure()
# 定义从-pi到pi之间的数据,平均去64个数据点
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True)
# 将绘图区域分成两行三列
gs = gridspec.GridSpec(2, 3)
# 指定ax1占用第一行(0)整行
ax1 = plt.subplot(gs[0, :])
# 指定ax2占用第二行(1)的第一格(第二个参数0代表)
ax2 = plt.subplot(gs[1, 0])
# 指定ax3占用第二行(1)的第二、三格(第二个参数用1:3代表)
ax3 = plt.subplot(gs[1, 1:3])
# 绘制正弦曲线
ax1.plot(x_data, np.sin(x_data))
ax1.spines['right'].set_color('none')
ax1.spines['top'].set_color('none')
ax1.spines['bottom'].set_position(('data', 0))
ax1.spines['left'].set_position(('data', 0))
ax1.set_title('正弦曲线')
# 绘制余弦曲线
ax2.plot(x_data, np.cos(x_data))
ax2.spines['right'].set_color('none')
ax2.spines['top'].set_color('none')
ax2.spines['bottom'].set_position(('data', 0))
ax2.spines['left'].set_position(('data', 0))
ax2.set_title('余弦曲线')
# 绘制正切曲线
ax3.plot(x_data, np.tan(x_data))
ax3.spines['right'].set_color('none')
ax3.spines['top'].set_color('none')
ax3.spines['bottom'].set_position(('data', 0))
ax3.spines['left'].set_position(('data', 0))
ax3.set_title('正切曲线')
plt.show()
运行效果:
功能丰富的数据图
(一)饼图
使用Matplotlib提供的pie() 函数来绘制饼图。
示例数据表 TIOBE2019年6月编程语言指数排行榜前10名
语言 | 排名 |
---|---|
Java | 15.004% |
C | 13.300% |
Python | 8.530% |
C++ | 7.384% |
Visual Basic.NET | 4.624% |
C# | 4.483% |
JavaScript | 2.716% |
PHP | 2.567% |
SQL | 2.224% |
Assembly language | 1.479% |
饼图示例
import matplotlib.pyplot as plt
# 准备数据
data = [
0.15004, 0.13300, 0.08530, 0.07384, 0.04624, 0.04483, 0.02716, 0.02567,
0.02224, 0.01479, 0.37689
]
# 准备标签
labels = [
'Java', 'C', 'Python', 'C++', 'Visual Basic.NET', 'C#', 'JavaScript',
'PHP', 'SQL', 'Assembly language', '其他'
]
# 将排在第3位的语言(Python)分离出来
explode = [0, 0, 0.3, 0, 0, 0, 0, 0, 0, 0, 0]
# 使用自定义颜色
colors = ['red', 'pink', 'magenta', 'purple', 'orange']
# 将横、纵坐标轴标准化处理,保证饼图是一个正圆,否则为椭圆
plt.axes(aspect='equal')
# 控制X轴和Y轴的范围(用于控制饼图的圆心、半径)
plt.xlim(0, 8)
plt.ylim(0, 8)
# 绘制饼图
plt.pie(x=data, # 绘图数据
labels=labels, # 添加编程语言标签
explode=explode, # 突出显示Python
colors=colors, # 设置饼图的自定义填充色
autopct='%.3f%%', # 设置百分比的格式,此处保留3位小数
pctdistance=0.8, # 设置百分比标签与圆心的距离
labeldistance=1.05, # 设置标签与圆心的距离
startangle=180, # 设置饼图的初始角度
center=(4, 4), # 设置饼图的圆心(相当于X轴和Y轴的范围)
radius=3.8, # 设置饼图的半径(相当于X轴和Y轴的范围
counterclock=False, # 是否为逆时针方向,这里为顺时针
wedgeprops={
'linewidth': 1,
'edgecolor': 'green'
}, # 设置饼图内外边界的属性值
textprops={
'fontsize': 12,
'color': 'black'
}, # 设置文本标签的属性值
frame=1) # 是否显示饼图的圆圈,此处设置为显示
# 不显示X轴和Y轴的刻度值
plt.xticks(())
plt.yticks(())
# 添加图形标题
plt.title('TIOBE2019年6月编程语言指数排行榜前10名')
# 显示图形
plt.show()
运行效果:
(二)柱状图
使用Matplotlib提供的bar()函数来绘制柱状图。与前面介绍的plot()函数类似, 程序每次调用bar()函数时都会生成一组柱状图, 如果希望生成多组柱状图,则可通过多次调用bar()函数来实现。
示例
import matplotlib.pyplot as plt
# 构建数据
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]
# 绘图
plt.bar(x=x_data, height=y_data, label='产品1', color='steelblue', alpha=0.8)
plt.bar(x=x_data, height=y_data2, label='产品2', 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("产品对比")
# 为两个坐标轴设置名称
plt.xlabel("年份")
plt.ylabel("销量")
# 显示图例
plt.legend()
plt.show()
运行效果:
使用bar()函数绘制柱状图时,默认不会在柱状图上显示具体的数值。程序可以通过调用text()函数在数据图上输出文字。text()函数前两个参数控制输出文字的X、Y坐标,第三个参数控制输出的内容,va控制文字的垂直对齐方式,ha控制文字的水平对齐方式。
如果不希望两组数据重叠在一起,那么就需要对X轴进行设置,因为两组柱状图使用的是同一组list列表数据,为了将多个柱状图的条柱并列显示,程序需要为这些柱状图重新计算不同的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='产品1',
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='产品2',
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('产品对比')
# 为两个坐标轴设置名称
plt.xlabel("年份")
plt.ylabel("销量")
# 显示图例
plt.legend()
plt.show()
运行效果:
以上程序有一个不足之处,就是X轴的刻度值变成了0,1,2……而不再显示年份,为了让柱状图的X轴刻度显示年份,可以调用xticks()函数重新设置X轴的刻度值。如:
plt.xticks(np.arange(len(x_data)) + bar_width/2, x_data)
(三)水平柱状图
调用Matplotlib的barh()函数可以生成水平柱状图。barh()函数的用法与bar()函数的用法基本一样,只是在调用barh()函数时使用y 参数传入Y 轴数据,使用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
# Y轴数据使用range(len(x_data)),也就是0、1、2、……
plt.barh(y=range(len(x_data)),
width=y_data,
label='产品1',
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='产品2',
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("产品比较")
# 为两个坐标轴设置名称
plt.xlabel("销量")
plt.ylabel("年份")
# 显示图例
plt.legend()
plt.show()
运行效果
(四)散点图
实际上,散点图和折线图类似,区别是折线图会将各个点用线连接起来,而散点图不会。调用Matplotlib的scatter()函数可以绘制散点图,该函数接收如下参数:
- x:指定X轴数据。
- y:指定Y轴数据。
- s:指定散点的大小。
- c:指定散点的颜色。
- alpha:指定散点的透明度。
- linewidths:指定散点边框线的宽度。
- edgecolors:指定散点边框的颜色。
- marker:指定散点的图形样式。
- cmap:指定散点的颜色映射,会使用不同的颜色来区分散点的值。
散点样式表
样式字符 | 样式 |
---|---|
‘.’ | 点标记 |
‘,’ | 像素标记 |
‘o’ | 圆形标记 |
‘v’ | 向下三角形标记 |
‘^’ | 向上三角形标记 |
‘<’ | 向左三角形标记 |
‘>’ | 向右三角形标记 |
‘1’ | 向下三叉标记 |
‘2’ | 向上三叉标记 |
‘3’ | 向左三叉标记 |
‘4’ | 向右三叉标记 |
‘s’ | 正方形标记 |
‘p’ | 五边形标记 |
‘*’ | 星号标记 |
‘h’ | 八边形标记 |
‘H’ | 另一种八边形标记 |
‘+’ | 加号标记 |
‘x’ | x标记 |
‘D’ | 菱形标记 |
‘d’ | 尖菱形标记 |
‘|’ | 竖线标记 |
‘_’ | 横线标记 |
示例
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
# 定义从-pi到pi之间的数据,平均取64个数据点
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True)
# 将整个figure分成两行两列,第三个参数表示将图形放在第1个网格中
# 沿着正弦曲线绘制散点图
plt.scatter(x_data,
np.sin(x_data),
c='purple',
s=50,
alpha=0.5,
marker='p',
linewidths=1,
edgecolors=['green', 'yellow'])
# 绘制第二个散点图(只包含一个起点),突出起点
plt.scatter(x_data[0], np.sin(x_data)[0], c='red', s=150, alpha=1)
# 绘制第三个散点图(只包含一个结束点),突出结束点
plt.scatter(x_data[63], np.sin(x_data)[63], c='black', s=150, alpha=1)
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('正弦曲线的散点图')
plt.show()
运行效果:
(五)等高线图
等高线图需要三维数据,其中X、Y轴数据决定坐标点,还需要对应的高度数据(相当于Z轴)来决定不同坐标点的高度。程序调用contour()函数绘制等高线,调用contourf()函数为等高线图填充颜色。
contour()、contourf()函数常用参数如下:
- X:指定X轴数据
- Y:指定Y轴数据
- Z:指定X、Y坐标对应点的高度数据
- colors:指定不同高度的等高线的颜色
- alpha:指定等高线的透明度
- cmap:指定登高线的颜色映射,即自动使用不同的颜色来区分不同的高度区域
- linewidths:指定等高线的宽度
- linestyles:指定等高线的样式
示例
import matplotlib.pyplot as plt
import numpy as np
delta = 0.025
# 生成代表x轴数据的列表
x = np.arange(-3.0, 3.0, delta)
# 生成代表y轴数据的列表
y = np.arange(-2.0, 2.0, delta)
# 对X、y数据进行网格化
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
# 计算Z轴数据(高度数据)
Z = (Z1 - Z2) * 2
# 为等高线图填充颜色,16指定将等高线分为几部分
plt.contourf(x, y, Z, 16, alpha=0.75, cmap='rainbow') # 使用颜色映射来区分不同高度的区域
# 绘制等高线
c = plt.contour(x, y, Z, 16, colors='black', linewidths=0.5)
# 绘制等高线数据
plt.clabel(c, inline=True, fontsize=10)
# 去除坐标轴
plt.xticks(())
plt.yticks(())
# 设置标题
plt.title('等高线图')
# 为两个坐标轴设置名称
plt.xlabel("纬度")
plt.ylabel("经度")
plt.show()
运行效果:
以上代码中要注意一个地方,很多书里都将c = plt.contour(x, y, Z, 16, colors='black', linewidths=0.5)
中的linewidths写成了linewidth。
(六)3D图形
调用Axes3D对象的plot_surface()方法来绘制3D图形。
示例
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(12, 8))
ax = Axes3D(fig)
delta = 0.125
# 生成代表X轴数据的列表
x = np.arange(-3.0, 3.0, delta)
# 生成代表Y轴数据的列表
y = np.arange(-2.0, 2.0, delta)
# 对x、y数据进行网格化
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
# 计算Z轴数据(高度数据)
Z = (Z1 - Z2) * 2
# 绘制3D图形
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.get_cmap('rainbow'))
# 设置Z轴范围
ax.set_zlim(-2, 2)
# 设置标题
plt.title("3D图")
plt.show()
运行效果:
三、使用Pygal生成数据图
Pygal是另一个简单易用的数据图库,它以面向对象的方式来创建各种数据图,而且使用Pygal可以非常方便地生成各种格式的数据图,包括PNG 、SVG 等。使用Pygal也可以生成XML etree、HTML 表格(这些都需要安装其他包)。
(一)安装Pygal包
pip安装
pip install pygal
查看文档
python -m pydoc -p 8899
(二)Pygal数据图入门
使用Pygal生成数据图步骤如下:
① 创建Pygal数据图对象。有pygal.Bar,pygal.Pie,Pygal.Line等对象类型。
② 调用数据图对象的add()方法添加数据。
③ 调用Config对象的属性配置数据图。
④ 调用数据图对象的render_to_xxx()方法将数据图渲染到指定的输出节点——可以是PNG图片、SVG文件等。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两组柱状图的Y轴数据
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 创建pygal.Bar对象
bar = pygal.Bar()
# 添加两组代表条柱的数据
bar.add('产品1', y_data)
bar.add('产品2', y_data2)
# 设置X轴的刻度值
bar.x_labels = x_data
bar._title = '产品历年销售量'
# 设置X,Y轴的标题
bar._x_title = '年份'
bar._y_title = '销量'
# 指定将数据图输出到SVG文件中
bar.render_to_file('pygal_bar_test.svg')
运行后生成pygal_bar_test.svg文件,用浏览器打开效果如下:
(三)配置Pygal数据图
Pygal模块下有一个config模块,该模块包含了BaseConfig、CommonConfig、Config、SerieConfig等配置类。
部分配置属性示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两组柱状图的Y轴数据
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 创建pygal.Bar对象(柱状图)
bar = pygal.Bar()
# 添加两组代表条柱的数据
bar.add('产品1', y_data)
bar.add('产品2', y_data2)
# 设置X轴的刻度值
bar.x_labels = x_data
bar.title = '产品历年销量'
# 设置X、Y轴的标题
bar.x_title = '年份'
bar.y_title = '销量'
# 设置X轴的刻度值旋转45°
bar.x_label_rotation = 45
# 设置将图例放在底部
bar.legend_at_bottom = True
# 设置数据图四周的页边距
# 也可通过margin_bottom、margin_left、margin_right、margin_top只设置单独一边的页边距
bar.margin = 35
# 隐藏Y轴上的网络线
bar.show_y_guides = False
# 显示X轴上的网格线
bar.show_x_guides = True
# 指定将数据图输出到SVG文件中
bar.render_to_file('pygal_bar_config.svg')
pygal_bar_config.svg文件效果:
四、Pygal支持的常见数据图
(一)折线图
使用pygal.Line 类来表示折线图,程序创建pygal.Line对象就是创建折线图。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两组柱状图的Y轴数据
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 创建pygal.Line对象(折线图)
line = pygal.Line()
# 添加两组代表折线的数据
line.add('产品1', y_data)
line.add('产品2', y_data2)
# 设置X轴的刻度值
line.x_labels = x_data
# 重新设置Y轴的刻度值
line.y_labels = [20000, 40000, 60000, 80000, 100000]
line._title = '产品历年销量'
# 设置X,Y轴的标题
line.x_title = '年份'
line.y_title = '销量'
# 设置将图例放在底部
line.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
line.render_to_file('pygal_line_test.svg')
SVG图形效果:
(二)水平柱状图和水平折线图
使用pygal.HorizontalBar类来表示水平柱状图。使用pygal.HorizontalBar生成水平柱状图的步骤与创建普通柱状图的步骤基本相同。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两组柱状图的Y轴数据
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 创建pygal.HorizontalBar对象
horizontal_bar = pygal.HorizontalBar()
# 添加两组数据
horizontal_bar.add('产品1', y_data)
horizontal_bar.add('产品2', y_data2)
# 设置Y轴的刻度值
horizontal_bar.x_labels = x_data
# 重新设置X轴的刻度值
horizontal_bar.y_labels = [20000, 40000, 60000, 80000, 100000]
horizontal_bar._title = '产品历年销量'
# 设置X、Y轴的标题
horizontal_bar.x_title = '销量'
horizontal_bar.y_title = '年份'
# 设置将图例放在底部
horizontal_bar.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
horizontal_bar.render_to_file('pygal_horizontal_bar_test.svg')
SVG效果图:
与水平柱状图类似的还有水平折线图,水平折线图使用pygal.HorizontalLine 类来表示,水平折线图的X 轴刻度值同样使用y_labels属性来设置,而Y轴刻度值才使用x_labels属性来设置。
(三)叠加柱状图和叠加折线图
叠加柱状图使用pygal.StackedBar 类来表示,程序使用pygal.StackedBar 创建叠加柱状图的步骤与创建普通柱状图的步骤基本相同。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两组柱状图的Y轴数据
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 创建pygal.StackedBar对象
stacked_bar = pygal.StackedBar()
# 添加两组数据
stacked_bar.add('产品1', y_data)
stacked_bar.add('产品2', y_data2)
# 设置X轴的刻度值
stacked_bar.x_labels = x_data
# 重新设置Y轴的刻度值
stacked_bar.y_labels = [20000, 40000, 60000, 80000, 100000]
stacked_bar.title = '产品历年销量'
# 设置X、Y轴的标题
stacked_bar.y_title = '年份'
stacked_bar.x_title = '销量'
# 设置将图例放在底部
stacked_bar.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
stacked_bar.render_to_file('pygal_stacked_bar_test.svg')
SVG效果图:
(四)饼图
Pygal提供了pygal.Pie 类来支持饼图,支持如下两个特有的属性。
- inner_radius:设置饼图内圈的半径。通过设置该属性可以实现环形数据图。
- half_pie:将该属性设置为True,可以实现半圆的饼图。
示例
import pygal
# 准备数据
data = [
0.16881, 0.14966, 0.07471, 0.06992, 0.04762, 0.03541, 0.02925, 0.02411,
0.02316, 0.01409, 0.36326
]
# 准备标签
labels = [
'Java', 'C', 'C++', 'Python', 'Visual Basic.NET', 'c#', 'PHP',
'JavaScript', 'SQL', 'Assembly langugage', '其它'
]
# 创建pygal.Pie对象
pie = pygal.Pie()
# 采用循环为饼图添加数据
for i, per in enumerate(data):
pie.add(labels[i], per)
pie.title = '2018年8月编程语言排行'
# 设置将图例放在底部
pie.legend_at_bottom = True
# 设置内圈的半径长度
pie.inner_radius = 0.4
# 创建班员数据图
pie.half_pie = True
# 指定将数据图输出到SVG文件中
pie.render_to_file('language_percent.svg')
SVG效果图:
(五)点图
点图使用点( 圆) 的大小来表示数值的大小。Pygal 使用pygal.Dot 类表示点图,创建点图的方式与创建柱状图的方式基本相同。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义两个列表分别作为两组柱状图的Y轴数据
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 创建pygal.Dot对象
dot = pygal.Dot()
dot.dots_size = 5
# 添加两组数据
dot.add('产品1', y_data)
dot.add('产品2', y_data2)
# 设置X轴的刻度值
dot.x_labels = x_data
# 重新设置Y轴的刻度值
dot.y_labels = ['产品1', '产品2']
# 设置Y轴刻度值的旋转角度
dot.y_label_rotation = 45
dot.title = '产品历年销量'
# 设置X轴的标题
dot.x_title = '年份'
# 设置将图例放在底部
dot.legend_at_bottom = True
# 指定将数据图输出的SVG文件中
dot.render_to_file('pygal_dot_test.svg')
SVG效果图:
(六)仪表(Gauge)图
仪表图类似于一个仪表盘,在仪表盘内使用不同的指针代表不同的数据。Pygal使用pygal.Gauge类表示仪表图。程序在创建pygal.Gauge对象之后,为pygal.Gauge 对象添加数据的方式与为pygal.Pie对象添加数据的方式相似。pygal.Gauge对象有一个特别的属性:range ,该属性用于指定仪表图的最小值和最大值。
示例
import pygal
# 准备数据
data = [
0.16881, 0.14966, 0.07471, 0.06992, 0.04762, 0.03541, 0.02925, 0.02411,
0.02316, 0.01409, 0.36326
]
# 准备标签
labels = [
'Java', 'C', 'C++', 'Python', 'Visual Basic.NET', 'c#', 'PHP',
'JavaScript', 'SQL', 'Assembly langugage', '其它'
]
# 创建pygal.Gauge对象
gauge = pygal.Gauge()
gauge.range = [0, 1]
# 采用循环为仪表图添加数据
for i, per in enumerate(data):
gauge.add(labels[i], per)
gauge.title = '2018年8月编程语言'
# 设置将图例放在底部
gauge.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
gauge.render_to_file('pygal_gauge_test.svg')
SVG效果图:
(七)雷达图
雷达图适合用于分析各对象在不同维度的优势和劣势,通过雷达图可对比每个对象在不同维度的得分。
假如我们从下表所示的5个方面(平台健壮性、语法易用性、社区活跃度、市场份额和未来趋势)的得分来评价各编程语言的优势。
平台健壮性 | 语法易用性 | 社区活跃度 | 市场份额 | 未来趋势 | |
---|---|---|---|---|---|
Java | 5 | 4.0 | 5 | 5 | 5 |
C | 4.8 | 2.8 | 4.8 | 4.8 | 4.9 |
C++ | 4.5 | 2.9 | 4.6 | 4.0 | 4.9 |
Python | 4.0 | 4.8 | 4.9 | 4.0 | 5 |
C# | 3.0 | 4.2 | 2.3 | 3.5 | 2 |
PHP | 4.8 | 4.3 | 3.9 | 3.0 | 4.5 |
雷达图示例
import pygal
# 准备数据
data = [[5, 4.0, 5, 5, 5], [4.8, 2.8, 4.8, 4.8, 4.9],
[4.5, 2.9, 4.6, 4.0, 4.9], [4.0, 4.8, 4.9, 4.0, 5],
[3.0, 4.2, 2.3, 3.5, 2], [4.8, 4.3, 3.9, 3.0, 4.5]]
# 准备标签
labels = ['Java', 'C', 'C++', 'Python', 'C#', 'PHP']
# 创建pygal.Radar对象
rader = pygal.Radar()
# 采用循环为雷达图添加数据
for i, per in enumerate(labels):
rader.add(labels[i], data[i])
rader.x_labels = ['平台健壮性', '语法易用性', '社区活跃度', '市场份额', '未来趋势']
rader.title = '编程语言对比图'
# 控制各得分点的大小
rader.dots_size = 8
# 设置将图例放在底部
rader.legend_at_bottom = True
# 指定将数据图输出的SVG文件中
rader.render_to_file('language_compare.svg')
SVG效果图:
五、处理数据
(一)CSV文件格式
csv文件格式的本质是一种以文本存储的表格数据(使用Excel工具即可读写csv 文件) 。csv文件的每行代表一行数据,每行数据中每个单元格内的数据以逗号隔开。
Python提供了csv模块来读写csv文件。由于csv 文件的格式本身比较简单( 通常第一行是表头,用于说明每列数据的含义, 接下来每行代表一行数据) , 因此使用csv模块读取csv文件也非常简单。
① 创建CSV模块的读取器
② 循环调用CSV读取器的next()方法逐行读取CSV文件内容即可。next()方法返回一个list列表代表一行数据,list列表的每个元素代表一个单元格数据。
CSV数据读取示例
import csv
filename = 'guangzhou-2017.csv'
# 打开文件
with open(filename) as f:
# 创建CSV读取器
reader = csv.reader(f)
# 读取第一行,这行是表头数据
header_row = next(reader)
print(header_row)
# 读取第二行,这行是真正的数据
first_row = next(reader)
print(first_row)
使用Matplotlib结合CSV文件读取展示图表示例
import csv
from datetime import datetime
from matplotlib import pyplot as plt
filename = 'guangzhou-2017.csv'
# 打开文件
with open(filename) as f:
# 创建CSV读取器
reader = csv.reader(f)
# 读取第一行,这行是表头数据
header_row = next(reader)
print(header_row)
# 定义读取起始日期
start_date = datetime(2017, 6, 30)
# 定义读取结束日期
end_date = datetime(2017, 8, 1)
# 定义三个list列表作为展示的数据
dates, highs, lows = [], [], []
for row in reader:
# 将第一列的值格式化为日期
d = datetime.strptime(row[0], '%Y-%m-%d')
# 只展示2017年7月的数据
if start_date < d < end_date:
dates.append(d)
highs.append(int(row[1]))
lows.append(int(row[2]))
# 配置图形
fig = plt.figure(dpi=128, figsize=(12, 9))
# 绘制最高气温的折线
plt.plot(dates,
highs,
c='red',
label='最高气温',
alpha=0.5,
linewidth=2.0,
linestyle='-',
marker='v')
# 绘制最低气温的折线
plt.plot(dates,
lows,
c='blue',
label='最低气温',
alpha=0.5,
linewidth=3.0,
linestyle='-.',
marker='o')
# 为两个数据的绘图区填充颜色
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 设置标题
plt.title("2017年7月广州最高气温和最低气温")
# 为两个坐标轴设置名称
plt.xlabel("日期")
# 该方法绘制歇着的日期标签
fig.autofmt_xdate()
plt.ylabel("气温(℃)")
# 显示图例
plt.legend()
ax = plt.gca()
# 设置右边坐标轴线的颜色
ax.spines['right'].set_color('none')
# 设置顶部坐标轴线的颜色
ax.spines['top'].set_color('none')
plt.show()
运行效果:
使用Pygal结合CSV读取展示数据图示例
import csv
import pygal
filename = 'guangzhou-2017.csv'
# 打开文件
with open(filename) as f:
# 创建CSV读取器
reader = csv.reader(f)
# 读取第一行数据的表头信息
header_row = next(reader)
print(header_row)
# 准备展示的数据
shades, sunys, cloudys, rainys = 0, 0, 0, 0
for row in reader:
if '阴' in row[3]:
shades += 1
elif '晴' in row[3]:
sunys += 1
elif '云' in row[3]:
cloudys += 1
elif '雨' in row[3]:
rainys += 1
else:
print(row[3])
# 创建pygal.pei对象
pie = pygal.Pie()
# 为饼图添加数据
pie.add("阴", shades)
pie.add("晴", sunys)
pie.add("多云", cloudys)
pie.add("雨", rainys)
pie.title = '2017年广州天气汇总'
# 设置图例放在底部
pie.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
pie.render_to_file('pygal_guangzhou_weather.svg')
SVG效果:
(二)JSON数据
示例1
import json
from matplotlib import pyplot as plt
import numpy as np
filename = 'gdp_json.json'
# 读取JSON格式的GDP数据
with open(filename) as f:
gdp_list = json.load(f)
# 使用list列表依次保存中国、美国、日本、俄罗斯、加拿大的GDP值
country_gdps = [{}, {}, {}, {}, {}]
country_codes = ['CHN', 'USA', 'JPN', 'RUS', 'CAN']
# 遍历列表的每个元素,每个元素都是一个GDP数据项
for gdp_dict in gdp_list:
for i, country_code in enumerate(country_codes):
# 只读取指定国家的数据
if gdp_dict['Country Code'] == country_code:
year = gdp_dict['Year']
# 值读取从2001年到2016年的数据
if 2017 > year > 2000:
country_gdps[i][year] = gdp_dict['Value']
country_gdp_list = [[], [], [], [], []]
# 构建时间数据
x_data = range(2001, 2017)
for i in range(len(country_gdp_list)):
for year in x_data:
# 除以1e8,让数值变成以亿为单位
country_gdp_list[i].append(country_gdps[i][year] / 1e8)
bar_width = 0.15
fig = plt.figure(dpi=128, figsize=(15, 9))
colors = ['indianred', 'steelblue', 'gold', 'lightpink', 'seagreen']
# 定义国家名称列表
countries = ['中国', '美国', '日本', '俄罗斯', '加拿大']
# 采用循环绘制5组柱状图
for i in range(len(colors)):
# 使用自定义的X坐标将数据分开
plt.bar(x=np.arange(len(x_data)) + bar_width * i,
height=country_gdp_list[i],
label=countries[i],
color=colors[i],
alpha=0.8,
width=bar_width)
# 仅在中国、美国的条柱上绘制GDP值
if i < 2:
for x, y in enumerate(country_gdp_list[i]):
plt.text(x, y + 100, '%.0f' % y, ha='center', va='bottom')
# 为X轴设置刻度值
plt.xticks(np.arange(len(x_data)) + bar_width * 2, x_data)
# 设置标题
plt.title("从2001年到2016年各国GDP对比")
# 为两个坐标轴设置名称
plt.xlabel("年份")
plt.ylabel("GDP(亿美元)")
# 显示图例
plt.legend()
plt.show()
运行效果:
(三)数据清洗
当程序使用Python 进行数据展示时,经常发现数据存在以下两种情况。
- 数据丢失
- 数据格式错误
对于数据丢失的情况,程序应i亥生成报告:对于数据格式发生错误的情况, 程序应该能略过发生错误的数据,继续处理后面的程序,并报告发生错误的数据。
(四)读取网络数据
示例 爬取并展示http://lishi.tianqi.com站点的数据
import re
from datetime import datetime
from datetime import timedelta
from matplotlib import pyplot as plt
from urllib.request import *
# 定义一个函数读取http://lishi.tianqi.com站点的数据
def get_html(city, year, month):
url = 'http://lishi.tianqi.com/' + city + '/' + str(year) + str(
month) + '.html'
# 创建请求
request = Request(url)
# 添加请求头
request.add_header(
'User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64)' +
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
)
response = urlopen(request)
# 获取服务器响应
return response.read().decode('utf-8')
# 定义三个list列表作为展示的数据
dates, highs, lows = [], [], []
city = 'chongqing'
year = '2018'
months = [
'01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'
]
prev_day = datetime(2017, 12, 31)
# 循环读取每个月的天气数据
for month in months:
html = get_html(city, year, month)
# 将HTML响应拼接起来
text = "".join(html.split())
# 定义包含天气信息的div的正则表达式
patten = re.compile(r'<ulclass="lishitable_contentclearfix">(.*?)</ul>')
table = re.findall(patten, text)
patten1 = re.compile(r'<li.*?>(.*?)</li>')
uls = re.findall(patten1, table[0])
# 去除最后一个包含“查看更多”的<li>
uls = uls[:-1]
for ul in uls:
# 定义解析天气信息的正则表达式
patten2 = re.compile(r'<div.*?>(.*?)</div>')
lis = re.findall(patten2, ul)
print(lis)
# 解析得到日期数据
d_str = re.findall(r'">(.*?)</a>', lis[0])[0]
try:
# 将日期字符串格式化为日期
cur_day = datetime.strptime(d_str, '%Y-%m-%d')
# 解析得到最高气温和最低气温
high = int(lis[1])
low = int(lis[2])
except ValueError:
print(cur_day, '数据出现错误')
else:
# 计算前、后两天数据的时间差
diff = cur_day - prev_day
# 如果前、后两天数据的时间差不是相差一天,则说明数据有问题
if diff != timedelta(days=1):
print('%s之间少了%d天的数据' % (cur_day, diff.days - 1))
dates.append(cur_day)
highs.append(high)
lows.append(low)
prev_day = cur_day
# 配置图形
fig = plt.figure(dpi=128, figsize=(12, 9))
# 绘制最高气温的折线
plt.plot(dates, highs, c='red', label='最高气温', alpha=0.5, linewidth=2.0)
# 绘制最低气温的折线
plt.plot(dates, lows, c='blue', label='最低气温', alpha=0.5, linewidth=2.0)
# 为两个数据的绘图区域填充颜色
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 设置标题
plt.title("%s年重庆最高气温和最低气温" % year)
# 为两个坐标轴设置名称
plt.xlabel("日期")
# 该方法绘制斜着的日期标签
fig.autofmt_xdate()
plt.ylabel("气温(℃)")
# 显示图例
plt.legend()
ax = plt.gca()
# 设置右边坐标线不显示
ax.spines['right'].set_color('none')
# 设置顶部坐标线不显示
ax.spines['top'].set_color('none')
plt.show()
运行效果:
练习
1.使用Matplotlib生成折线图,分析自己在两个月内体重变化与运动时间之间的关系。
import matplotlib.pyplot as plt
# 定义两个列表分别作为X轴、Y轴数据
# Y轴代表运动时间,X轴代表体重
y_data = [
'60分钟', '30分钟', '45分钟', '60分钟', '30分钟', '45分钟', '60分钟', '30分钟', '45分钟',
'60分钟', '30分钟', '45分钟', '60分钟', '30分钟', '45分钟', '60分钟', '30分钟', '45分钟',
'60分钟', '30分钟', '45分钟', '60分钟', '30分钟', '45分钟', '60分钟', '30分钟', '45分钟',
'60分钟', '30分钟', '45分钟'
]
x_data = [
68, 67.5, 67, 66, 66.5, 66, 65.5, 65, 64.5, 64, 64.5, 64, 63.5, 63, 64, 63,
62.5, 62, 61.5, 61, 61.5, 60, 59.5, 59, 58.5, 58, 57.5, 57, 56.5, 56
]
# 第一个列表代表横坐标的值,第二个列表代表纵坐标的值
plt.plot(x_data, y_data)
# 调用show()函数显示图形
plt.show()
2.使用Pygal生成饼图,分析本年度自己在生活、教育学习、健身、旅游、娱乐各方面的时间投入和金钱投入。
import pygal
# 准备数据
data = [191400, 50000, 1000, 30000, 110000]
data1 = [365, 100, 125, 30, 200]
# 准备标签
labels = ['生活', '教育学习', '健身', '旅游', '娱乐']
# 创建pygal.Pie对象
pie = pygal.Pie()
# 采用循环为饼图添加数据
for i, per in enumerate(data):
pie.add(labels[i], per)
pie.title = '2019年消费投入图'
# 设置将图例放在底部
pie.legend_at_bottom = True
# 设置内圈的半径长度
pie.inner_radius = 0.4
# 指定将数据图输出到SVG文件中
pie.render_to_file('my.svg')
# 创建pygal.Pie对象
pie1 = pygal.Pie()
# 采用循环为饼图添加数据
for i, per in enumerate(data1):
pie1.add(labels[i], per)
pie1.title = '2019年时间投入图'
# 设置将图例放在底部
pie1.legend_at_bottom = True
# 设置内圈的半径长度
pie1.inner_radius = 0.5
# 指定将数据图输出到SVG文件中
pie.render_to_file('my1.svg')
3.使用随机数生成5000 个(-3, -3 )~(3,3 )范围的点,并使用散点图绘制它们。
import matplotlib.pyplot as plt
import random
plt.figure()
x_data, y_data = [], []
for i in range(5000):
x_data.append(random.uniform(-3, 3))
for i in range(5000):
y_data.append(random.uniform(-3, 3))
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.scatter(x_data,
y_data,
c='purple',
s=50,
alpha=0.5,
marker='p',
linewidths=1,
edgecolors=['green', 'yellow'])
# 绘制第二个散点图(只包含一个起点),突出起点
plt.scatter(x_data[0], y_data[0], c='red', s=150, alpha=1)
# 绘制第三个散点图(只包含一个结束点),突出结束点
plt.scatter(x_data[4999], y_data[4999], c='black', s=150, alpha=1)
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('随机数的散点图')
plt.show()
4.从https://www.tiobe.com/tiobe-index/网站查找2018年各月Python和Java两门语言的市场份额,并绘制它们的柱状图进行对比。
import csv, pygal
filename = 'exercise\language.csv'
x_data = ['0' + str(i + 1) for i in range(12)]
java_data = [0] * 12
python_data = [0] * 12
# 打开文件
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
for row in reader:
# Java的数据
if row[0] == 'java':
java_data[int(row[2][5:]) - 1] = float(row[1])
# Python的数据
elif row[0] == 'python':
python_data[int(row[2][5:]) - 1] = float(row[1])
bar = pygal.Bar()
bar.add('Java', java_data)
bar.add('python', python_data)
bar.x_labels = x_data
bar.title = '2018年各月Java与Python市场份额对比图'
bar.x_title = '月份'
bar.y_title = '份额'
bar.legend_at_bottom = True
bar.render_to_file('language.svg')
5.从https://datahub.io网站下载世界各国的人口数据,并绘制中国、印度历年人口变化的折线图。
import json
import pygal
pop_filename = 'exercise\\population-figures-by-country.json'
# 读取JSON格式的人口数据
with open(pop_filename) as f:
pop_list = json.load(f)
# 构建时间数据
x_data = range(1970, 2017)
# 使用list列表依次保存中国、印度的人口
country_pops_list = [[], []]
for pop_dict in pop_list:
# 获取中国的人口数据
if pop_dict['Country_Code'] == 'CHN':
for year in x_data:
country_pops_list[0].append(pop_dict['Population_in_%d' % year] /
10000)
# 获取印度的人口数据
if pop_dict['Country_Code'] == 'IND':
for year in x_data:
country_pops_list[1].append(pop_dict['Population_in_%d' % year] /
10000)
# 定义国家名称列表
countries = ['中国', '印度']
# 创建pygal.Bar对象
bar = pygal.Bar()
# 采用循环添加代表条柱的数据
for i in range(len(countries)):
bar.add(countries[i], country_pops_list[i])
bar.width = 1100
# 设置X轴的刻度值
bar.x_labels = x_data
bar.title = '1970-2016年中国印度人口对比'
bar.x_title = '年份'
bar.y_title = '人口(万)'
# 设置X轴的刻度值旋转45度
bar.x_label_rotation = 45
# 设置将图例放在底部
bar.legend_at_bottom = True
# 将数据图输出到文件
bar.render_to_file('population.svg')
6.从http://lishi.tianqi.com网站读取深圳的2017年历史天气数据,并绘制最高气温、最低气温的折线图。
import re
from datetime import datetime
from datetime import timedelta
from matplotlib import pyplot as plt
from urllib.request import *
# 定义一个函数读取http://lishi.tianqi.com站点的数据
def get_html(city, year, month):
url = 'http://lishi.tianqi.com/' + city + '/' + str(year) + str(
month) + '.html'
# 创建请求
request = Request(url)
# 添加请求头
request.add_header(
'User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64)' +
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
)
response = urlopen(request)
# 获取服务器响应
return response.read().decode('utf-8')
# 定义三个list列表作为展示的数据
dates, highs, lows = [], [], []
city = 'shenzhen'
year = '2017'
months = [
'01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'
]
prev_day = datetime(2016, 12, 31)
# 循环读取每个月的天气数据
for month in months:
html = get_html(city, year, month)
# 将HTML响应拼接起来
text = "".join(html.split())
# 定义包含天气信息的div的正则表达式
patten = re.compile(r'<ulclass="lishitable_contentclearfix">(.*?)</ul>')
table = re.findall(patten, text)
patten1 = re.compile(r'<li.*?>(.*?)</li>')
uls = re.findall(patten1, table[0])
# 去除最后一个包含“查看更多”的<li>
uls = uls[:-1]
for ul in uls:
# 定义解析天气信息的正则表达式
patten2 = re.compile(r'<div.*?>(.*?)</div>')
lis = re.findall(patten2, ul)
print(lis)
# 解析得到日期数据
d_str = re.findall(r'">(.*?)</a>', lis[0])[0]
try:
# 将日期字符串格式化为日期
cur_day = datetime.strptime(d_str, '%Y-%m-%d')
# 解析得到最高气温和最低气温
high = int(lis[1])
low = int(lis[2])
except ValueError:
print(cur_day, '数据出现错误')
else:
# 计算前、后两天数据的时间差
diff = cur_day - prev_day
# 如果前、后两天数据的时间差不是相差一天,则说明数据有问题
if diff != timedelta(days=1):
print('%s之间少了%d天的数据' % (cur_day, diff.days - 1))
dates.append(cur_day)
highs.append(high)
lows.append(low)
prev_day = cur_day
# 配置图形
fig = plt.figure(dpi=128, figsize=(12, 9))
# 绘制最高气温的折线
plt.plot(dates, highs, c='red', label='最高气温', alpha=0.5, linewidth=2.0)
# 绘制最低气温的折线
plt.plot(dates, lows, c='blue', label='最低气温', alpha=0.5, linewidth=2.0)
# 为两个数据的绘图区域填充颜色
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 设置标题
plt.title("%s年重庆最高气温和最低气温" % year)
# 为两个坐标轴设置名称
plt.xlabel("日期")
# 该方法绘制斜着的日期标签
fig.autofmt_xdate()
plt.ylabel("气温(℃)")
# 显示图例
plt.legend()
ax = plt.gca()
# 设置右边坐标线不显示
ax.spines['right'].set_color('none')
# 设置顶部坐标线不显示
ax.spines['top'].set_color('none')
plt.show()