这是《Python编程:从入门到实践》的第二个实践项目的第二部分,对应第16章,对CSV和JSON格式的数据绘制图表。
1. 读取csv文件
这里的csv文件记录的是某地的天气,包括气象站的编码、名称、日期、降水量、最高气温和最低气温。
读取csv文件表头,并获得列名的索引。
import csv
filename = 'data/sitka_weather_07-2018_simple.csv'
### 读取csv文件头
with open(filename) as f: #f是一个表示文件的对象
reader = csv.reader(f) #创建一个与该文件相关联的阅读器对象
header_row = next(reader) #返回文件中的下一行
print(header_row) #将逗号分隔的每一项数据作为一个元素存储在列表中
#['STATION', 'NAME', 'DATE', 'PRCP', 'TAVG', 'TMAX', 'TMIN']
for index, column_header in enumerate(header_row):
print(index, column_header) #enumerate()获取每个元素的索引及其值
其它的一些读取文件内容的方法。
#open()接受一个参数,即要打开的文件名,返回一个表示文件的对象;with在不需要访问文件后将其关闭
with open(filename) as f:
contents = f.read() #方法read()读取文件的内容,作为一个长字符串赋值给contents
print(contents)
with open(filename) as f:
for line in f: #逐行读取文件内容
print(line)
with open(filename) as f:
lines = f.readlines() #方法readlines()从文件中读取每一行,并将其存储在一个列表中
for line in lines:
print(line)
提取csv文件的某列内容。
import csv
filename = 'data/sitka_weather_07-2018_simple.csv'
with open(filename) as f: #f是一个表示文件的对象
reader = csv.reader(f) #创建一个与该文件相关联的阅读器对象
header_row = next(reader) #返回文件中的下一行
#从文件中获取最高温度
highs = []
for row in reader: #遍历文件余下的各行,阅读器从其停留的地方继续往下读取csv
high = int(row[5]) #默认是字符串,转换为整数
highs.append(high)
print(highs)
2. 从csv文件读取数据并绘图
将最高温度画成折线图。
import csv
import matplotlib.pyplot as plt
filename = 'data/sitka_weather_07-2018_simple.csv'
#读取csv文件并获得最高温度
with open(filename) as f: #f是一个表示文件的对象
reader = csv.reader(f) #创建一个与该文件相关联的阅读器对象
header_row = next(reader) #返回文件中的下一行
highs = []
for row in reader: #遍历文件余下的各行,阅读器从其停留的地方继续往下读取csv
high = int(row[5]) #默认是字符串,转换为整数
highs.append(high)
#绘制温度图表
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.plot(highs, c='red')
#设置图形格式
plt.title("Daily high temperatures, July 2018", fontsize=24)
plt.xlabel('', fontsize=16)
plt.ylabel("Temperature (F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
#plt.show()
plt.savefig('03_csv_plotting.png', bbox_inches='tight')
在x轴表示日期。
import csv
from datetime import datetime
import matplotlib.pyplot as plt
filename = 'data/sitka_weather_2018_simple.csv'
#读取csv文件并获得日期和最高温度
with open(filename) as f: #f是一个表示文件的对象
reader = csv.reader(f) #创建一个与该文件相关联的阅读器对象
header_row = next(reader) #返回文件中的下一行
dates, highs = [], []
for row in reader: #遍历文件余下的各行,阅读器从其停留的地方继续往下读取csv
current_date = datetime.strptime(row[2], '%Y-%m-%d') #将字符串转换为表示日期的对象
high = int(row[5]) #默认是字符串,转换为整数
dates.append(current_date)
highs.append(high)
#绘制温度图表
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.plot(dates, highs, c='red')
#设置图形格式
ax.set_title("Daily high temperatures - 2018", fontsize=20)
ax.set_xlabel('', fontsize=13)
fig.autofmt_xdate() #绘制倾斜的日期标签
ax.set_ylabel("Temperature (F)", fontsize=13)
ax.tick_params(axis='both', which='major', labelsize=13)
#plt.show()
plt.savefig('04_csv_datetime.png', bbox_inches='tight')
增加图表内容。
import csv
from datetime import datetime
import matplotlib.pyplot as plt
filename = 'data/sitka_weather_2018_simple.csv'
#读取csv文件并获得日期、最高温度、最低温度
with open(filename) as f: #f是一个表示文件的对象
reader = csv.reader(f) #创建一个与该文件相关联的阅读器对象
header_row = next(reader) #返回文件中的下一行
dates, highs, lows = [], [], []
for row in reader: #遍历文件余下的各行,阅读器从其停留的地方继续往下读取csv
current_date = datetime.strptime(row[2], '%Y-%m-%d') #将字符串转换为表示日期的对象
high = int(row[5]) #默认是字符串,转换为整数
low = int(row[6])
dates.append(current_date)
highs.append(high)
lows.append(low)
#绘制温度图表
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.plot(dates, highs, c='red', linewidth=1, alpha=0.8)
ax.plot(dates, lows, c='blue', linewidth=1, alpha=0.8)
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
#设置图形格式
ax.set_title("Daily high temperatures - 2018", fontsize=20)
ax.set_xlabel('', fontsize=13)
fig.autofmt_xdate() #绘制倾斜的日期标签
ax.set_ylabel("Temperature (F)", fontsize=13)
ax.tick_params(axis='both', which='major', labelsize=13)
#plt.show()
plt.savefig('05_csv_adding.png', bbox_inches='tight')
3. 应对csv文件中的缺失值
如果csv文件中有缺失值,读取时会出现一个异常ValueError。
import csv
from datetime import datetime
import matplotlib.pyplot as plt
filename = 'data/death_valley_2018_simple.csv'
#读取csv文件并获得日期、最高温度、最低温度
with open(filename) as f: #f是一个表示文件的对象
reader = csv.reader(f) #创建一个与该文件相关联的阅读器对象
header_row = next(reader) #返回文件中的下一行
dates, highs, lows = [], [], []
for row in reader: #遍历文件余下的各行,阅读器从其停留的地方继续往下读取csv
current_date = datetime.strptime(row[2], '%Y-%m-%d') #将字符串转换为表示日期的对象
try: #如果下面的代码运行没有问题,将跳过except
high = int(row[4]) #默认是字符串,转换为整数
low = int(row[5])
except ValueError: #如果导致了错误,会查找匹配的except代码块并运行;后面的程序还能继续运行
print(f"Missing data for {current_date}") #或者使用pass静默失败
else: #try下面的代码执行成功后执行else代码块
dates.append(current_date)
highs.append(high)
lows.append(low)
#绘制温度图表
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.plot(dates, highs, c='red', linewidth=1, alpha=0.8)
ax.plot(dates, lows, c='blue', linewidth=1, alpha=0.8)
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
#设置图形格式
ax.set_title("Daily high and low temperatures - 2018\nDeath Valley, CA",
fontsize=18)
ax.set_xlabel('', fontsize=13)
fig.autofmt_xdate() #绘制倾斜的日期标签
ax.set_ylabel("Temperature (F)", fontsize=13)
ax.tick_params(axis='both', which='major', labelsize=13)
#plt.show()
plt.savefig('06_csv_valueerror.png', bbox_inches='tight')
4. 读取json文件
这个.json文件直接打开是这样的。
读取这个文件,然后将其转换成更易读的格式。
import json
#读取json文件
filename = 'data/eq_data_1_day_m1.json'
with open(filename) as f:
all_eq_data = json.load(f)
#保存json文件
readable_file = 'data/readable_eq_data.json'
with open(readable_file, 'w') as f:
json.dump(all_eq_data, f, indent=4)
#indent=4使用与数据结构匹配的缩进来设置数据格式
现在直接打开是这样的。
需要提取地震的位置、震级等信息。
import json
# 读取json文件
filename = 'data/eq_data_1_day_m1.json'
with open(filename) as f:
all_eq_data = json.load(f)
# 提取与键'features'相关联的数据,是一个列表,列表元素为字典,表示每一次地震
all_eq_dicts = all_eq_data['features']
print(len(all_eq_dicts))
# 提取震级
mags = []
for eq_dict in all_eq_dicts:
mag = eq_dict['properties']['mag']
mags.append(mag)
print(mags[:10])
# 提取位置信息
mags, titles, lons, lats = [], [], [], []
for eq_dict in all_eq_dicts:
mag = eq_dict['properties']['mag']
title = eq_dict['properties']['title']
lon = eq_dict['geometry']['coordinates'][0] #经度
lat = eq_dict['geometry']['coordinates'][1] #纬度
mags.append(mag)
titles.append(title)
lons.append(lon)
lats.append(lat)
print(mags[:10])
print(titles[:2])
print(lons[:5])
print(lats[:5])
5. 从json文件读取数据并绘图
感觉这一部分书上讲的有点不清楚。需要下载安装pandas。
python -m pip install --user pandas
使用plotly绘制散点图。
import json
import plotly.express as px
# 读取json文件
filename = 'data/eq_data_1_day_m1.json'
with open(filename) as f:
all_eq_data = json.load(f)
# 提取位置信息
all_eq_dicts = all_eq_data['features']
mags, titles, lons, lats = [], [], [], []
for eq_dict in all_eq_dicts:
mag = eq_dict['properties']['mag']
title = eq_dict['properties']['title']
lon = eq_dict['geometry']['coordinates'][0] #经度
lat = eq_dict['geometry']['coordinates'][1] #纬度
mags.append(mag)
titles.append(title)
lons.append(lon)
lats.append(lat)
# 绘制震级散点图
fig = px.scatter(
x=lons,
y=lats,
labels={'x':'经度','y':'纬度'},
range_x=[-200, 200],
range_y=[-90, 90],
width=800,
height=800,
title='全球地震散点图'
)
fig.write_html('09_json_plotly.html')
fig.show()
使用pandas,并增加图像细节。
import json
import plotly.express as px
import pandas as pd
# 读取json文件
filename = 'data/eq_data_30_day_m1.json'
with open(filename) as f:
all_eq_data = json.load(f)
# 提取位置信息
all_eq_dicts = all_eq_data['features']
mags, titles, lons, lats = [], [], [], []
for eq_dict in all_eq_dicts:
mag = eq_dict['properties']['mag']
title = eq_dict['properties']['title']
lon = eq_dict['geometry']['coordinates'][0] #经度
lat = eq_dict['geometry']['coordinates'][1] #纬度
mags.append(mag)
titles.append(title)
lons.append(lon)
lats.append(lat)
#创建一个DataFrame将数据封装起来
data = pd.DataFrame(
data=zip(lons, lats, titles, mags), columns=['经度', '纬度', '位置', '震级']
)
data.head()
# 绘制震级散点图
fig = px.scatter(
data,
x='经度',
y='纬度',
range_x=[-200, 200],
range_y=[-90, 90],
width=800,
height=800,
title='全球地震散点图',
size='震级',
size_max=10, #默认20像素,缩放到10
color='震级', #默认数值从小到大,颜色从蓝到红再到黄
hover_name='位置', #鼠标指向时显示的文本
)
fig.write_html('10_json_pandas.html')
fig.show()