来源:《Python编程:从入门到实践》
将文件btc_close_2017.json下载到本章程序所在的文件夹中
,也可以用Python 3.x标准库中模块urllib的函数urlopen
来做,还可以通过Python的第三方模块requests(下一章节将学习)下载数据
btc_close_2017.json
[{
"date": "2017-01-01",
"month": "01",
"week": "52",
"weekday": "Sunday",
"close": "6928.6492"
},
--SNIP--
{
"date": "2017-12-12",
"month": "12",
"week": "50",
"weekday": "Tuesday",
"close": "113732.6745"
}]
函数urlopen
来下载数据呢:btc_close_2017.py
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from urllib.request import urlopen
import json
json_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)
# 加载json格式
file_urllib = json.loads(req)
print(file_urllib)
第三方模块requests
封装了许多常用的方法,让数据下载和读取方式显得更简单:--snip--
import requests
json_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)
# 加载json格式
file_urllib = json.loads(req)
req = requests.get(json_url)
# 将数据写入文件
with open('btc_close_2017_request.json', 'w') as f:
f.write(req.text)
file_requests = req.json()
requests通过get方法向Github服务器发送请求
req.text熟悉可以直接读取文件数据,返回格式是字符串
直接用req.json()就可以将btc_close_2017.json文件的数据转换成Python列表file_requests,与之前的file_urllib内容相同
print(file_requests == file_urllib)
True
btc_close_2017.py
import json
# 将数据加载到一个列表中
filename = '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.py
--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(btc_dict['close'])
print("{} is month {} week {}, {}, the close price is {}RMB".format(date, month, week, weekday, close))
btc_close_2017.py
--snip--
# 打印每一天的信息
for btc_dict in btc_data:
--snip--
close = int(float(btc_dict['close']))
print("{} is month {} week {}, {}, the close price is {}RMB".format(date, month, week, weekday, close))
前面的章节学习了用Pygal绘制条形图(bar chart),也学习了用matplotlib绘制折线图(line chart)
下面用Pygal实现收盘价的折现图
绘制之前,先获取x、y轴数据
btc_close_2017.py
--snip--
# 创建5个列表,分别存储日期和收盘价
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'])
closes.append(int(float(btc_dict['close'])))
btc_close_2017.py
--snip--
import pygal
line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False)
line_chart.title = '收盘价 (¥)'
line_chart.x_labels = dates
N = 20 # x轴坐标每隔20天显示一次
line_chart.x_labels_major = dates[::N]
line_chart.add('收盘价', close)
line_chart.render_to_file('收盘价折线图 (¥).svg')
pygal
x_label_rotation=20——让x轴上的日期标签顺时针旋转20°
;show_minor_x_labels=False——图形不用显示所有的x轴标签
x_labels_major
属性,让x轴坐标每隔20天显示一次,这样x轴不会拥挤btc_close_2017.py
--snip--
import pygal
import math
line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False)
line_chart.title = '收盘价对数变换 (¥)'
line_chart.x_labels = dates
N = 20 # x轴坐标每隔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')
btc_close_2017.py
from itertools import groupby
def 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
def 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
idx_month = dates.index('2017-12-01')
line_chart_month = draw_line(
months[:idx_month], close[:idx_month], '收盘价月日均值(¥)', '月日均值')
line_chart_month
line_chart.x_labels = x_unique
# 横坐标必须是字符串类型,而这里x_unique的类型为int,所以引发了异常:TypeError: object of type 'int' has no len()
# 下面遍历x_unique将其转换为str类型
new_x_unique = []
for x in x_unique:
new_x_unique.append(str(x))
line_chart.x_labels = new_x_unique
idx_week = dates.index('2017-12-11')
line_chart_week = draw_line(
weeks[1:idx_week], close[1:idx_week], '收盘价周日均值(¥)', '周日均值')
line_chart_week
idx_week = dates.index('2017-12-11')
wd = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
weekdays_int = [wd.index(w) + 1 for w in weekdays[1:idx_week]]
line_chart_weekday = draw_line(weekdays_int, close[1:idx_week], '收盘价星期均值(¥)', '星期均值')
line_chart_weekday.x_labels = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
line_chart_weekday.render_to_file('收盘价星期均值(¥).svg')
btc_close_2017.py
--snip--
with open('收盘价Dashboard.html', 'w', encoding='utf8') as html_file:
html_file.write(
'收盘价Dashboard \n')
for svg in [
'收盘价折线图 (¥).svg', '收盘价对数变换折线图(¥).svg',
'收盘价月日均值(¥).svg', '收盘价周日均值(¥).svg',
'收盘价星期均值(¥).svg',
]:
html_file.write(
' \n'.format(svg))
html_file.write('')