生成数据
数据可视化 :通过可视化表示来探索数据
数据挖掘 :使用代码来探索数据集的规律和关联
安装 matplotlib pip pip 是一个以Python写成的软件包管理系统 ,它可以安装和管理软件包 。
大多数较新的Python版本都自带pip,因此首先可检查系统是否已经安装了pip。
在Windows系统中检查是否安装了pip
打开一个终端窗口,并执行如下命令:
1 2 > python -m pip --version pip 20.1.1 from C:\Users\Hunter\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pip (python 3.8)
在 Windows 系统中安装 matplotlib 在Windows系统中,首先需要安装Visual Studio 。接下来,访问matplotlib · PyPI ,查找与使用的Python版本、操作系统相匹配的.whl
文件。
将这个.whl
文件复制到项目所在文件夹 ,打开命令窗口,使用pip来安装matplotlib:
1 python -m pip install --user matplotlib-3.2.2-cp38-cp38-win32.whl
测试 matplotlib 安装必要的包后,对安装进行测试。为此,首先使用命令python或python3启动一个终端会话,再尝试导入matplotlib:
1 2 $ python3 >>> import matplotlib
如果没有出现任何错误消息,就说明成功安装了 matplotlib 。
绘制简单的折线图 我们将使用平方数序列1、4、9、16和25来绘制这个图表。
1 2 3 4 5 6 7 import matplotlib.pyplot as plt%matplotlib inline squares = [1 , 4 , 9 , 16 , 25 ] plt.plot(squares) plt.show()
修改标签文字和线条粗细 上述代码通过matplotlib查看器显示的图形,标签文字太小、线条太细 。下面通过一些定制来改善这个图形的可读性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import matplotlib.pyplot as pltsquares = [1 , 4 , 9 , 16 , 25 ] plt.plot(squares, linewidth=5 ) plt.title("Square Numbers" , fontsize=24 ) plt.xlabel("Value" , fontsize=14 ) plt.ylabel("Square of Value" , fontsize=14 ) plt.tick_params(axis='both' , labelsize=14 ) plt.show()
参数linewidth 决定了plot()
绘制的线条的粗细
函数title()
给图表指定标题
参数fontsize指定了图表中文字的大小
函数xlabel()
和ylabel()
函数tick_params()
设置刻度的样式
校正图形 图形更容易阅读后,我们发现没有正确地绘制数据 :折线图的终点指出4.0的平方为25。下面来修复这个问题。
当你向plot()
提供一系列数字时,它假设第一个数据点对应的x坐标值为0 ,但我们的第一个点对应的x值为1。为改变这种默认行为,我们可以给plot()
同时提供输入值和输出值 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import matplotlib.pyplot as pltinput_values = [1 , 2 , 3 , 4 , 5 ] squares = [1 , 4 , 9 , 16 , 25 ] plt.plot(input_values, squares, linewidth=5 ) plt.title("Square Numbers" , fontsize=24 ) plt.xlabel("Value" , fontsize=14 ) plt.ylabel("Square of Value" , fontsize=14 ) plt.tick_params(axis='both' , labelsize=14 ) plt.show()
使用 scatter()
绘制散点图并设置其样式 有时候,需要绘制散点图 并设置各个数据点的样式 。例如,你可能想以一种颜色显示较小的值 ,用另一种颜色显示较大的值 。绘制大型数据集时,还可以对每个点都设置相同的样式,再使用不同的样式选项重新绘制某些点,以突出它们 。
要绘制简单的点,可使用函数scatter()
,并向它传递一对x和y坐标,它将在指定位置绘制一个点 。
1 2 3 4 import matplotlib.pyplot as pltplt.scatter(2 , 4 ) plt.show()
下面来设置输出的样式 ,使其更有趣:添加标题,给轴加上标签,并确保所有文本都大到能够看清 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import matplotlib.pyplot as pltplt.scatter(2 , 4 , s=200 ) plt.title("Square Numbers" , fontsize=24 ) plt.xlabel("Value" , fontsize=14 ) plt.ylabel("Square of Value" , fontsize=14 ) plt.tick_params(axis='both' , which='major' , labelsize=14 ) plt.legend() plt.show()
plt.scatter(2, 4, s=200)
:实参s设置了 绘制图形时使用的点的尺寸
使用 scatter() 绘制一系列点 要绘制一系列的点,可向scatter()
传递两个分别包含x值和y值的列表 ,如下所示:
1 2 3 4 5 6 7 8 9 import matplotlib.pyplot as pltx_values = [1 , 2 , 3 , 4 , 5 ] y_values = [1 , 4 , 9 , 16 , 25 ] plt.scatter(x_values, y_values, s=100 ) --snip--
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 --snip-- x_values_1 = titanic.query("Sex == 'male' & Age != 'NaN'" )['Age' ] y_values_1 = titanic.query("Sex == 'male' & Age != 'NaN'" )['Fare' ] x_values_2 = titanic.query("Sex == 'female' & Age != 'NaN'" )['Age' ] y_values_2 = titanic.query("Sex == 'female' & Age != 'NaN'" )['Fare' ] plt.scatter(x_values_1, y_values_1, s=10 , c='b' , label='Male' ) plt.scatter(x_values_2, y_values_2, s=10 , c='r' , label='Female' ) titanic.loc[titanic['Sex' ] == 'male' , 'color' ] = 'b' titanic.loc[~(titanic['Sex' ] == 'male' ), 'color' ] = 'r' plt.scatter(titanic['Age' ].dropna(), titanic['Fare' ].dropna(), s=10 , c=titanic[color]) plt.title("船票与年龄" , fontsize=24 ) plt.xlabel("Age" , fontsize=14 ) plt.ylabel("Fare" , fontsize=14 ) plt.legend() plt.show()
可利用query()
排除一些极端值的干扰
1 2 3 gu = grouped_user.sum ().query('order_amount < 6000' ) plt.scatter(gu['order_amount' ], gu['order_products' ])
自动计算数据 下面是绘制1000个点 的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import matplotlib.pyplot as pltx_values = list (range (1 , 1001 )) y_values = [x**2 for x in x_values] plt.scatter(x_values, y_values, s=40 ) plt.title("Square Numbers" , fontsize=24 ) plt.xlabel("Value" , fontsize=14 ) plt.ylabel("Square of Value" , fontsize=14 ) plt.axis([0 , 1100 , 0 , 1100000 ]) plt.show()
由于这个数据集较大,我们将点设置得较小 ,并使用函数axis()
指定了每个坐标轴的取值范围 。
删除数据点的轮廓 matplotlib允许你给散点图中的各个点指定颜色 ,默认为蓝色点 和黑色轮廓 。在散点图包含的数据点不多时效果很好,但绘制很多点时,黑色轮廓可能会粘连在一起 。
要删除数据点的轮廓,可在调用scatter()
时传递实参edgecolor='none'
:
plt.scatter(x_values, y_values, edgecolor='none', s=40)
注意:matplotlib 2.0.0版本之后,scatter()
函数的实参edgecolor默认为 ’none'
。
自定义颜色 要修改数据点的颜色 ,可向scatter()
传递参数c ,并将其设置为要使用的颜色的名称 ,如下所示:
plt.scatter(x_values, y_values, c='red', s=40)
还可以使用RGB颜色模式自定义颜色:
plt.scatter(x_values, y_values, c=(0, 0, 0.8), s=40)
值越接近0,指定的颜色越深,值越接近1,指定的颜色越浅 。
使用颜色映射 颜色映射 (colormap )是一系列颜色,它们从起始颜色渐变到结束颜色 。在可视化中,颜色映射用于突出数据的规律 ,例如你可能用较浅的颜色来显示较小的值,并用较深的颜色来显示较大的值。
模块pyplot内置了一组颜色映射 :
1 2 3 4 5 6 7 8 9 10 import matplotlib.pyplot as pltx_values = list (range (1 , 1001 )) y_values = [x**2 for x in x_values] plt.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Blues, s=40 ) --snip--
我们将参数c设置成了一个y值列表 ,并使用参数cmap告诉pyplot使用哪个颜色映射 。y值较小的点显示为浅蓝色,y值较大的点显示为深蓝色。
注意:要了解pyplot中所有的颜色映射,访问Colormap reference
自动保存图表 要让程序自动将图表保存到文件中 ,可将对plt.show()
的调用替换为对plt.savefig()
的调用:
plt.savefig('suqares_plot.png', bbox_inches='tight')
第一个实参指定要以什么样的文件名保存图表,这个文件将存储到当前程序所在的目录中 。
第二个实参指定将图表多余的空白区域剪掉 。如果要保留图表周围多余的空白区域,可省略这个实参 。
绘制饼图 matplotlib可视化饼图 - 知乎
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 males = (titanic['Sex' ] == 'male' ).sum () females = (titanic['Sex' ] == 'female' ).sum () proportions = [males, females] plt.pie( proportions, labels = ['Males' , 'Females' ], shadow = False , colors = ['blue' , 'red' ], explode = (0.15 , 0.3 ), startangle = 90 , autopct = '%1.1f%%' ) plt.axis('equal' ) plt.title("男女乘客比例" ) plt.tight_layout() plt.show()
随机漫步 随机漫步 是这样行走得到的路径 :每次行走都完全是随机的,没有明确的方向,结果是由一系列随机决策决定的 。在自然界、物理学、生物学、化学和经济领域,随机漫步都有其实际用途。例如,漂浮在水滴上的花粉因不断受到水分子的挤压而在水面上移动。水滴中的分子运动是随机的,因此花粉在水面上的运动路径犹如随机漫步。
创建 RandomWalk() 类 创建一个RandomWalk()
类,这个类需要三个属性:
存储随机漫步次数的变量
随机漫步经过的每个点的x坐标
随机漫步经过的每个点的y坐标
RandomWalk()
类只包含两个方法:
__init__()
fill_walk()
:计算随机漫步经过的所有点
先来看看__init__()
:
1 2 3 4 5 6 7 8 9 10 11 12 from random import choiceclass RandomWalk (): """一个生成随机漫步数据的类""" def __init__ (self, num_points=5000 ): """初始化随机漫步的属性""" self.num_points = num_points self.x_values = [0 ] self.y_values = [0 ]
为做出随机决策,我们将所有可能的选择都存储在一个列表中 ,并在每次做决策时都使用choice()
来决定使用哪种选择 。
选择方向 我们将使用fill_walk()
来生成漫步包含的点,并决定每次漫步的方向,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def fill_walk (self ): """计算随机漫步包含的所有点""" while len (self.x_values) < self.num_points: x_direction = choice([1 , -1 ]) x_distance = choice([0 , 1 , 2 , 3 , 4 ]) x_step = x_direction * x_distance y_direction = choice([1 , -1 ]) y_distance = choice([0 , 1 , 2 , 3 , 4 ]) y_step = y_direction * y_distance if x_step == 0 and y_step == 0 : continue next_x = self.x_values[-1 ] + x_step next_y = self.y_values[-1 ] + y_step self.x_values.append(next_x) self.y_values.append(next_y)
choice([-1, 1])
:从-1和1中随机选择一个值
choice([0, 1, 2, 3, 4])
:从0~4中随机选择一个值
绘制随机漫步图 rw_visual.py :
1 2 3 4 5 6 7 8 9 import matplotlib.pyplot as pltfrom random_walk import RandomWalkrw = RandomWalk() rw.fill_walk() plt.scatter(rw.x_values, rw.y_values, s=15 ) plt.show()
模拟多次随机漫步 要在不多次运行程序的情况下模拟多次随机漫步 ,一种办法是将这些代码放在一个while循环中 ,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import matplotlib.pyplot as pltfrom random_walk import RandomWalkwhile True : rw = RandomWalk() rw.fill_walk() plt.scatter(rw.x_values, rw.y_values, s=15 ) plt.show() keep_running = input ("Make another walk? (y/n): " ) if keep_running == 'n' : break
给点着色 我们将使用颜色映射 来指出漫步中各点的先后顺序 。为根据漫步中各点的先后顺序进行着色,我们传递参数c ,并将其设置为一个列表 ,其中包含各点的先后顺序 。
由于这些点是按顺序绘制的,因此给参数c指定的列表只需包含数字1~5000 :
1 2 3 4 5 6 7 8 9 10 11 12 --snip-- while True : rw = RandomWalk() rw.fill_walk() point_numbers = list (range (rw.num_points)) plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, s=15 ) plt.show() keep_running = input ("Make another walk? (y/n): " ) --snip--
重新绘制起点和终点 1 2 3 4 5 6 7 8 9 10 11 --snip-- while True : --snip-- plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, s=15 ) plt.scatter(0 , 0 , c='green' , s=100 ) plt.scatter(rw.x_values[-1 ], rw.y_values[-1 ], c='red' , s=100 ) plt.show() --snip--
隐藏坐标轴 1 2 3 4 5 6 7 8 9 10 11 --snip-- while True : --snip-- plt.scatter(rw.x_values[-1 ], rw.y_values[-1 ], c='red' , s=100 ) plt.axes().get_xaxis().set_visible(False ) plt.axes().get_yaxis().set_visible(False ) plt.show() --snip--
为修改坐标轴,使用了函数plt.axes()
来将每条坐标轴的可见性设置为False。
增加点数 在创建RandomWalk实例时增大num_points的值,并在绘图时调整每个点的大小 ,如下所示:
1 2 3 4 5 6 7 8 9 10 --snip-- while True : rw = RandomWalk(5000 ) rw.fill_walk() point_numbers = list (range (rw.num_points)) plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, s=1 ) --snip--
调整尺寸以适合屏幕 图表适合屏幕大小时,更能有效地将数据中的规律呈现出来。为让绘图窗口更适合屏幕大小 ,可像下面这样调整matplotlib输出的尺寸 :
1 2 3 4 5 6 7 8 9 --snip-- while True : rw = RandomWalk() rw.fill_walk() plt.figure(figsize=(10 , 6 )) --snip--
函数figure()
用于指定图表的宽度、高度、分辨率和背景色 :
需要给形参figsize
指定一个元组 ,向matplotlib指出绘图窗口的尺寸 ,单位为英寸 。
Python假定屏幕分辨率为80像素/英寸 ,如果知道自己系统的分辨率,可使用形参dpi向figure()
传递该分辨率,以有效利用可用的屏幕空间:
plt.figure(dpi=128, figsize=(10, 6))
使用 Pygal 模拟掷骰子 本节将使用Python可视化包Pygal 来生成可缩放的矢量图形文件 ,它们将自动缩放 ,以适合观看者的屏幕。如果你打算以在线的方式使用图表,请考虑使用Pygal来生成它们,这样在任何设备上显示都会很美观。
在这个项目中,我们将对掷骰子的结果进行分析。为确定哪些点数出现的可能性最大,我们将生成一个表示掷骰子结果的数据集,并根据结果绘制出一个图形 。
安装 Pygal 在 Windows 系统中,命令:
python -m pip install --user pygal==1.7
Paygal 画廊 要了解使用Pygal可创建什么样的图表,可以查看Chart types — pygal documentation
创建 Die 类 下面的类模拟掷一个骰子:
1 2 3 4 5 6 7 8 9 10 11 12 from random import randintclass Die (): """表示一个骰子的类""" def __init__ (self, num_sides=6 ): """骰子默认为6面""" self.num_sides = num_sides def roll (self ): """返回一个位于1和骰子面数之间的随机数""" return randint(1 , self.num_sides)
方法roll()
使用函数randint()
来返回一个1和面数之间的随机整数(包括起始值1和终止值num_sides)
骰子根据面数命名,6面的骰子命名为D6,8面的骰子命名为D8。
掷骰子 使用这个类来创建图表前,先来掷D6骰子,将结果打印出来,并检查结果是否合理:
1 2 3 4 5 6 7 8 9 10 11 12 from die import Diedie = Die() results = [] for roll_num in range (100 ): result = die.roll() results.append(result) print (results)
分析结果 为分析掷一个D6骰子的结果,我们计算每个点数出现的次数 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 --snip-- results = [] for roll_num in range (1000 ): result = die.roll() results.append(result) frequencies = [] for value in range (1 , die.num_sides+1 ): frequency = results.count(value) frequencies.append(frequency) print (frequencies)
为分析结果,我们创建了空列表frequencies,用于存储每种点数出现的次数
绘制条形图(bar chart) 有了频率列表后,我们就可以绘制一个表示结果的条形图(bar chart), 指出各种结果出现的频率 。
利用pygal绘制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import pygal--snip-- frequencies = [] for value in range (1 , die.num_sides+1 ): frequency = results.count(value) frequencies.append(frequency) bar = pygal.Bar() bar.title = "Results of rolling one D6 1000 times." bar.x_labels = ['1' , '2' , '3' , '4' , '5' , '6' ] bar.x_title = "Result" bar.y_title = "Frequency of Result" bar.add('D6' , frequencies) bar.render_to_file('die_visual.svg' )
为创建**条形图(bar diagram)**,创建了一个pygal.Bar()
实例
将D6骰子的可能结果用作x轴的标签
使用add()
将一系列值添加到图表中(传递给添加的值指定的标签 、将出现在图表中的值的列表 )
将图表渲染为一个SVG文件 (Scalable Vector Graphics,可缩放的矢量图形,是一种基于XML 的图像文件格式 )
要查看生成的直方图,最简单的方式是使用Web浏览器。为此,在任意浏览器中新建一个标签页,再打开文件die_visual.svg,将看到对应的图表。
注意:Python让这个图表具有交互性:如果将鼠标指向该图表中的任何条形,将看到与之相关联的数据 (若无效果,刷新)。
绘制直方图(histogram)
利用pyplot绘制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import pandas as pdimport matplotlib.pyplot as pltplt.hist(titanic['Fare' ], bins = range (0 ,600 ,10 )) plt.xlabel('Fare' ) plt.ylabel('Frequency' ) plt.title('船票价格分布' ) plt.show() plt.hist(grouped_user.sum ().query('order_amount < 1000' )['order_amount' ], bins = 20 ) plt.show()
同时掷两个骰子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import pygalfrom die import Diedie_1 = Die() die_2 = Die() results = [] for roll_num in range (1000 ): result = die_1.roll() + die_2.roll() results.append(result) frequencies = [] max_result = die_1.num_sides + die_2.num_sides for value in range (2 , max_result+1 ): frequency = results.count(value) frequencies.append(frequency) bar = pygal.Bar() bar.title = "Results of rolling two D6 dice 1000 times." bar.x_labels = ['2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '10' , '11' , '12' ] bar.x_title = "Result" bar.y_title = "Frequency of Result" bar.add('D6 + D6' , frequencies) bar.render_to_file('dice_visual.svg' )
同时掷两个面数不同的骰子 下面来创建一个6面骰子和一个10面骰子,看看同时掷这两个骰子50000次的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from die import Dieimport pygaldie_1 = Die() die_2 = Die(10 ) results = [] for roll_num in range (50000 ): result = die_1.roll() + die_2.roll() results.append(result) frequencies = [] max_result = die_1.num_sides + die_2.num_sides for value in range (2 , max_result+1 ): frequency = results.count(value) frequencies.append(frequency) bar = pygal.Bar() bar.title = "Results of rolling a D6 and a D10 50,000 times." bar.x_labels = [str (value) for value in range (2 , 17 )] bar.x_title = "Result" bar.y_title = "Frequency of Result" bar.add('D6 + D10' , frequencies) bar.render_to_file('dice_visual.svg' )
下载数据 网上的数据多得难以置信,且大多未经过仔细检查。如果能够对这些数据进行分析,你就能发现别人没有发现的规律和关联。
CSV 文件格式 要在文本文件 中存储数据,最简单的方式是将数据作为一系列以逗号分隔的值 (CSV , Comma-Separated Values)写入文件,这样的文件称为CSV文件 。
例如,下面是一行CSV格式的天气数据:
2014-1-5,61,44,26,18,7,-1,56,30,9,30.34,30.27,30.15,,,,10,4,,0.00,0,,195
CSV文件对人来说阅读起来比较麻烦,但程序可轻松地提取并处理其中的值,这有助于加快数据分析过程。
最好使用用文字编辑器打开csv文件查看 ,Excel可能会更改显示格式
分析 CSV 文件头 csv模块包含在Python标准库中,可用于分析CSV文件中的数据行,让我们能够快速提取感兴趣的值。下面先来看一下sitka_weather_07-2014.csv
文件的第一行 ,其中包含一系列有关数据的描述 :
1 2 3 4 5 6 7 import csvfilename = 'sitka_weather_07-2014.csv' with open (filename) as f: reader = csv.reader(f) header_row = next (reader) print (header_row)
调用csv.reader()
,并将前面存储的文件对象作为实参传入 ,从而创建一个与该文件相关联的阅读器对象
模块csv的reader类 包含next()
方法,调用内置函数next()
并 将一个阅读器对象作为参数传入,将调用阅读器对象的next()
方法,从而返回文件中的下一行 。
reader处理文件中以逗号分隔的第一行数据 ,并将每项数据都作为一个元素存储在列表中 。
注意:文件头的格式并非总是一致的, 空格和单位可能出现在奇怪的地方,但不会带来任何问题 。
打印文件头及其位置 为让文件头数据更容易理解,将列表中的每个文件头及其位置 打印出来:
1 2 3 4 5 6 7 --snip-- with open (filename) as f: reader = csv.reader(f) header_row = next (reader) for index, column_header in enumerate (header_row): print (index, column_header)
对列表调用了enumerate()
(枚举 )来获取每个元素的索引及其值 。
提取并读取数据 首先读取每天的最高气温 :
1 2 3 4 5 6 7 8 9 10 11 12 13 import csvfilename = 'sitka_weather_07-2014.csv' with open (filename) as f: reader = csv.reader(f) header_row = next (reader) highs = [] for row in reader: highs.append(row[1 ]) print (highs)
下面使用int()
将这些字符串转换为数字 ,让matplotlib能够读取它们 :
1 2 3 4 5 6 7 --snip-- highs = [] for row in reader: high = int (row[1 ]) highs.append(high) print (highs)
绘制气温图表 为可视化这些气温数据,我们首先使用matplotlib创建一个显示每日最高气温的简单图形 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import csvfrom matplotlib import pyplot as plt--snip-- plt.figure(dpi=128 , figsize=(10 , 6 )) plt.plot(highs, c='red' ) plt.title("Daily high temperatures, July 2014" , fontsize=24 ) plt.xlabel('' , fontsize=16 ) plt.ylabel("Temperature (F)" , fontsize=16 ) plt.tick_params(axis='both' , which='major' , labelsize=16 ) plt.show()
模块 datetime 下面在图表中添加日期 。在天气数据文件中,第一个日期在第二行 :
获取日期数据时,获得的是一个字符串 ,因此需要将字符串'2014-7-1'
转换为一个表示相应日期的对象 。可使用模块datetime 中的方法strptime()
:
1 2 3 4 >>> from datetime import datetime >>> first_date = datetime.strptime('2014-7-1', '%Y-%m-%d') >>> print(first_date) 2014-07-01 00:00:00
在图表中添加日期 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import csvfrom datetime import datetimefrom matplotlib import pyplot as pltfilename = 'sitka_weather_07-2014.csv' with open (filename) as f: reader = csv.reader(f) header_row = next (reader) dates, highs = [], [] for row in reader: current_date = datetime.strptime(row[0 ], "%Y-%m-%d" ) dates.append(current_date) high = int (row[1 ]) highs.append(high) plt.figure(dpi=128 , figsize=(10 , 6 )) plt.plot(dates, highs, c='red' ) plt.title("Daily high temperatures, July 2014" , fontsize=24 ) plt.xlabel('' , fontsize=16 ) plt.gcf().autofmt_xdate() plt.ylabel("Temperature (F)" , fontsize=16 ) plt.tick_params(axis='both' , which='major' , labelsize=16 ) plt.show()
创建了两个空列表:dates, highs = [], []
将包含日期信息的数据转换为datetime对象:datetime.strptime(row[0], "%Y-%m-%d")
将日期和最高气温值传给plot()
:plt.plot(dates, highs, c='red')
涵盖更长的时间 创建覆盖整年 的天气图:
1 2 3 4 5 6 7 8 9 --snip-- filename = 'stika_weather_2014.csv' with open (filename) as f:--snip-- plt.title("Daily high temperatures - 2014" , fontsize=24 ) plt.xlabel('' , fontsize=16 ) --snip--
再绘制一个数据系列 从数据文件中提取最低气温,并添加到图表中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 --snip-- filename = 'sitka_weather_2014.csv' with open (filename) as f: reader = csv.reader(f) header_row = next (reader) dates, highs, lows = [], [], [] for row in reader: current_date = datetime.strptime(row[0 ], "%Y-%m-%d" ) dates.append(current_date) high = int (row[1 ]) highs.append(high) low = int (rpw[3 ]) lows.append(low) plt.figure(dpi=128 , figsize=(10 , 6 )) plt.plot(dates, highs, c='red' ) plt.plot(dates, lows, c='blue' ) plt.title("Daily high and low temperatures - 2014" , fontsize=24 ) --snip--
给图表区域着色 通过着色来呈现每天的气温范围 ,为此使用方法fill_between()
,它接受一个x值系列和两个y值系列,并填充两个y值系列之间的空间 :
1 2 3 4 5 6 --snip-- fig = plt.figure(dpi=128 , figsize=(10 , 6 )) plt.plot(dates, highs, c='red' . alpha=0.5 ) plt.plot(dates, lows, c='blue' . alpha=0.5 ) plt.fill_between(dates, highs, lows, facecolor='blue' , alpha=0.1 )
实参alpha
指定颜色的透明度
fill_between()
错误检查 我们应该能够使用有关任何地方的天气数据来运行highs_lows.py中的代码,但有些气象站会偶尔出现故障,未能收集部分或全部其应该收集的数据 。缺失数据可能会引发异常,如果不妥善地处理,还可能导致程序崩溃 。
例如,我们来看看生成加利福尼亚死亡谷的气温图时出现的情况:
1 2 3 4 5 --snip-- filename = 'death_valley_2014.csv' withj open (filename) as f: --snip--
运行结果:
1 2 3 4 Traceback (most recent call last): File "highs_lows.py", line 17, in <module> high = int(row[1]) ValueError: invalid literal for int() with base 10: ''
查看文件可知,没有记录2014年2月16日 的数据,表示最高温度的字符串为空 。为解决这种问题,我们从CSV文件中读取值时执行错误检查代码,对分析数据集时可能出现的异常进行处理 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 --snip-- filename = 'death_valley_2014.csv' with open (filename) as f: reader = csv.reader(f) header_row = next (reader) dates, highs, lows = [], [], [] for row in reader: try : current_date = datetime.strptime(row[0 ], "%Y-%m-%d" ) high = int (row[1 ]) low = int (row[3 ]) except ValueError: print (current_date, 'missing data' ) else : dates.append(current_date) highs.append(high) lows.append(low) --snip-- title = "Daily high and low temperatures - 2014\nDeath Valley, CA" plt.title(title, fontsize=20 ) --snip--
在有些情况下,需要使用continue来跳过一些数据 ,或者使用remove()
(删除列表值)或del
(删除 键-值 对)将已提取的数据删除 。可采用任何管用的方法,只要能进行精确而有意义的可视化就好。
16-2 比较锡特卡和死亡谷的气温: 为准确地比较锡特卡和死亡谷的气温范围,在y轴上使用相同的刻度 ,对两地的气温范围进行直接比较:
pyplot的方法ylim()
可以对y轴的刻度做限制 ;xlim()
则可以对x轴的刻度做限制。
1 2 3 4 5 --snip-- plt.ylim(10 , 120 ) plt.show()
尝试在一个图表中呈现这两个数据集 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import csvfrom datetime import datetimefrom matplotlib import pyplot as pltdef get_weather_data (filename, dates, highs, lows ): """从文件中获取日期、最高气温和最低气温""" with open (filename) as f: reader = csv.reader(f) header_row = next (reader) for row in reader: try : current_date = datetime.strptime(row[0 ], "%Y-%m-%d" ) high = int (row[1 ]) low = int (row[3 ]) except ValueError: print (current_date, 'missing data' ) else : dates.append(current_date) highs.append(high) lows.append(low) dates, highs, lows = [], [], [] get_weather_data('stika_weather_2014.csv' , dates, highs, lows) plt.figure(dpi=128 , figsize=(10 , 6 )) plt.plot(dates, highs, c='red' , alpha=0.6 ) plt.plot(dates, lows, c='blue' , alpha=0.6 ) plt.fill_between(dates, highs, lows, facecolor='blue' , alpha=0.15 ) dates, highs, lows = [], [], [] get_weather_data('death_valley_2014.csv' , dates, highs, lows) plt.plot(dates, highs, c='red' , alpha=0.3 ) plt.plot(dates, lows, c='blue' , alpha=0.3 ) plt.fill_between(dates, highs, lows, facecolor='blue' , alpha=0.05 ) title = "Daily high and low temperatures - 2014" title += "\nSitka, AK and Death Valley, CA" plt.title(title, fontsize=20 ) plt.xlabel('' , fontsize=16 ) plt.gcf().autofmt_xdate() plt.ylabel("Temperature (F)" , fontsize=16 ) plt.tick_params(axis='both' , which='major' , labelsize=16 ) plt.ylim(10 , 120 ) plt.show()
制作交易收盘价走势图: JSON 格式 下载收盘价数据 btc_close_2017.json实际是一个很长的Python列表 ,其中每个元素都是一个包含五个键的字典 :统计日期、月份、周数、周几以及收盘价。由于2017年1月1日是周日,作为2017年的第一周实在太短,。因此被计入2016年的第52周。于是2017年的第一周是从1月2日开始的。
可以将收盘价数据文件 直接下载到程序所在的文件夹中,也可以用Python 2.x 标准库中模块urllib2 (Python 3.x 版本使用urllib )的函数urlopen()
来做,还可以通过Python的第三方模块requests 下载数据。
如果采用函数urlopen()
来下载数据,可以使用如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from __future__ import (absolute_import, division, print_function, unicode_literals)try : from urllib2 import urlopen except ImportError: from urllib.request import urlopen import jsonjson_url = 'https://raw.githubusercontent.com/muxuezi/btc/master/btc_close_2017.json' response = urlopen(json_url) req = response.read() with open ('btc_close_2017_urllib.json' , 'wb' ) as f: f.write(req) file_urllib = json.loads(req) print (file_urllib)
函数urlopen的代码稍微复杂一些,第三方模块requests 封装了许多常用的方法,让数据下载和读取方式变得非常简单 :
1 2 3 4 5 6 7 8 import requestsjson_url = 'https://raw.githubusercontent.com/muxuezi/btc/master/btc_close_2017.json' req = requests.get(json_url) with open ('btc_close_2017_request.json' , 'w' ) as f: f.write(req.text) file_requests = req.json()
req.text
属性可以直接读取文件数据 ,返回格式是字符串
req.json()
可以将json文件的数据转换为Python列表 ,与之前的file_urllib
内容相同
提取相关的数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import jsonfilename = 'btc_close_2017.json' with open (filename) as f: btc_data = json.load(f) for btc_dict in btc_data: date = btc_dict['date' ] month = btc_dict['month' ] week = btc_dict['week' ] weekday = btc_dict['weekday' ] close = btc_dict['close' ] print ("{} is month {} week {}, {}, the close price is {} RMB" .format (date, month, week, weekday, close))
将字符串转换为数字值 btc_close_2017.json中的每个键和值都是字符串。为了能在后边的内容中对交易数据进行计算 ,需要先将表示周数和收盘价的字符串转换为数值 ,因此使用函数int()
:
1 2 3 4 5 6 7 8 9 10 --snip-- for btc_dict in btc_data: date = btc_dict['date' ] month = int (btc_dict['month' ]) week = int (btc_dict['week' ]) weekday = btc_dict['weekday' ] close = int (float (btc_dict['close' ])) print ("{} is month {} week {}, {}, the close price is {} RMB" .format (date, month, week, weekday, close))
在实际工作中,原始数据的格式经常是不统一的 。此类数值类型转换造成的ValueError异常十分普遍 。该例子中,无法将包含小数点的字符串转换为整数 ,因此需要先转换为浮点数再转换为整数 :int(float(btc_dict['close']))
有了这些数据之后,可以结合Pygal的可视化功能来探索一些有趣的信息 。
绘制收盘价折线图 之前章节介绍过用Pygal绘制条形图(bar chart)的方法,也介绍了 用matplotlib绘制折线图(line chart)的方法。下面用 Pygal 来实现收盘价的折线图 。
绘制折线图之前,需要获取x轴与y轴数据 ,因此我们创建了几个列表来存储数据 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --snip-- dates = [] months = [] weeks = [] weekdays = [] close = [] for btc_dict in btc_data: dates.append(btc_dict['date' ]) months.append(int (btc_dict['month' ])) weeks.append(int (btc_dict['week' ])) weekdays.append(btc_dict['weekday' ]) close.append(int (float (btc_dict['close' ])))
由于数据点比较多,x轴要显示346个日期,因此需要利用Pygal的配置参数,对图形进行适当的调整 :
1 2 3 4 5 6 7 8 9 10 11 --snip-- import pygalline_chart = pygal.Line(x_label_rotation=20 , show_mirror_x_labels=False ) line_chart.title = '收盘价(¥)' line_chart.x_labels = dates N = 20 line_chart.x_labels_major = dates[::N] line_chart.add('收盘价' , close) line_chart.render_to_file('收盘价折线图(¥).svg' )
pygal.Line()
创建Line实例
x_label_rotation=20
:让x轴上的标签顺时针旋转20°
show_mirror_x_labels=False
:告诉图形不用显示所有的x轴标签
line_chart.x_labels_major = dates[:20]
:x轴坐标每隔20天显示一次
下面对价格做一些简单的探索
时间序列特征初探 进行时间序列分析 总是期望发现趋势(trend)、 周期性(seasonality)和 噪声(noise),从而能够 描述事实、预测未来、做出决策 。
从收盘价的折线图可以看出,2017年的总体趋势 时非线性的,而且增长幅度不断增大,似乎呈指数分布 。但是,在每个季度末 (3月、6月、9月)似乎有一些相似的波动 ,为了验证周期性的假设,需要先将非线性的趋势(指数增长部分)消除 。**对数变换(log transformation)**是常用的处理方法之一。
用Python标准库的数学模块math 来解决这个问题。math里有许多常用的数学函数,这里以10为底的对数函数math.log10计算收盘价 ,日期仍然保持不变——这种方式称为半对数(semi-logarithmic)变换 。
1 2 3 4 5 6 7 8 9 10 11 12 13 --snip-- import pygalimport mathline_chart = pygal.Line(x_label_rotation=20 , show_mirror_x_labels=False ) line_chart.title = '收盘价对数变换(¥)' line_chart.x_labels = dates N = 20 line_chart.x_labels_major = dates[::N] close_log = [math.log10(_) for _ in close] line_chart.add('log收盘价' , close_log) line_chart.render_to_file('收盘价对数变换折线图(¥).svg' )
剔除非线性趋势 之后,整体的趋势更接近线性增长 ,且收盘价在每个季度末似乎有显著的周期性 。那么,12月会不会再现这一场景?下面来看看收盘价的月日均值 与周日均值 的表现。
收盘价均值 再利用btc_close_2017.json文件中的数据,绘制2017年前11个月 的日均值、前49周(01-02~12-10)的日均值,以及 每周各天 的日均值。虽然这些日均值的数值不同,但都是一段时间的均值,计算方法都是一样的。因此,可以将绘图代码封装成函数 ,以便重复使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 --snip-- from itertools import groupbydef draw_line (x_data, y_data, title, y_legend ): xy_map = [] for x, y in groupby(sorted (zip (x_data, y_data)), key=lambda _: _[0 ]): y_list = [v for _, v in y] xy_map.append([x, sum (y_list) / len (y_list)]) x_unique, y_mean = [*zip (*xy_map)] line_chart = pygal.Line() line_chart.title = title line_chart.x_labels = x_unique line_chart.add(y_legend, y_mean) line_chart.render_to_file(title+'.svg' ) return line_chart
由于需要将数据按月份、周数、周几分组,再计算每组的均值 ,因此导入Python标准库中模块itertools的函数groupby 。
将x轴与y轴的数据合并 、排序 ,再用函数groupby分组
分组之后,求出每组的平均值,存储到xy_map中
最后,将xy_map中存储的x轴与y轴数据分离,就可以像之前一样用Pygal画图了
下面画出收盘价月日均值 ,由于12月的数据不完整,只取1月到11月的数据。通过dates查找2017-12-01索引的位置,确定周数和收盘价的取值范围 :
1 2 3 4 idx_month = dates.index('2017-12-01' ) line_chart_month = draw_line(months[:idx_month], close[:idx_month], '收盘价月日均值(¥)' , '月日均值' ) line_chart_month
收盘价数据仪表盘 每个SVG文件打开之后都是独立的页面,如果能整合 在一起,就可以方便地进行长期管理、监测和分析 。另外,新的图表也可以方便地加入进来 ,这样就形成了一个数据仪表盘 (dashboard )。下面,将之前绘制的图整合起来,做一个收盘价数据仪表盘:
1 2 3 4 5 6 7 8 9 10 11 12 --snip-- with open ('收盘价Dashboard.html' , 'w' , encoding='utf8' ) as html_file: html_file.write( '<html><head><title>收盘价Dashboard</title><meta charset="utf-8"></head><body>\n' ) for svg in [ '收盘价折线图(¥).svg' , '收盘价对数变换折线图(¥).svg' , '收盘价月日均值(¥).svg' , '收盘价周日均值(¥).svg' , '收盘价星期均值(¥).svg' ]: html_file.write( ' <object type="image/svg+xml" data="{0}" height=500></object>\n' .format (svg)) html_file.write('</body></html>' )
和常见网络应用的数据仪表盘一样,这个数据仪表盘也是一个完整的网页。
使用 API 使用 Web API Web API是网站的一部分,用于 与使用非常具体的URL请求特定信息 的程序 交互 。这种请求称为API调用 。请求的数据将以易于处理的格式(如JSON或CSV)返回 。
依赖于外部数据源 的大多数应用程序都依赖于API调用 ,如集成社交媒体网站的应用程序。
Git 和 GitHub 本章的可视化将基于来自GitHub的信息。我们将使用GitHub的API来请求有关该网站中Python项目的信息 ,然后使用Pygal生成交互式可视化,以呈现这些项目的受欢迎程度 。
本章将编写一个程序,它自动下载GitHub上星级最高的Python项目的信息,并对这些信息进行可视化 。
使用 API 调用请求数据 GitHub的API让你能够通过API调用来请求各种信息。要知道API调用是什么样的,在浏览器中访问如下地址:
1 https://api.github.com/search/repositories?q=language:python&sort=starshttps://api.github.com/
第一部分https://api.github.com/
:将请求发送到GitHub网站中响应API调用的部分
接下来的部分search/repositories
:让API搜索GitHub上的所有仓库
repositories后面的问号 指出我们要传递一个实参 。
q=
:q 表示查询 ,等号 让我们能够开始指定查询
通过使用language:python
,我们指出只想获取主要语言为Python的仓库的信息
最后一部分&sort=stars
:指定将项目按其获得的星级排序
安装 requests requests包 让Python程序能够轻松地向网站请求信息以及检查返回的响应 。要安装requests,执行:
1 pip install --user requests
处理 API 响应 下面来编写一个程序,它执行API调用并处理结果,找出GitHub上星级最高的Python项目:
1 2 3 4 5 6 7 8 9 10 11 12 import requestsurl = 'https://api.github.com/search/repositories?=language:python&sort=stars' r = requests.get(url) print ("Status code:" , r.status_code)response_dict = r.json() print (response_dict.keys())
处理响应字典 下面来生成一些概述API调用返回的信息的输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import requestsurl = 'https://api.github.com/search/repositories?q=language:python&sort=stars' r = requests.get(url) print ("Status code:" , r.status_code)response_dict = r.json() print ("Total repositories:" , response_dict['total_count' ])repo_dicts = response_dict['items' ] print ("Repositories returned:" , len (repo_dicts))repo_dict = repo_dicts[0 ] print ("\nKeys:" , len (repo_dict))for key in sorted (repo_dict.keys()): print (key)
与'items'
关联的值是一个列表 ,其中包含很多字典,每个字典都包含有关一个Python仓库的信息 。
下面来提取repo_dict中与一些键相关联的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 --snip-- repo_dict = repo_dicts[0 ] print ("\nSelected information about first repository:" )print ('Name:' , repo_dict['name' ])print ('Owner:' , repo_dict['owner' ]['login' ])print ('Stars:' , repo_dict['stargazers_count' ])print ('Reposiory:' , repo_dict['html_url' ])print ('Created:' , repo_dict['created_at' ])print ('Updated:' , repo_dict['updated_at' ])print ('Description:' , repo_dict['description' ])
概述最受欢迎的仓库 对这些数据进行可视化 时,我们需要涵盖多个仓库 。下面就来编写一个循环,打印API调用返回的每个仓库的特定信息,以便能够在可视化中包含所有这些信息:
1 2 3 4 5 6 7 8 9 10 11 12 --snip-- repo_dicts = response_dict['items' ] print ("Repositories returned:" , len (repo_dicts))print ("\nSelected information about each repository:" )for repo_dict in repo_dicts: print ('\nName:' , repo_dict['name' ]) print ('Owner:' , repo_dict['owner' ]['login' ]) print ('Stars:' , repo_dict['stargazers_count' ]) print ('Reposiory:' , repo_dict['html_url' ]) print ('Description:' , repo_dict['description' ])
监视 API 的速率限制 大多数API都存在速率限制 ,即你在特定时间内可执行的请求数存在限制 。要获悉你是否接近了GitHub的限制,在浏览器中输入https://api.github.com/rate_limit
,将得到类似于下面的响应:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 { "resources" : { "core" : { "limit" : 60 , "remaining" : 0 , "reset" : 1593698255 } , "graphql" : { "limit" : 0 , "remaining" : 0 , "reset" : 1593700880 } , "integration_manifest" : { "limit" : 5000 , "remaining" : 5000 , "reset" : 1593700880 } , "search" : { "limit" : 10 , "remaining" : 10 , "reset" : 1593697340 } } , "rate" : { "limit" : 60 , "remaining" : 0 , "reset" : 1593698255 } }
我们关心的信息是搜索API 的速率限制。从18~22行可知,极限为每分钟 10个请求;当前这一分钟内,还可执行10个请求;reset
值指的是配额将重置的Unix时间或新纪元时间(1970-01-01午夜后多少秒)。用完配额后,将收到一条简单的响应,由此知道已到达API极限。 到达极限后 ,必须等待配额重置 。
注意:很多API都要求你注册获得密钥后才能执行API调用 。GitHub没有这样的要求,但获得API密钥后,配额将高得多。
使用 Pygal 可视化仓库 我们来进行可视化,呈现GitHub上Python项目的受欢迎程度 。创建一个交互式条形图,条形的高度表示项目获得了多少颗星。单击条形将进入项目在GitHub上的主页 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import requestsimport pygalfrom pygal.style import LightColorizedStyle as LCS, LightenStyle as LSurl = 'https://api.github.com/search/repositories?q=language:python&sort=stars' r = requests.get(url) print ("Status code:" , r.status_code)response_dict = r.json() print ("Total repositories:" , response_dict['total_count' ])repo_dicts = response_dict['items' ] names, stars = [], [] for repo_dict in repo_dicts: names.append(repo_dict['name' ]) stars.append(repo_dict['stargazers_count' ]) my_style = LS('#333366' , base_style=LCS) chart = pygal.Bar(style=my_style, x_label_rotation=45 , show_legend=False ) chart.title = 'Most-Starred Python Projects on GitHub' chart.x_labels = names chart.add('' , stars) chart.render_to_file('python_repos.svg' )
LS('#333366', base_style=LCS)
:使用LightenStyle (别名LS)定义了一种样式 ,并将基色设置为深蓝色 ;还传递了实参base_style
,以使用LightColorizedStyle类 (别名LCS)
show_legend=False
隐藏了图例,因为只在图表中绘制一个数据系列
由于不需要给这个数据系列添加标签 ,因此添加数据时,将标签设置成了空字符串 。
改进 Pygal 图表 我们将进行多个方面的定制,因此先来稍微调整代码结构,创建一个配置对象 ,其中包含要传递给Bar()
的所有定制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 --snip-- my_style = LS('#333366' , base_style=LCS) my_config = pygal.Config() my_config.x_label_rotation = 45 my_config.show_legend = False my_config.title_font_size = 24 my_config.label_font_size = 14 my_config.major_label_font_size = 18 my_config.truncate_label = 15 my_config.show_y_guides = False my_config.width = 1000 chart = pygal.Bar(my_config, style=my_style) chart.title = 'Most-Starred Python Projects on GitHub' chart.x_labels = names chart.add('' , stars) chart.render_to_file('python_repos.svg' )
9~11行设置了图表标题、副标签和主标签的字体大小。
在这个图表中 ,副标签 是x轴上的项目名和y轴上的大部分 数字;主标签 是y轴上为5000整数倍的刻度 ,这些标签更大,以与副标签区分开。
truncate_label=15
将较长的项目缩短 为15个字符(将鼠标指向被截短的项目名,将显示完整的项目名)
show_y_guides=False
:隐藏图表中的水平线 。
width=1000
:自定义的宽度,让图表更充分地利用浏览器中的可用空间
添加自定义工具提示 在Python中,将鼠标指向条形将显示它表示的信息 ,这通常称为工具提示 。下面来创建一个自定义工具提示,以同时显示项目的描述。
来看一个简单的示例,它可视化前三个项目,并给每个项目对应的条形都指定自定义标签。为此,我们向add()
传递一个字典列表 ,而不是值列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import pygalfrom pygal.style import LightColorizedStyle as LCS, LightenStyle as LSmy_style = LS('#333366' , base_style=LCS) chart = pygal.Bar(style=my_style, x_label_rotation=45 , show_legend=False ) chart.title = 'Python Projects' chart.x_labels = ['httpie' , 'django' , 'flask' ] plot_dicts = [ {'value' : 16101 , 'label' : 'Description of httpie.' }, {'value' : 15028 , 'label' : 'Description of django.' }, {'value' : 14798 , 'label' : 'Description of flask.' }, ] chart.add('' , plot_dicts) chart.render_to_file('bar_descriptions.svg' )
plot_dicts列表包含三个字典,'value'
对应的值确定条形高度 ;'label'
对应的值给条形创建工具提示 。
根据数据绘图 为根据数据绘图,我们将自动生成plot_dicts。其中包含API调用返回的30个项目的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 --snip-- repo_dicts = response_dict['items' ] print ("Number of items:" , len (repo_dicts))names, plot_dicts = [], [] for repo_dict in repo_dicts: names.append(repo_dict['name' ]) plot_dict = { 'value' : repo_dict['stargazers_count' ], 'label' : repo_dict['description' ], } plot_dicts.append(plot_dict) my_style = LS('#333366' , base_style=LCS) --snip-- chart.add('' , plot_dicts) chart.render_to_file('python_repos.svg' )
在图表中添加可单击的链接 Pygal还允许将图表中的每个条形用作网站的链接 。为此,在为每个项目创建的字典中,添加一个键为'xlink'
的 键-值 对:
1 2 3 4 5 6 7 8 9 10 11 12 --snip-- names, plot_dicts = [], [] for repo_dict in repo_dicts: names.append(repo_dict['name' ]) plot_dict = { 'value' : repo_dict['stargazers_count' ], 'label' : repo_dict['description' ], 'xlink' : repo_dict['html_url' ], } plot_dicts.append(plot_dict) --snip--
单击图表中的任何条形,都将在浏览器中打开一个新的标签页,并在其中显示相应项目的GitHub页面。
Hacker News API 为探索如何使用其他网站的API调用,我们来看看
Hacker News网站,用户分享编程和技术方面的文章,并就这些文章展开积极的讨论。Hacker News的API让你能够访问有关该网站所有文章和评论的信息,且不要求通过注册获得密钥。
已被墙。
问题 Jupyter Notebook 用matplotlib作图显示中文乱码 1 plt.rc('font' , family='SimHei' , size=7 )
存在极端值干扰
条形图和直方图的区别
条形图 (bar chart)
用条形的高度 表示各类别频数的多少 ,其宽度 (表示类别 )则是固定 的;
条形图各矩形分开排列(有间隙)
主要用于展示分类数据
直方图 (Histogram )
用面积 表示各组频数的多少 ,矩形的高度 表示每一组的频数或频率 ,宽度 则表示各组的组距
分组数据具有连续性 ,直方图各矩形通常是连续排列
主要用于展示数值型数据
绘图时x轴/y轴的刻度标签重叠 Matplotlib绘图时x轴标签重叠的解决办法 - 云+社区 - 腾讯云
箱线图(箱型图/盒型图) 直方图 用于显示一组数据的分布情况 ,而箱线图 用于显示一组数据内部的分散情况 。例如: 最大值、最小值,中位数,4分位数、异常值 等等。