第十九章 python 数据可视化 Matplotlib Pygal
python 数据可视化
- 一、通过Matplotlib创建图表
-
-
-
- 在使用Matplotlib绘制图表时遇到中文显示异常的小方框问题
-
-
-
-
- 相关知识点
-
-
-
- 安装Matplotlib软件包
-
-
-
- 使用Matplotlib进行基础图表绘制(利用plot函数)
-
(1)单线条折线图表
-
(2)多线条折线图表
- 5. 管理图例
- 6. 管理坐标轴
- 7. 管理多个子图
-
二、功能丰富的数据图
-
-
- 1. 饼图(pie())
- 2. 柱状图(bar())
- 3. 水平柱状图(barh())
- 4. 散点图(scatter())
- 5. 等高线图(contour())
- 6. 3D图形(plot_surface())
-
-
通过使用 Py gal 工具创建数据分析可视化图表。
首先,请安装 Python 中的 Py gal 库以获取数据分析可视化的能力。
学习如何利用 Py gal 进行基本的数据可视化操作与分析方法。
详细设置和配置 Py gal 的数据可视化图表,请注意其中柱状图的具体实现可通过调用 py gal.Bar() 函数来完成。
- 第四章 Pygal支持的主要图表类型
-
第一种类型为折线可视化,由模块pygal.Lin()实现
- 第二种类型是水平条形图表与水平折线图表,分别由模块pygal.HorizontalBar()提供实现
- 第三种类型则包括叠加条形图表与叠加折线图表,可使用模块pygal.StackedBar()创建
- 第四种图形为饼形分布展示,功能由模块pygal.Pie负责
- 第五种为离散点分布图形,可通过模块pygal.Dot生成
- 第六种是指示表显示格式,实现功能依赖于模块pygal.Gauge
- 最后一种主要应用于多变量分析,由模块py gal.Radar创建雷达型分布曲线
-
五、处理数据
-
-
- 1. CSV文件格式
- 2. JSON数据
- 3. 数据清洗
- 4. 读取网络数据
-
-
一、使用Matplotlib生成数据图
1. matplotlib画图中文乱码小方框的解决方法
链接:<>
链接:<>
采用新宋体的细明字体格式设计;
采用细明字体制作的普通文本元素;
使用标楷体作为标准书法艺术字体样式;
应用黑底显示的Hei系统字体作为主要视觉元素;
采用系统默认的SimSun字体风格作为背景元素;
采用NSimSun版本的新颖宋体样式作为界面主体元素;
模仿传统宋体风格的设计方案用于文本显示部分。
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['simhei']
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
plt.rcParams['font.sans-serif']=['KaiTi']
plt.rcParams['axes.unicode_minus'] = False
# 使用Matplotlib的字体管理器加载中文字体
my_font=fm.FontProperties(fname="C:\Windows\Fonts\msyh.ttf")
plt.legend(labels=['疯狂Java讲义年销量', '疯狂Android讲义年销量'],
loc='lower right', prop=my_font)
2. 知识点
pyplot子模块下的plot()函数
color :颜色
linewidth :宽度
linestyle :样式(线)
linestyle 折现样式:
- -:代表实线,这是默认值。
- –:代表虚线。
- ::代表点线。
- -.:代表短线、点相间的虚线。
通过调用 legend() 函数 可以 实现 图形中的图例 显示。
该 handles 参数将被用来 对应 地 引用 每一条 折现;
此 labels 参数则指定 每一条 折现对应的 图例 文本;
在 fontproperties 赋值后 的 结果 中 ,字体管理器将成功 加载 中文字体。
loc参数:指定图例的添加位置,支持如下参数值:
算法自动优化图像的位置参数设置为最佳值。
右上方放置图例以增强视觉效果。
左上方放置图例有助于突出重点区域。
左下方放置图例可以用于显示数据的低值部分。
右下方放置图例适合展示高值区域。
右边布局可以使图例更加醒目。
将图例置于左中心位置有助于平衡整体布局。
将图例置于右中心位置可以突出右侧内容。
底部居中位置放置图例便于阅读对比。
将图例置于顶部居中位置可以突出主标题信息。
prop属性指定使用中文字体。
x_label(xlable)函数用于设定X轴标签
y_label(ylabel)函数用于设定Y轴标签
figure_title(title)函数用于设定图表的整体标题
x-axis_values(xticks)函数用于调整X轴刻度线的位置及标记(特别地,在此实现中支持以文本形式指定刻度标记)
y-axis_values(yticks)函数用于调整Y轴刻度线的位置及标记(特别地,在此实现中支持以文本形式指定刻度标记)
gca()函数用于获取当前绘图区域的坐标轴信息对象,并对其实施控制。
使用ax.xaxis.set_ticks_position('bottom')命令可将x轴主刻度线位于数据域底部位置。
类似地,在y方向上使用ax.yaxis.set_ticks_position('left')将y方向上的刻度置于数据域左侧。
通过ax.spines['right'].set_color('none')这一操作可将右侧边线的颜色设为空,并相应地将其从绘图中移除。
同理,在顶部方向上也执行同样的操作以隐藏顶部边线。
最后设定底边线位于数据域中7×1e4的位置。
通过调用subplot()函数可以创建一个子图,并随后可以在该子图中进行绘图操作。 subplot(nrows, ncols, index, **kwargs)函数用于生成布局并指定位点绘区。其中: nrows参数用于指示数据图表区域被划分为多少行; ncols参数用于指示数据图表区域被划分为多少列; index参数用于确定索引对应的绘区位置。
使用GridSpec对绘图区域进行分割。
3. 安装Matplotlib包
使用pip安装matplotlib库
使用pip添加matplotlib库,并指定--user选项下载自用文件夹中的包
以python脚本方式执行pip安装matplotlib库
pydoc 查看文档
python -m pydoc -p 8899
4. Matplotlib数据图入门(折线图plot())
pyplot子模块下的plot()函数
(1)单条折线图
代码如下:
import matplotlib.pyplot as plt
# 定义2个列表分别作为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)
plt.plot(y_data)
# 调用show()函数显示图形
plt.show()

(2)多条折线图
代码如下:
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义2个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
# 传入2组分别代表X轴、Y轴的数据
#plt.plot(x_data, y_data, x_data, y_data2)
plt.plot(x_data, y_data)
plt.plot(x_data, y_data2)
# 调用show()函数显示图形
plt.show()

color :颜色
linewidth :宽度
linestyle :样式(线)
linestyle 折现样式:
- -:代表实线,这是默认值。
- –:代表虚线。
- ::代表点线。
- -.:代表短线、点相间的虚线。
代码如下:
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义2个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
plt.plot(x_data, y_data, color = 'red', linewidth = 2.0, linestyle = '--')
plt.plot(x_data, y_data2, color = 'blue', linewidth = 3.0, linestyle = '-.')
# 调用show()函数显示图形
plt.show()

5. 管理图例
通过调用legend()函数生成图表的图例
handles列表中的第一个元素用于获取图表中每条线条的数据;
列表参数(labels)表示各条折线所对应的图例;该字体属性被设置为‘字体位置’:表示系统正在加载指定的中文 fonts。
loc参数:指定图例的添加位置,支持如下参数值:
- ‘best’:自动选择最佳位置。
- 'upper right,:将图例放在右上角。
- ‘upper left’:将图例放在左上角。
- ‘lower left’:将图例放在左下角。
- ‘lower right’:将图例放在右下角。
- ‘right’:将图例放在右边。
- ‘centerleft’:将图例放在左边居中的位置。
- ‘centerright’:将图例放在右边居中的位置。
- 'lowercenter*:将图例放在底部居中的位置。
- 'uppercenter*:将图例放在顶部居中的位置。
- ‘center’:将图例放在中心。
prop属性指定使用中文字体。
代码如下:
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义2个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [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_data2, color = 'blue', linewidth = 3.0, linestyle = '-.')
import matplotlib.font_manager as fm
# 使用Matplotlib的字体管理器加载中文字体
my_font=fm.FontProperties(fname="C:\Windows\Fonts\msyh.ttf")
# 调用legend函数设置图例
#plt.legend(handles=[ln2, ln1], labels=['疯狂Android讲义年销量', '疯狂Java讲义年销量'],
# loc='lower right', prop=my_font)
plt.legend(labels=['疯狂Java讲义年销量', '疯狂Android讲义年销量'],
loc='lower right', prop=my_font)
# 调用show()函数显示图形
plt.show()

代码如下:
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义2个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
plt.plot(x_data, y_data, color = 'red', linewidth = 2.0,
linestyle = '--', label='疯狂Java讲义年销量')
plt.plot(x_data, y_data2, color = 'blue', linewidth = 3.0,
linestyle = '-.', label='疯狂Android讲义年销量')
import matplotlib.font_manager as fm
# 使用Matplotlib的字体管理器加载中文字体
my_font=fm.FontProperties(fname="C:\Windows\Fonts\SimHei_0.ttf")
# 调用legend函数设置图例
plt.legend(loc='best', prop=my_font)
# 调用show()函数显示图形
plt.show()

6. 管理坐标轴
xlabel() 函数指定 X 轴标签
代码如下:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义2个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
plt.plot(x_data, y_data, color = 'red', linewidth = 2.0,
linestyle = '--', label='疯狂Java讲义年销量')
plt.plot(x_data, y_data2, color = 'blue', linewidth = 3.0,
linestyle = '-.', label='疯狂Android讲义年销量')
# 调用legend函数设置图例
plt.legend(loc='best')
# 设置两条坐标轴的名字
plt.xlabel("年份")
plt.ylabel("图书销量(本)")
# 设置数据图的标题
plt.title('疯狂图书的历年销量')
# 设置Y轴上的刻度值
# 第一个参数是点的位置,第二个参数是点的文字提示
plt.yticks([50000, 70000, 100000],
[r'挺好', r'优秀', r'火爆'])
# 调用show()函数显示图形
plt.show()

gca()函数用于获取当前坐标系的相关信息对象,并对坐标系执行必要的控制操作
设置X轴刻度显示在底部位置
设定Y轴刻度位于左侧位置
移除右侧边线并使其不可见
移除顶部边线并使其不可见
将底部边线放置于数据值70000的位置
代码如下:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义2个列表分别作为两条折线的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
# 指定折线的颜色、线宽和样式
plt.plot(x_data, y_data, color = 'red', linewidth = 2.0,
linestyle = '--', label='疯狂Java讲义年销量')
plt.plot(x_data, y_data2, color = 'blue', linewidth = 3.0,
linestyle = '-.', label='疯狂Android讲义年销量')
import matplotlib.font_manager as fm
# 使用Matplotlib的字体管理器加载中文字体
my_font=fm.FontProperties(fname="C:\Windows\Fonts\msyh.ttf")
# 调用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轴的刻度值放在底部X轴上
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()

7. 管理多个子图
使用matplotlib.pyplot.subplots()函数生成一个子图框架后,在该子图上进行数据可视化操作即可完成绘图任务。该函数通过以下参数配置实现布局控制:
nrows参数用于指定将绘图区域垂直划分为多少个部分;ncols参数用于指定将绘图区域水平划分为多少个部分;index参数则用于确定具体选择哪一个划分后的区域进行绘制。
代码如下:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
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()

第一个图占用两个网格
代码如下:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
plt.figure()
# 定义从-pi到pi之间的数据,平均取64个数据点
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True) # ①
# 将整个figure分成两行一列,第三个参数表示该图形放在第1个网格
plt.subplot(2, 1, 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分成两行两列,并将该图形放在第4个网格
plt.subplot(223)
# 绘制余弦曲线
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分成两行两列,并该图形放在第4个网格
plt.subplot(224)
# 绘制正切曲线
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()

使用GridSpec对绘图区域进行分割。
代码如下:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.gridspec as gridspec
plt.figure()
# 定义从-pi到pi之间的数据,平均取64个数据点
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True) # ①
# 将绘图区域分成2行3列
gs = gridspec.GridSpec(2, 3)
# 指定ax1占用第一行(0)整行
ax1 = plt.subplot(gs[0, :])
# 指定ax1占用第二行(1)的第一格(第二个参数0代表)
ax2 = plt.subplot(gs[1, 0])
# 指定ax1占用第二行(1)的第二、三格(第二个参数0代表)
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['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()

二、功能丰富的数据图
1. 饼图(pie())
pie()函数绘制饼图
绘制数据为x(其中x的数据来源于data)。在图表中添加分类标签:labels。为了强调Python项目的特殊性,在图形元素中使用了explode参数进行突出显示。定义饼块颜色样式:colors,并将其格式化为保留三位小数百分比数值 autopct=’%.3f%%’ 。调整百分比数字与圆心的距离比例为pctdistance=0.8 。设定各标签与圆心的距离值 labeldistance = 1.15 。指定起始角度位置 startangle = 180度 。设定坐标轴范围 center=(4,4) 和半径 radius=3.8 。决定扇区走向方向 counterclock=False ,表示按顺时针方向排列扇区片段。配置扇区边框属性 wedgeprops={‘linewidth’:1, ‘edgecolor’:’green’} 。设定文本标注格式 textprops={‘fontsize’:12, ‘color’:’black’} 。选择是否展示圆环框架 frame=1 ,这里选择展示状态
代码如下:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
# 准备数据
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', '其他']
# 将第4个语言(Python)分离出来
explode = [0, 0, 0, 0.3, 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.15, # 设置标签与圆心的距离
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('2018年8月的编程语言指数排行榜')
# 显示图形
plt.show()

2. 柱状图(bar())
柱形图重叠
bar()函数绘制柱形图
透明度参数设置为介于0和1之间的数值。
text()函数用于在数据可视化图表中标注文字内容。
其中前两个参数用于确定标注文字的位置坐标,
第三个参数则决定了标注的文字内容。
关于Y坐标的设置中,
条柱的数值正好位于其高度位置,
若将其Y坐标设定为条柱数值加100,
则会将标注文字放置在其上方一定位置。
水平方向对齐采用'center'选项,
垂直方向对齐选择'bottom'方式。
代码如下:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
# 构建数据
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='疯狂Java讲义', color='steelblue', alpha=0.8)
plt.bar(x=x_data, height=y_data2, label='疯狂Android讲义', 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("Java与Android图书对比")
# 为两条坐标轴设置名称
plt.xlabel("年份")
plt.ylabel("销量")
# 显示图例
plt.legend()
plt.show()

柱形图不重叠(width参数)
代码如下:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
# 构建数据
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='疯狂Java讲义',
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='疯狂Android讲义', color='indianred', alpha=0.8, width=bar_width)
plt.bar(x=np.arange(len(x_data))+bar_width+0.05, height=y_data2,
label='疯狂Android讲义', 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')
# 为X轴设置刻度值
plt.xticks(np.arange(len(x_data))+bar_width/2, x_data)
# 设置标题
plt.title("Java与Android图书对比")
# 为两条坐标轴设置名称
plt.xlabel("年份")
plt.ylabel("销量")
# 显示图例
plt.legend()
plt.show()

3. 水平柱状图(barh())
barh()函数生成水平柱状图
代码如下:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
# 构建数据
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='疯狂Java讲义',
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='疯狂Android讲义', 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("Java与Android图书对比")
# 为两条坐标轴设置名称
plt.xlabel("销量")
plt.ylabel("年份")
# 显示图例
plt.legend()
plt.show()

4. 散点图(scatter())
scatter()函数绘制散点图
常用参数:
-
x:指定X轴数据。
-
y:指定F轴数据。
-
s:指定散点的大小。
-
c:指定散点的颜色。
-
alpha:指定散点的透明度。
-
linewidths:指定散点边框线的宽度。
-
edgecolors:指定散点边框的颜色。
-
marker:指定散点的图形样式。
-
该参数支持:
- ‘.’(点标记)
- ‘,’ (像素标记)
- ‘o’ (圆形标记)
- ‘v’ (向下三角形标记)
- ‘^’(向上三角形标记)
- ‘<’ (向左三角形标记)
- ‘>’(向右三角形标记)
- 1 (向下三叉标记)
- 2 (向上三叉标记)
- 3 (向左三叉标记)
- 4 (向右三叉标记)
- ‘s’(正方形标记)
- ‘p’(五边形标记)
- '* '(星形标记)
- ‘h’ (八边形标记)
- 'H '(另一种八边形标记)
- ‘+’(加号标记)
- ‘x’ (x标记)
- ‘D’ (菱形标记)
- ‘d’(尖菱形标记)
- ‘|’ (竖线标记)
- ‘_’(横线标记)等值。
-
cmap:指定散点的颜色映射,会使用不同的颜色来区分散点的值。
代码如下:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
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', # 设置点的颜色
#plt.scatter(x_data, np.sin(x_data), cmap=plt.get_cmap('rainbow'), # 设置点的颜色
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()

5. 等高线图(contour())
contour()函数绘制等高线,contourf()函数为等高线图填充颜色
绘制等高线图所需的三维数据中,在其中x和y轴的数据决定了坐标的点位置,此外,在每个坐标点上还需要对应的高度数值(相当于z轴数值),以确定其高度位置。
在调用contour()、contourf()函数时可以指定如下常用参数。
x轴数据用于确定
y轴数值用于确定
对应位置的高度值
颜色设置
等高线透明度调节
颜色映射设置
线宽设定
样式选择
代码如下:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
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)
# 为等高线图填充颜色, 16指定将等高线分为几部分
plt.contourf(x, y, Z, 16, alpha = 0.75,
cmap='rainbow') # 使用颜色映射来区分不同高度的区域
# 绘制等高线
C = plt.contour(x, y, Z, 16,
colors = 'black', # 指定等高线的颜色
linewidth = 0.5) # 指定等高线的线宽
# 绘制等高线数据
plt.clabel(C, inline = True, fontsize = 10)
# 去除坐标轴
plt.xticks(())
plt.yticks(())
# 设置标题
plt.title("等高线图")
# 为两条坐标轴设置名称
plt.xlabel("纬度")
plt.ylabel("经度")
plt.show()

6. 3D图形(plot_surface())
Axes3D对象的plot_surface()方法
代码如下:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
plt.rcParams['font.sans-serif']=['simhei']
plt.rcParams['axes.unicode_minus'] = False
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)
# 绘制3D图形
ax.plot_surface(X, Y, Z,
rstride=1, # rstride(row)指定行的跨度
cstride=1, # cstride(column)指定列的跨度
cmap=plt.get_cmap('rainbow')) # 设置颜色映射
# 设置Z轴范围
ax.set_zlim(-2, 2)
# 设置标题
plt.title("3D图")
plt.show()

三、使用Pygal生成数据图
1. 安装Pygal包
pip install Pygal --user -i https://pypi.douban.com/simple
2. Pygal数据图入门
使用Pygal生成数据图的步骤大致如下。
①创建Pygal数据图对象。Pygal为不同的数据图提供了不同的类,比如柱状图使用pygal.Bar类,饼图使用pygaLPie类,折线图使用pygal.Line类,等等。
②调用数据图对象的add()方法添加数据。
③调用Config对象的属性配置数据图。
④调用数据图对象的render_to_xxx()方法将数据图渲染到指定的输出节点一此处的输出节点可以是PNG图片、SVG文件,Ml可以是其他节点。
代码如下:
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义2个列表分别作为两组柱状图的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
# 创建pygal.Bar对象(柱状图)
bar = pygal.Bar()
# 添加两组代表条柱的数据
bar.add('疯狂Java讲义', y_data)
bar.add('疯狂Android讲义', y_data2)
## 设置X轴的刻度值
#bar.x_labels = x_data
#bar.title = '疯狂图书的历年销量'
## 设置X、Y轴的标题
#bar.x_title = '年份'
#bar.y_title = '销量'
# 指定将数据图输出到SVG文件中
bar.render_to_file('fk_books.svg')

3. 配置Pygal数据图(柱状图(pygal.Bar()))
pygal.Bar()类来表示柱状图
设置X轴的刻度标签:bar.x_labels
将图表标题设为:bar.title
将X轴刻度标签旋转指定角度:bar.x_label_rotation以角度单位表示
将图表图例放置于底部位置:bar.legend_at_bottom
设定数据图表四周的页边距为固定数值大小:bar.margin = 30
隐藏图表中指定轴上的网格线:bar.show_x_guides = False
代码如下:
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定义2个列表分别作为两组柱状图的Y轴数据
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
# 创建pygal.Bar对象(柱状图)
bar = pygal.Bar()
# 添加两组代表条柱的数据
bar.add('疯狂Java讲义', y_data)
bar.add('疯狂Android讲义', 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
# 隐藏X轴上的网格线
bar.show_y_guides=False
# 显示X轴上的网格线
bar.show_x_guides=True
# 指定将数据图输出到SVG文件中
bar.render_to_file('fk_books.svg')

四、Pygal支持的常见数据图
1. 折线图(pygal.Lin())
pygal.Lin类来表示折线图
代码如下:
import pygal
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]
# 创建pygal.Line对象(折线图)
line = pygal.Line()
# 添加两组代表折线的数据
line.add('疯狂Java讲义', y_data)
line.add('疯狂Android讲义', 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('fk_books.svg')

2. 水平柱状图和水平折线图(pygal.HorizontalBar())
使用pygal.HorizontalBar类来表示水平柱状图
代码如下:
import pygal
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]
# 创建pygal.HorizontalBar对象(水平柱状图)
horizontal_bar = pygal.HorizontalBar()
# 添加两组数据
horizontal_bar.add('疯狂Java讲义', y_data)
horizontal_bar.add('疯狂Android讲义', 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('fk_books1.svg')

3. 叠加柱状图和叠加折线图(pygal.StackedBar())
代码如下:
import pygal
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]
# 创建pygal.StackedBar对象(叠加柱状图)
stacked_bar = pygal.StackedBar()
# 添加两组数据
stacked_bar.add('疯狂Java讲义', y_data)
stacked_bar.add('疯狂Android讲义', 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.x_title = '销量'
stacked_bar.y_title = '年份'
# 设置将图例放在底部
stacked_bar.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
stacked_bar.render_to_file('fk_books.svg')

4. 饼图(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')

5. 点图(pygal.Dot)
代码如下:
import pygal
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]
# 创建pygal.Dot对象(点图)
dot = pygal.Dot()
dot.dots_size = 5
# 添加两组数据
dot.add('疯狂Java讲义', y_data)
dot.add('疯狂Android讲义', y_data2)
# 设置X轴的刻度值
dot.x_labels = x_data
# 重新设置Y轴的刻度值
dot.y_labels = ['疯狂Java讲义', '疯狂Android讲义']
# 设置Y轴刻度值的旋转角度
dot.y_label_rotation = 45
dot.title = '疯狂图书的历年销量'
# 设置X轴的标题
dot.x_title = '年份'
# 设置将图例放在底部
dot.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
dot.render_to_file('fk_books.svg')

6. 仪表图(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('language_percent.svg')

7 . 雷达图(pygal.Radar)
代码如下:
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')

五、处理数据
1. CSV文件格式
通过导入csv模块的方式实现文件的读取。
①通过调用模块导入函数生成读取器对象。
③依次调用循环结构中的迭代器调用对象invoke next()方法以获取每一行的数据内容。
每次操作会返回一个列表类型的数据结构
其中每个元素对应着单元格中的具体信息
代码如下:
import csv
filename = 'guangzhou-2017.csv'
# 打开文件
with open(filename) as f:
# 创建cvs文件读取器
reader = csv.reader(f)
# 读取第一行,这行是表头数据。
header_row = next(reader)
print(header_row)
# 读取第二行,这行是真正的数据。
first_row = next(reader)
print(first_row)
代码如下:
import csv
from datetime import datetime
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif']=['KaiTi']
plt.rcParams['axes.unicode_minus'] = False
filename = 'guangzhou-2017.csv'
# 打开文件
with open(filename) as f:
# 创建cvs文件读取器
reader = csv.reader(f)
# 读取第一行,这行是表头数据。
header_row = next(reader)
print(header_row)
# 定义读取起始日期
start_date = datetime(2017, 6, 30)
# 定义结束日期
end_date = datetime(2017, 8, 1)
# 定义3个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()
# 设置右边坐标轴线的颜色(设置为none表示不显示)
ax.spines['right'].set_color('none')
# 设置顶部坐标轴线的颜色(设置为none表示不显示)
ax.spines['top'].set_color('none')
plt.show()

代码如下:
import csv
import pygal
filename = 'guangzhou-2017.csv'
# 打开文件
with open(filename) as f:
# 创建cvs文件读取器
reader = csv.reader(f)
# 读取第一行,这行是表头数据。
header_row = next(reader)
print(header_row)
# 准备展示的数据
shades, sunnys, cloudys, rainys = 0, 0, 0, 0
for row in reader:
if '阴' in row[3]:
shades += 1
elif '晴' in row[3]:
sunnys += 1
elif '云' in row[3]:
cloudys += 1
elif '雨' in row[3]:
rainys += 1
else:
print(row[3])
# 创建pygal.Pie对象(饼图)
pie = pygal.Pie()
# 为饼图添加数据
pie.add("阴", shades)
pie.add("晴", sunnys)
pie.add("多云", cloudys)
pie.add("雨", rainys)
pie.title = '2017年广州天气汇总'
# 设置将图例放在底部
pie.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
pie.render_to_file('guangzhou_weather.svg')

2. JSON数据
世界各国历年GDP总和,数据来源于https://datahub.io网站。数据格式如下:
[{"Country Code": "ARB", "Country Name": "Arab World",
"Value": 25760683041.0857, "Year": 1968},
{"Country Code": "ARB", "Country Name": "Arab World",
"Value": 28434203615.4829, "Year": 1969},
···
改写说明
使用Python的json模块读取JSON数据极为简便。通过调用json.load()函数即可完成数据加载。以下代码展示了如何获取中国2016年的GDP数据:
代码如下:
import json
filename = 'gdp_json.json'
with open(filename) as f:
gpd_list = json.load(f)
# 遍历列表的每个元素,每个元素是一个GDP数据项
for gpd_dict in gpd_list:
# 只显示中国、2016年的GDP
if gpd_dict['Year'] == 2016 and gpd_dict['Country Code'] == 'CHN':
print(gpd_dict['Country Name'], gpd_dict['Value'])
收集从2001年到2016年间中国、美国、日本及俄罗斯这五个国家的GDP数据,并通过柱状图展示其变化趋势
代码如下:
import json
import matplotlib.pyplot as plt
import numpy as np
# 用来正常显示中文标签,SimHei是字体名称,字体必须再系统中存在,字体的查看方式和安装第三部分
plt.rcParams['font.sans-serif']=['SimHei']
# 用来正常显示负号
plt.rcParams['axes.unicode_minus']=False
filename = 'gdp_json.json'
# 读取JSON格式的GDP数据
with open(filename) as f:
gpd_list = json.load(f)
# 使用list列表依次保存中国、美国、日本、俄罗斯、加拿大的GDP值
country_gdps = [{}, {}, {}, {}, {}]
country_codes = ['CHN', 'USA', 'JPN', 'RUS', 'CAN']
# 遍历列表的每个元素,每个元素是一个GDP数据项
for gpd_dict in gpd_list:
for i, country_code in enumerate(country_codes):
# 只读取指定国家的数据
if gpd_dict['Country Code'] == country_code:
year = gpd_dict['Year']
# 只读取2001年到2016
if 2017 > year > 2000:
country_gdps[i][year] = gpd_dict['Value']
# 使用list列表依次保存中国、美国、日本、俄罗斯、加拿大的GDP值
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, 8))
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()

可从 https://datahub.io 网站获取各国人口数据后即可计算出各国家的人均GDP值。该程序将利用Pygal技术来呈现各国人均GDP的数据图表。
代码如下:
import json
import pygal
filename = 'gdp_json.json'
# 读取JSON格式的GDP数据
with open(filename) as f:
gpd_list = json.load(f)
pop_filename = 'population-figures-by-country.json'
# 读取JSON格式的人口数据
with open(pop_filename) as f:
pop_list = json.load(f)
# 使用list列表依次保存美国、日本、俄罗斯、加拿大的人均GDP值
country_mean_gdps = [{}, {}, {}, {}]
country_codes = ['USA', 'JPN', 'RUS', 'CAN']
# 遍历列表的每个元素,每个元素是一个GDP数据项
for gpd_dict in gpd_list:
for i, country_code in enumerate(country_codes):
# 只读取指定国家的数据
if gpd_dict['Country Code'] == country_code:
year = gpd_dict['Year']
# 只读取2001年到2016
if 2017 > year > 2000:
for pop_dict in pop_list:
# 获取指定国家的人口数据
if pop_dict['Country_Code'] == country_code:
# 使用该国GDP总值除以人口数量,得到人均GDP
country_mean_gdps[i][year] = round(gpd_dict['Value']
/ pop_dict['Population_in_%d' % year])
# 使用list列表依次保存美国、日本、俄罗斯、加拿大的人均GDP值
country_mean_gdp_list = [[], [], [], []]
# 构建时间数据
x_data = range(2001, 2017)
for i in range(len(country_mean_gdp_list)):
for year in x_data:
country_mean_gdp_list[i].append(country_mean_gdps[i][year])
# 定义国家名称列表
countries = ['美国', '日本', '俄罗斯', '加拿大']
# 创建pygal.Bar对象(柱状图)
bar = pygal.Bar()
# 采用循环添加代表条柱的数据
for i in range(len(countries)):
bar.add(countries[i], country_mean_gdp_list[i])
bar.width=1100
# 设置X轴的刻度值
bar.x_labels = x_data
bar.title = '2001到2016年各国人均GDP对比'
# 设置X、Y轴的标题
bar.x_title = '年份'
bar.y_title = '人均GDP(美元)'
# 设置X轴的刻度值旋转45度
bar.x_label_rotation = 45
# 设置将图例放在底部
bar.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
bar.render_to_file('mean_gdp.svg')

3. 数据清洗
若仔细查阅前面介绍展示2017年广州天气情况的相关程序时会发现最后仅统计到363个天气数据点其中雨量级包含雨日164日晴量级涵盖晴日67日阴量级包括阴日24日以及多云量级共计多云日108例然而全年共计应有365个自然日在观察过程中未涵盖全部日期这导致所得数据出现偏差
当程序使用Python进行数据展示时,经常发现数据存在以下两种情况。
- 数据丢失。
- 数据格式错误。
当出现数据丢失的情形时(注释:此处省略补充说明),该系统应输出相应的报告;而当遇到数据格式出错的情况时(同样省略),该系统应跳过这些出错的数据进行后续处理,并记录这些错误信息以便后续处理。
代码改进,如下:
import csv
import pygal
from datetime import datetime
from datetime import timedelta
filename = 'guangzhou-2017.csv'
# 打开文件
with open(filename) as f:
# 创建cvs文件读取器
reader = csv.reader(f)
# 读取第一行,这行是表头数据。
header_row = next(reader)
print(header_row)
# 准备展示的数据
shades, sunnys, cloudys, rainys = 0, 0, 0, 0
prev_day = datetime(2016, 12, 31)
for row in reader:
try:
# 将第一列的值格式化为日期
cur_day = datetime.strptime(row[0], '%Y-%m-%d')
description = row[3]
except ValueError:
print(cur_day, '数据出现错误')
else:
# 计算前、后两天数据的时间差
diff = cur_day - prev_day
# 如果前、后两天数据的时间差不是相差一天,说明数据有问题
if diff != timedelta(days=1):
print('%s之前少了%d天的数据' % (cur_day, diff.days - 1))
prev_day = cur_day
if '阴' in description:
shades += 1
elif '晴' in description:
sunnys += 1
elif '云' in description:
cloudys += 1
elif '雨' in description:
rainys += 1
else:
print(description)
# 创建pygal.Pie对象(饼图)
pie = pygal.Pie()
# 为饼图添加数据
pie.add("阴", shades)
pie.add("晴", sunnys)
pie.add("多云", cloudys)
pie.add("雨", rainys)
pie.title = '2017年广州天气汇总'
# 设置将图例放在底部
pie.legend_at_bottom = True
# 指定将数据图输出到SVG文件中
pie.render_to_file('guangzhou_weather.svg')
>>> ['Date', 'Max TemperatureC', 'Min TemperatureC', 'Description', 'WindDir', 'WindForce']
>>> 2017-03-06 00:00:00之前少了2天的数据
4. 读取网络数据
之前已经讲解了Python的网络支持库:urllib。该库中的request模块允许用户轻松地向远程发送HTTP请求,并接收服务器返回的数据。基于此原理,本程序采用urllib.request模块向lishi.tianqi.com发送HTTP请求的方式,并利用其中接收到的数据进行处理。随后运用Python中的正则表达式模块re来进行数据解析,在提取所需信息时实现了自动化流程。
本程序将通过网络获取来自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 *
# 定义一个函数读取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('gbk')
# 定义3个list列表作为展示的数据
dates, highs, lows = [], [], []
city = 'guangzhou'
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('<divclass="tqtongji2">(.*?)</div><divstyle="clear:both">')
table = re.findall(patten, text)
patten1 = re.compile('<ul>(.*?)</ul>')
uls = re.findall(patten1, table[0])
for ul in uls:
# 定义解析天气信息的正则表达式
patten2 = re.compile('<li>(.*?)</li>')
lis = re.findall(patten2, ul)
# 解析得到日期数据
d_str = re.findall('>(.*?)</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()
# 设置右边坐标轴线的颜色(设置为none表示不显示)
ax.spines['right'].set_color('none')
# 设置顶部坐标轴线的颜色(设置为none表示不显示)
ax.spines['top'].set_color('none')
plt.show()
在该程序的绘图代码主要部分上,并未体现出明显的差异。然而,在该程序中出现过最显著的变化的是其前半部分的代码。值得注意的是,在读取本地CSV文件时,该程序采用了不使用csv模块的新方法。
该程序调用urllib.request获取lishi.tianqi.com网站的天气数据。程序中①号代码创建了一个get_html()函数用于捕获指定网站的HTML内容。
接下来, 程序采用循环结构依次处理从01到12月份的数据, 每次获取一个月度对应的响应页面. 程序提取了每个回应页面对应的HTML代码段落, 这些文件内容中包含了天气信息的相关原始代码片段, 如图19.37所示.
在程序的第一部分, 第一条加粗的关键字代码块利用正则表达式匹配并提取了包含全部天气信息的主要weather information container元素. 其中图中的标记号为①的部分对应的就是该 weather information container.
在程序运行过程中(运行时),第二行代码通过正则表达式识别出天气<div.../>无属性的<ul.../>元素(如图19.37所示)。这些特定位置上的<ul.../>标记点共有多个实例(例如数字2标注的位置),每个这样的标记点对应一天内的天气数据信息。因此,在上述算法设计中(设计思路),采用了循环机制来逐一处理这些标记点以获取完整的天气数据信息集。
该程序在第三行将加粗标记应用于正则表达式以匹配每日天气数据中的li元素。例如,在图19.37中标记为数字3的li元素。每个ul.../ul〉内部包含六个不同的li.../li〉标签对但在这些标签对中仅提取日期、最高温度和最低温度数值因此在提取天气信息时该程序只关注前三个相关的列表项
通过网络和正则表达式收集数据后, 程序将利用Matplotlib库生成可视化图表以展示这些信息. 在执行该程序后, 请查看如图19.38所示的数据可视化结果.


