Python入门:数据可视化(2)

这是《Python编程:从入门到实践》的第二个实践项目的第二部分,对应第16章,对CSVJSON格式的数据绘制图表。


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()获取每个元素的索引及其值
01_csv_headers.JPG

其它的一些读取文件内容的方法。

#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')
03_csv_plotting.png

在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')
04_csv_datetime.png

增加图表内容。

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')
05_csv_adding.png

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')
06_csv_valueerror.png

4. 读取json文件

这个.json文件直接打开是这样的。

07 eq_data_1_day_m1.JPG

读取这个文件,然后将其转换成更易读的格式。

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使用与数据结构匹配的缩进来设置数据格式

现在直接打开是这样的。

07 readable_eq_data.JPG

需要提取地震的位置、震级等信息。

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])
08_json_extracting.JPG

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()
09_json_plotly.JPG

使用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()
10_json_pandas.JPG

你可能感兴趣的:(Python入门:数据可视化(2))