Python可视化数据学习

使用matplotlib制作图表

制作简单的折线图

import matplotlib.pyplot as plt

input_values = [1,2,3,4,5]
squares = [1,4,9,16,25]
plt.plot(input_values,squares,linewidth=5)
#设置图表标题,并给坐标轴加上标签
plt.title("Square Number",fontsize=24)
plt.xlabel("Value",fontsize=14)
plt.ylabel("Square of Value",fontsize=14)

#设置刻度标记的字体大小
plt.tick_params(axis='both',labelsize=14)

plt.show()

Python可视化数据学习_第1张图片

使用scatter()绘制散点图

import matplotlib.pyplot as plt


x_values = list(range(1,101))
y_values = [x**2 for x in x_values]
plt.scatter(x_values,y_values,c='red',edgecolor='none',s=4) #edgecolor删除数据点黑色轮廓


#设置图表标题并给坐标轴加上标签
plt.title("Square Number",fontsize=24)
plt.xlabel("Value",fontsize=14)
plt.ylabel("Square of Value",fontsize=14)
#设置刻度标记的大小
plt.tick_params(axis='both',which='major',labelsize=14)
plt.axis([0,110,0,12100])
plt.show()

Python可视化数据学习_第2张图片

可以使用RGB颜色模式自定义颜色。要指定自定义颜色,可传递参数c ,并将其设置为一个元组,其中包含三个0~1之间的小数值,它们分别表示红色、绿色和蓝色分量。值越接近0,指定的颜色越深,值越接近1,指定的颜色越浅。

plt.scatter(x_values, y_values, c=(0, 0, 0.8), edgecolor='none', s=40)
颜色映射 (colormap)是一系列颜色,它们从起始颜色渐变到结束颜色。在可视化中,颜色映射用于突出数据的规律
plt.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Blues,edgecolor='none', s=40)
参数c 设置成了一个 y 值列表,并使用参数cmap 告诉pyplot 使用哪个颜色映射。这些代码将 y 值较小的点显示为浅蓝色,并将y 值较大的点显示为深蓝色,
Python可视化数据学习_第3张图片
要让程序自动将图表保存到文件中,可将对plt.show() 的调用替换为对plt.savefig() 的调用:
plt.savefig('squares_plot.png', bbox_inches='tight')

随机漫步

每次行走都完全是随机的,没有明确的方向,结果是由一系列随机决策决定的

random_walk.py

from random import choice

class RandomWalk():
	"""一个生成随机漫步数据的类"""
	def __init__(self,num_points = 5000):
		"""初始化随机漫步的属性"""
		self.num_points = num_points
		
		#所有随机漫步都始于(0,0)
		self.x_values = [0]
		self.y_values = [0]

	def fill_walk(self):
		"""计算随机漫步包含的所有点"""
		#不断漫步,直到列表达到指定的长度
		while len(self.x_values) < self.num_points:
			#决定前进方向以及沿这个方向前进的距离
			x_step = self.get_step()
			y_step = self.get_step()
			#拒绝原地踏步
			if x_step == 0 and y_step == 0:
				continue
			
			#计算下一个点的x和y的值
			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)

	def get_step(self):
		self.direction = choice([1,-1])
		self.distance = choice([0,1,2,3,4])
		self.step = self.direction * self.distance
		return self.step

rw_visual.py

import matplotlib.pyplot as plt
from random_walk import RandomWalk
#只要程序处于活动状态,就不断地模拟随机漫步
while True:
	#创建一个RandomWalk实例,并将其包含的点都绘制出来
	rw = RandomWalk()
	rw.fill_walk()
	plt.scatter(rw.x_values,rw.y_values,s=5)
	plt.show()
	keep_running =input("Make another walk?(y/n):")
	if keep_running == 'n':
		break

Python可视化数据学习_第4张图片

给点着色、绘制起点终点

我们将使用颜色映射指出漫步中各点的先后顺序,并删除每个点的黑色轮廓,让它们的颜色更明显。为根据漫步中各点的先后顺序进行着色,我们传递参数c ,并将其设置为一个列表,其中包含各点的先后顺序。由于这些点是按顺序绘制的,因此给参数c指定的列表只需包含数字1~5000

import matplotlib.pyplot as plt
from random_walk import RandomWalk

while True:
	#创建一个RandomWalk实例,并将其包含的点都绘制出来
	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,edgecolor='none',s=5)#给点着色
	#突出起点和重点
	plt.scatter(0,0,c='green',edgecolors='none',s=100)
	plt.scatter(rw.x_values[-1],rw.y_values[-1],c='red',edgecolors='none',s=100)
	plt.show()
	
	keep_running =input("Make another walk?(y/n):")
	if keep_running == 'n':
		break

隐藏坐标轴

	--snip--
        plt.scatter(rw.x_values[-1],rw.y_values[-1],c='red',edgecolors='none',s=100)
	#隐藏坐标轴
	plt.axes().get_xaxis().set_visible(False)
	plt.axes().get_yaxis().set_visible(False)
	
	plt.show()
        --snip--
增加点数
rw = RandomWalk(50000)

Python可视化数据学习_第5张图片

图表适合屏幕大小时,更能有效地将数据中的规律呈现出来。为让绘图窗口更适合屏幕大小:

# 设置绘图窗口的尺寸
    plt.figure(figsize=(10, 6))

函数figure() 用于指定图表的宽度、高度、分辨率和背景色。你需要给形参figsize 指定一个元组,向matplotlib指出绘图窗口的尺寸,单位为英寸。

Python假定屏幕分辨率为80像素/英寸,如果上述代码指定的图表尺寸不合适,可根据需要调整其中的数字。如果你知道自己的系统的分辨率,可使用形参dpi 向figure() 传递该分辨率,以有效地利用可用的屏幕空间,如下所示:

plt.figure(dpi=128, figsize=(10, 6))

使用Pygal模拟掷骰子

要了解使用Pygal可创建什么样的图表,请查看图表类型画廊:访问http://www.pygal.org/ ,单击Documentation,再单击Chart types。每个示例都包含源代码,让你知道这些图表是如何生成的。

掷一个骰子

die.py

from random import randint

class Die():
	"""表示一个骰子的类"""
	
	def __init__(self,num_sides=6):
		"""骰子默认为6面"""
		self.num_sides = num_sides
	def roll(self):
		"""返回一个位于1和骰子面数之间的随机值"""
		return randint(1,self.num_sides)

die_visual.py

from die import Die
import pygal
#创建一个D6
die = Die()
#掷几次骰子,并将结果存储在一个列表中
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)

#对结果进行可视化 直方图
hist = pygal.Bar()
hist.title = "Result of rolling one D6 1000 times."#标题
hist.x_labels=[x for x in range(1,die.num_sides+1)]#横坐标
hist.x_title = "Result"#横轴标题
hist.y_title = "Frequency of Result"#纵轴标题

hist.add('D6',frequencies)#将值添加到图表中
hist.render_to_file('die_visual.svg')#将图表渲染为svg文件

Python可视化数据学习_第6张图片

掷两个骰子

from die import Die
import pygal
#创建两个D6骰子
die_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)

#对结果进行可视化 直方图
hist = pygal.Bar()
hist.title = "Result of rolling two D6 1000 times."
hist.x_labels=[x for x in range(2,max_result+1)]
hist.x_title = "Result"
hist.y_title = "Frequency of Result"

hist.add('D6+D6',frequencies)
hist.render_to_file('dice_visual.svg')

Python可视化数据学习_第7张图片

处理csv文件

    要在文本文件中存储数据,最简单的方式是将数据作为一系列以逗号分隔的值 (CSV)写入文件。这样的文件称为CSV文件。csv 模块包含在Python标准库中,可用于分析CSV文件中的数据行。

import csv

filename = 'sitka_weather_07-2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader)
    print(header_row)

调用csv.reader() ,并将前面存储的文件对象作为实参传递给它,从而创建一个与该文件相关联的阅读器(reader )对象。模块csv 包含函数next() ,调用它并将阅读器对象传递给它时,它将返回文件中的下一行。

为让文件头数据更容易理解,将列表中的每个文件头及其位置打印出来

for index, column_header in enumerate(header_row):
          print(index, column_header)

对列表调用了enumerate() 来获取每个元素的索引及其值。(请注意,我们删除了代码行print(header_row))。得知日期和最高气温分别存储在第0列和第1列。

提取并读取数据

	highs = [int(row[1]) for row in reader] #将字符串转换为数字,方便matplotlib读取
	print(highs)

提取最高气温并添加到列表中

绘制气温图表

  import csv

  from matplotlib import pyplot as plt

  # 从文件中获取最高气温
  --snip--
# 根据数据绘制图形
  fig = 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()

Python可视化数据学习_第8张图片

模块datetime

读取日期数据时,获得的是一个字符串,因此我们需要想办法将字符串'2014-7-1' 转换为一个表示相应日期的对象。为创建一个表示2014年7月1日的对象,可使用模块datetime 中的方法strptime()。在终端会话中看看strptime() 的工作原理:

>>> from datetime import datetime
>>> first_date = datetime.strptime('2014-7-1', '%Y-%m-%d')

 下表是模块datetime中设置日期和时间格式的实参

Python可视化数据学习_第9张图片Python可视化数据学习_第10张图片

绘制一年时间的天气图

import csv
from matplotlib import pyplot as plt
from datetime import datetime
import matplotlib.dates as mdates
#从文件中获取最高气温
filename = 'sitka_weather_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)

#根据数据绘制图形
fig=plt.figure(dpi=128,figsize=(10,6))
plt.plot(dates,highs,c='red')

#设置图形格式
plt.title("Daily high temperatures - 2014",fontsize=24)
plt.xlabel("",fontsize=16)
#配置和横坐标
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m/%Y'))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())
fig.autofmt_xdate()#让日期标签倾斜
plt.ylabel("Temperature(F)",fontsize=16)
plt.tick_params(axis='both',which = 'major',labelsize=10)

plt.show()
问题1:横坐标刻度太少,自定义配置横坐标
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m/%Y'))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())

问题2:列表解析法分别读取文件两行内容,有一行是空的

highs = [int(row[1]) for row in reader]
dates = [datetime.strptime(row[0],"%Y-%M-%D") for row in reader]
print(len(highs))
print(len(dates))

第二行读取的内容是空的........为什么......

添加最低气温并给图表区域着色

在其中再添加最低气温数据,使其更有用。从数据文件中提取最低气温,并将它们添加到图表。通过着色来呈现每天的气温范围。为此,我们将使用方法fill_between() ,它接受一个 x 值系列和两个 y 值系列,并填充两个 y值系列之间的空间:

--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:
                --snip--
		low = int(row[3])
		lows.append(low)
#根据数据绘制图形
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)

#设置图形格式
plt.title("Daily high and low temperatures - 2014",fontsize=24)
--snip--

实参alpha 指定颜色的透明度。Alpha 值为0表示完全透明,1(默认设置)表示完全不透明。通过将alpha 设置为0.5,可让红色和蓝色折线的颜色看起来更浅。

向fill_between() 传递了一个 x 值系列:列表dates ,还传递了两个 y 值系列:highs 和lows 。实参facecolor 指定了填充区域的颜色,我们还将alpha 设置成了较小的值0.1,让填充区域将两个数据系列连接起来的同时不分散观察者的注意力。

Python可视化数据学习_第11张图片

问题3:横轴坐标如何从y轴开始

plt.xlim(dates[0],dates[-1])

错误检查

我们应该能够使用有关任何地方的天气数据来运行highs_lows.py中的代码,但有些气象站会偶尔出现故障,未能收集部分或全部其应该收集的数据。缺失数据可能会引发异常,如果不妥善地处理,还可能导致程序崩溃。

加利福尼亚死亡谷的气温图

文件death_valley_2014.csv没有记录2014年2月16日的数据,表示最高温度的字符串为空。为解决这种问题,我们在从CSV文件中读取值时执行错误检查代码,对分析数据集时可能出现的异常进行处理,如下所示:


--snip--
	for row in reader:
		try:
			current_date = datetime.strptime(row[0], "%Y-%m-%d")
			high = int(row[1])
			low = int(row[3])
		except:
			print(current_date,'missing data')
		else:
			dates.append(current_date)
			highs.append(high)
			lows.append(low)
--snip--

从中提取日期、最高气温和最低气温。只要缺失其中一项数据,Python就会引发ValueError 异常,打印一条错误消息,指出缺失数据的日期。打印错误消息后,循环将接着处理下一行。如果获取特定日期的所有数据时没有发生错误,将运行else 代码块,并将数据附加到相应列表的末尾

练习1:比较锡特卡和死亡谷的气温 :在有关锡特卡和死亡谷的图表中,气温刻度反映了数据范围的不同。为准确地比较锡特卡和死亡谷的气温范围,需要在y 轴上使用相同的刻度。为此,请修改y 轴设置,对锡特卡和死亡谷的气温范围进行直接比较(你也可以对任何两个地方的气温范围进行比较)。你还可以尝试在一个图表中呈现这两个数据集。

import csv
from datetime import datetime
from matplotlib import pyplot as plt

def 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('sitka_weather_2014.csv',dates,highs,lows) 

fig = 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)
fig.autofmt_xdate()
plt.ylabel("Temperature(F)",fontsize=16)
plt.tick_params(axis='both',which = 'major',labelsize=16)
plt.ylim(10,120)
plt.xlim(dates[0],dates[-1])
plt.show()
Python可视化数据学习_第12张图片

制作世界人口地图:JSON格式

获取数据值

population_data.json文件是一个Python列表每个元素都是一个包含四个键的字典:国家名、国别码、年份以及表示人口数量的值。文件中的每个键和值都是字符串。为处理这些人口数据,我们需要将表示人口数量的字符串转换为数字值,为此我们使用函数int() ,但是由于原始数据的格式常常不统一,因此经常会出现错误。Python不能直接将包含小数点的字符串 '1127437398.85751' 转换为整数(这个小数值可能是人口数据缺失时通过插值得到的)。为消除这种错误,先将字符串转换为浮点数,再将浮点数转换为整数:

import json
#将数据加载到一个列表中
filename = 'population_data.json'
with open(filename) as f:
	pop_data = json.load(f)

#打印每个国家2010年的人口数量
for pop_dict in pop_data:
	if pop_dict['Year'] == '2010':
		country_name = pop_dict['Country Name']
		#Python不能直接将包含小数点的字符串'1127437398.85751'转换为整数
		population = int(float(pop_dict['Value']))
		print(country_name + ": " + str(population))

获取两个字母的国别码

Pygal中的地图制作工具要求数据为特定的格式:用国别码表示国家,用数字表示人口数量。处理地理政治数据时,经常需要用到几个标准化国别码集。population_data.json中包含的是三个字母的国别码,但Pygal使用两个字母的国别码。我们需要想办法根据国家名获取两个字母的国别码。Pygal使用的国别码存储在模块i18n (internationalization的缩写)中。字典COUNTRIES 包含的键和值分别为两个字母的国别码和国家名。要查看这些国别码,可从模块i18n中导入这个字典,并打印其键和值:

from pygal.i18n import COUNTRIES

for country_code in sorted(COUNTRIES.keys()):
    print(country_code, COUNTRIES[country_code])

问题1:执行程序时,报错

ModuleNotFoundError: No module named ‘pygal.i18n‘
经查找是由于 pygal.i18n  已经不存在了,现在已经更改成了  pygal_maps_world,需要单独通过pip下载
pip install pygal_maps_world

然而pip下载报错,只能从下载tar压缩包解压后进入解压目录 使用python setup.py install命令安装,安装成功之后,修改为

from pygal_maps_world.i18n import COUNTRIES

就可以正常调用国别码了

制作世界地图

from pygal_maps_world.maps import World

wm = World()
wm.title = 'North,Central,and South Amercia'
wm.add('North America', ['ca','mx','us'])
wm.add('Central America',['bz','cr','gt','hn','ni','pa','sv'])
wm.add('South Ameirca',['ar','bo','br','cl','co','ec','gf','gy','pe','py','sr','uy','ve'])
wm.render_to_file('americas.svg')
问题2:执行程序时报错
import pygal
wm = pygal.Worldmap()
AttributeError: module 'pygal' has no attribute 'Worldmap'
对于绘制世界地图的指令,也就是我遇到的第二个报错,语句相应地更改模块名称:
from pygal_maps_world.maps import World
wm = World()

绘制完整的世界人口地图

import json
from country_codes import get_country_code
from pygal_maps_world.maps import World
#将数据加载到一个列表中
--snip--

#打印每个国家2010年的人口数量
#创建一个包含人口数量字典
cc_populations = {}
for pop_dict in pop_data:
	if pop_dict['Year'] == '2010':
		country_name = pop_dict['Country Name']
		#Python不能直接将包含小数点的字符串'1127437398.85751'转换为整数
		population = int(float(pop_dict['Value']))
		code = get_country_code(country_name)
		if code:
			cc_populations[code] = population
wm = World()
wm.title = 'World Population in 2010,by Country'
wm.add('2010',cc_populations)
wm.render_to_file('world_populations.svg')

创建了一个空字典,用于以Pygal要求的格式存储国别码和人口数量。如果返回了国别码,就将国别码和人口数量分别作为键和值填充字典cc_populations。创建了一个Worldmap 实例,并设置其title 属性。我们调用了add() ,并向它传递由国别码和人口数量组成的字典。

 根据人口数量将国家分组

根据人口数量分成三组——少于1000万的85、介于1000万和10亿之间的69以及超过10亿的2:

--snip--
#根据人口数量将所有的国家分成三组
cc_pops_1,cc_pops_2,cc_pops_3 ={},{},{}
for cc,pop in cc_populations.items():
	if pop < 10000000:
		cc_pops_1[cc] =pop
	elif pop < 1000000000:
		cc_pops_2[cc] = pop
	else:
		cc_pops_3[cc] = pop

#看看每组分别包含多少个国家
print(len(cc_pops_1),len(cc_pops_2),len(cc_pops_3))

wm = World()
wm.title = 'World Population in 2010,by Country'
wm.add('0-10m',cc_pops_1)
wm.add('10m-1bn',cc_pops_2)
wm.add('>1bn',cc_pops_3)
wm.render_to_file('world_populations.svg')

使用Pygal设置世界地图的样式

Pygal使用一种基色,但将指定该基色,并让三个分组的颜色差别更大:

import json
from country_codes import get_country_code
from pygal_maps_world.maps import World
from pygal.style import RotateStyle
--snip--
#根据人口数量将所有的国家分成三组
cc_pops_1,cc_pops_2,cc_pops_3 ={},{},{}
for cc,pop in cc_populations.items():
	if pop < 10000000:
		--snip--            

wm_style = RotateStyle('#336699')
wm = World(style = wm_style)
wm.title = 'World Population in 2010,by Country'
--snip--

十六进制格式 的RGB颜色是一个以井号(#)打头的字符串,后面跟着6个字符,其中前两个字符表示红色分量,接下来的两个表示绿色分量,最后两个表示蓝色分量。每个分量的取值范围为00 (没有相应的颜色)~FF (包含最多的相应颜色).#336699混合了少量的红色33、多一些的绿色66和更多一些的蓝色99,它为RotateStyle 提供了一种淡蓝色基色。Python可视化数据学习_第13张图片

你可能感兴趣的:(廖雪峰Python学习笔记)