Python的數據可視化

Python的數據可視化

本文參考書籍:《Python編程:從入門到實踐》

html

生成數據

matplotlib:數學繪圖庫
Pygal包:專一於生成適合在數字設備上顯示的圖表
python

繪製簡單的折線圖

import matplotlib.pyplot as plt	#導入模塊pyplot,並給它指定別名爲plt
squares = [1, 4, 9, 16, 25]
#默認第一個數據點對應的x爲0,以此類推
plt.plot(squares)	#(0,1) (1,4) (2,9) (3,16) (4,25)
plt.show()

在這裏插入圖片描述

修改標籤文字和線條粗細

import matplotlib.pyplot as plt
squares = [1, 4, 9, 16, 25]
#參數linewidth決定了plot()繪製的線條的粗細
plt.plot(squares, linewidth=5)	
#設置圖表標題,並給座標軸加上標籤
#函數title()給圖表指定標題
#參數fontsize指定了圖表中文字的大小
plt.title("Square Numbers", fontsize=24)
#函數xlabel(),ylabel()爲每條軸設置標題
plt.xlabel("Value", fontsize=14)
plt.ylabel("Square of Value", fontsize=14)
#設置刻度標記的大小
#函數tick_params()設置刻度樣式,
#其中指定的實參將影響x、y軸上的刻度(axis='both')
#並將刻度標記的字號設置爲14(labelsize=14)
plt.tick_params(axis='both', labelsize=14)
plt.show()

在這裏插入圖片描述

給plot()同時提供輸入和輸出值

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 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()繪製散點圖並設置樣式

import matplotlib.pyplot as plt
#向函數scatter()傳遞一對x和y座標,
#它將在指定位置繪製一個點
plt.scatter(2, 4)
plt.show()

#設置格式
import matplotlib.pyplot as plt
#實參s設置繪製圖形時使用的點的尺寸
plt.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.show()

使用scatter()繪製一系列點

import matplotlib.pyplot as plt
#向scatter()傳遞兩個分別包含x和y值的列表
x_values = [1, 2, 3, 4, 5]
y_values = [1, 4, 9, 16, 25]
plt.scatter(x_values, y_values, s=100)
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.show()

在這裏插入圖片描述

自動計算數據,繪製1000個散點

import matplotlib.pyplot as plt
x_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)
# 設置每一個座標軸的取值範圍
# 函數axis()要求提供x和y軸的最小值和最大值
plt.axis([0, 1100, 0, 1100000])
plt.tick_params(axis='both', which='major', labelsize=14)
plt.show()

在這裏插入圖片描述

刪除數據點的輪廓

matplotlib容許給散點圖中的各個點指定顏色。默認爲藍色點和黑色輪廓。git

# 在調用scatter()時傳遞實參edgecolor='none',刪除數據點輪廓
plt.scatter(x_values,y_values,edgecolor='none',s=40)

自定義顏色

要修改數據點的顏色,可向scatter()傳遞參數c,並將其設置爲要使用的顏色的名稱github

plt.scatter(x_values, y_values, c='red', s=100)

還可以使用RGB顏色模式自定義顏色。要指定自定義顏色,可傳遞參數c,並將其設置爲一個元組,其中包含三個0~1之間的小數值,分別表明紅色、綠色、藍色份量。值越接近於0,顏色越深,越接近1顏色越淺django

plt.scatter(x_values, y_values, c=(1, 0.1, 1), s=100)

使用顏色映射

顏色映射是一系列顏色,它們從起始顏色漸變到結束顏色。在可視化中,顏色映射用於突出數據的規律,如可用較淺顏色顯示較小的值,用較深顏色顯示較大的值
模塊pyplot內置了一組顏色映射。若需使用顏色映射,需告知pyplot該如何設置數據集中每一個點的顏色
編程

# 將參數c設置爲一個y值列表,並使用參數cmap告訴pyplot使用哪一個顏色映射
#如下將y值較小的點設置爲淺藍色,y值較大的點設置爲深藍色
plt.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Blues, s=100)

在這裏插入圖片描述

自動保存圖表

要讓程序自動將圖表保存到文件中,可進行plt.savefig()調用json

#scatter_squares.py文件
#第一個實參指定要以什麼樣的文件名保存圖表
#此文件將保存在scatter_squares.py所在的目錄中
#第二個實參指定將圖表多餘的空白區域裁剪掉
plt.savefig('squares_plot.png',bbox_inches='tight')

隨機漫步

隨機漫步是這樣行走獲得的路徑:每次行走都徹底是隨機的,沒有明確的方向,結果是由一系列隨機決策決定的flask

建立RandomWalk()類

RandomWalk類隨機地選擇前進方向,這個類需三個屬性,其一爲存儲隨機漫步次數的變量,其餘兩個爲列表,分別存儲隨機漫步通過的每一個點的x和y座標api

from random import choice
#在每次決策時使用choice()來決定使用哪一種選擇
class RandomWalk()def __init__(self,num_points=5000):
		#初始化隨機漫步的屬性
		self.num_points=num_points
		#全部隨機漫步都始於(0,0)
		self.x_values=[0]
		self.y_values=[0]

選擇方向

在RandomWalk類中添加fill_walk()來生成漫步包含的點,並決定每次漫步的方向服務器

def fill_walk(self):
	#計算隨機漫步包含的全部點
	#不斷漫步,直到列表達到指定的長度
	while len(self.x_values)<self.num_points:
		#決定前進方向以及沿這個方向前進的距離
		x_direction=choice([1,-1])
		#給x_direction選擇一個值
		#表示向右走1或向左走1
		x_distance=choice([0,1,2,3,4])
		#隨機選擇一個0~4之間的整數
		#告知沿指定的方向走多遠
		x_step=x_direction*x_distance
		#將移動方向乘以移動距離
		#肯定沿x軸移動的距離
		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
		#計算下一個點的x和y值
		#將x_step和x_values中最後一個值相加
		next_x=self.x_values[-1]+x_step
		next_y=self.y_values[-1]+y_step
		#得到下一個點的x、y後,附加到列表末尾
		self.x_values.append(next_x)
		self.y_values.append(next_y)

繪製隨機漫步圖

import matplotlib.pyplot as plt
from random_walk import RandomWalk
#建立一個RandomWalk實例,並將其包含的點都繪製出來
rw = RandomWalk()
rw.fill_walk()
plt.scatter(rw.x_values, rw.y_values, s=15)
plt.show()

在這裏插入圖片描述

模擬屢次隨機漫步

import matplotlib.pyplot as plt
from random_walk import RandomWalk
#只要程序處於活動狀態,就不斷進行模擬隨機漫步
while 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

import matplotlib.pyplot as plt
from random_walk import RandomWalk
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, edgecolors='none', s=15)
    plt.show()

    keep_running = input("Make another walk? (y/n): ")
    if keep_running == 'n':
        break

在這裏插入圖片描述

從新繪製起點和終點

讓起點和終點變得更大,並顯示爲不一樣的顏色

import matplotlib.pyplot as plt
from random_walk import RandomWalk
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, edgecolors='none', s=15)
    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

在這裏插入圖片描述

隱藏座標軸

使用函數plt.axes()將每條座標軸的可見性設爲False

import matplotlib.pyplot as plt
from random_walk import RandomWalk
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, edgecolors='none', s=15)
    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.axes().get_xaxis().set_visible(False)
    plt.axes().get_yaxis().set_visible(False)
    plt.show()

    keep_running = input("Make another walk? (y/n): ")
    if keep_running == 'n':
        break

在這裏插入圖片描述

增長點數

在建立RandomWalk實例時增長new_points的值,並調整每一個點的大小

import matplotlib.pyplot as plt
from random_walk import RandomWalk
while True:
    rw = RandomWalk(50000)
    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, edgecolors='none', s=1)
    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.axes().get_xaxis().set_visible(False)
    plt.axes().get_yaxis().set_visible(False)
    plt.show()

    keep_running = input("Make another walk? (y/n): ")
    if keep_running == 'n':
        break

在這裏插入圖片描述

調整尺寸以適合屏幕

函數figure()用於指定圖表的寬度、高度、分辨率和背景色。需給形參figsize指定一個元組,向matplotlib指出繪圖窗口的尺寸,單位爲英寸

import matplotlib.pyplot as plt
from random_walk import RandomWalk
while True:
    rw = RandomWalk(50000)
    rw.fill_walk()
    # 設置繪圖窗口的尺寸
    plt.figure(figsize=(10, 6))
    point_numbers = list(range(rw.num_points))
    plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolors='none', s=1)
    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.axes().get_xaxis().set_visible(False)
    plt.axes().get_yaxis().set_visible(False)
    plt.show()

    keep_running = input("Make another walk? (y/n): ")
    if keep_running == 'n':
        break

還可用形參dpi向figure()傳遞分辨率

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

使用Pygal模擬擲骰子

建立Die類

下面的類模擬擲一個骰子

from random import randint

class Die():
    
    def __init__(self, num_sides=6):
        self.num_sides = num_sides
    
    def roll(self):
    	# 返回一個位於1和骰子面數之間的隨機值
        return randint(1, self.num_sides)

方法__init__()接受一個可選參數,建立這個類的實例時,若沒有指定任何實參,面數默認爲6;若指定了實參,這個值將用於設置骰子的面數。

擲骰子

from die import Die
die = Die()
# 擲幾回骰子,並將結果存儲在一個列表中
results = []
for roll_num in range(100):
    result = die.roll()
    results.append(result)
    
print(results)

分析結果

計算每一個點數出現的次數

from die import Die
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)

print(frequencies)

繪製直方圖

import pygal
from die import Die
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)
# 建立條形圖,建立pygal.Bar()實例
hist = pygal.Bar()

hist.title = "Results of rolling one D6 1000 times."
hist.x_labels = ['1', '2', '3', '4', '5', '6']
hist.x_title = "Result"
hist.y_title = "Frequency of Result"

# 使用add()將一系列值添加到圖表中(向它傳遞要給添加的值指定的標籤,還有
# 一個列表,其中包含將出如今圖表中的值)
hist.add('D6', frequencies)
# 將直方圖渲染爲SVG文件
hist.render_to_file('die_visual.svg')

在這裏插入圖片描述

同時擲兩個骰子

import pygal
from die import Die
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 = "Results of rolling two D6 1000 times."
hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
hist.x_title = "Result"
hist.y_title = "Frequency of Result"

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

在這裏插入圖片描述

同時擲兩個面數不一樣的骰子

import pygal
from die import Die
die_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)

hist = pygal.Bar()

hist.title = "Results of rolling a D6 and a D10 50,000 times."
hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16']
hist.x_title = "Result"
hist.y_title = "Frequency of Result"

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

在這裏插入圖片描述

下載數據

CSV文件格式

要在文本文件中存儲數據,可將數據做爲一系列以逗號分隔的值(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模塊包含在Python標準庫中,可用於分析CSV文件中的數據行

import csv

# 將要使用的文件名稱存儲在filename中
filename = 'sitka_weather_07-2014.csv'
# 打開這個文件,並將結果文件對象存儲在f中
with open(filename) as f:
# 調用csv.reader(),並將前面存儲的文件對象做爲實參傳遞
# 給它,從而建立一個與該文件相關聯的閱讀器(reader)對# 象。將這個閱讀器對象存儲在reader中
    reader = csv.reader(f)
# 模塊csv的reader類包含next()方法,調用內置函數next()
# 並將一個reader做爲參數傳遞給它時,將調用reader的
# next()方法,從而返回文件的下一行。此處只調用了next()
# 一次,所以獲得的是文件的第一行,其中包含文件頭。將
# 返回的數據存儲在header_row中
# reader處理文件中以逗號分隔的第一行數據,並將每項數據
# 都做爲一個元素存儲在列表中
    header_row = next(reader)
    print(header_row)

打印文件頭及其位置

將列表中的每一個文件頭及其位置打印出來

import csv

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

# 對列表調用了enumerate()來獲取每一個元素的索引及其值
    for index, column_header in enumerate(header_row):
        print(index, column_header)

提取並讀取數據

import csv

# 從文件中獲取最高氣溫
filename = 'sitka_weather_07-2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader)

    highs = []
    for row in reader:
# 閱讀器對象從其停留的地方繼續向下讀取CSV文件,每次都
# 自動返回當前所處位置的下一行
        highs.append(row[1])

    print(highs)

使用int()將這些字符串轉換爲數字,讓matplotlib能讀取它們:

for row in reader:
        high = int(row[1])
        highs.append(high)

繪製氣溫圖表

使用matplotlib建立一個顯示每日最高氣溫的簡單圖形:

import csv

from matplotlib import pyplot as plt
filename = 'sitka_weather_07-2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader)

    highs = []
    for row in reader:
        high = int(row[1])
        highs.append(high)

    fig = plt.figure(dpi=128, figsize=(10, 6))
    # 將最高氣溫列表傳給plot()
    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

在圖表中添加日期
應將日期字符串轉換爲一個表示相應日期的對象,可以使用模塊datetime中的方法strptime()
在這裏插入圖片描述
導入m-模塊datetime中的datetime類,而後調用方法strptime(),並將包含所需日期的字符串做爲第一個實參。第二個實參告知如何設置日期的格式。
在此示例中,’%Y-‘將字符串中第一個連字符前面的部分視爲四位的年份;’%m-‘將第二個連字符前面的部分視爲表示月份的數字;’%d-'將字符串的最後一部分視爲月份中的一天



模塊datetime中設置日期和時間格式的實參:

%A			# 星期的名稱,如Monday
%B			# 月份名,如January
%m			# 用數字表示的月份(01~12)
%d			# 用數字表示月份中的一天(01~31)
%Y			# 四位的年份,如2015
%y			# 兩位的年份,如15
%H			# 24小時制的小時數(00~23)
%I			# 12小時制的小時數(01~12)
%p			# am或pm
%M			# 分鐘數(00~59)
%S			# 秒數(00~61) 

在圖表中添加日期

import csv
from datetime import datetime
from matplotlib import pyplot as plt
filename = '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)

    fig = 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)
    #調用斜的日期標籤,以避免彼此重疊
    fig.autofmt_xdate()
    plt.ylabel("Temperature (F)", fontsize=16)
    plt.tick_params(axis='both', which='major', labelsize=16)

    plt.show()

在這裏插入圖片描述

涵蓋更長的時間

import csv
from datetime import datetime
from matplotlib import pyplot as plt
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')
    xlim1 = datetime.strptime("2014-1", "%Y-%m")
    xlim2 = datetime.strptime("2014-12", "%Y-%m")
    plt.xlim([xlim1, xlim2])
    plt.title("Daily high temperatures - 2014", fontsize=24)
    plt.xlabel('', fontsize=16)
    fig.autofmt_xdate()
    plt.ylabel("Temperature (F)", fontsize=16)
    plt.tick_params(axis='both', which='major', labelsize=16)

    plt.show()

在這裏插入圖片描述

再繪製一個數據系列

添加最低溫數據

import csv
from datetime import datetime
from matplotlib import pyplot as plt
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(row[3])
        lows.append(low)

    fig = plt.figure(dpi=128, figsize=(10, 6))
    plt.plot(dates, highs, c='red')
    plt.plot(dates, lows, c='blue')
    xlim1 = datetime.strptime("2014-1", "%Y-%m")
    xlim2 = datetime.strptime("2014-12", "%Y-%m")
    plt.xlim([xlim1, xlim2])
    plt.ylim([10, 80])
    plt.title("Daily high and low temperatures - 2014", fontsize=24)
    plt.xlabel('', fontsize=16)
    fig.autofmt_xdate()
    plt.ylabel("Temperature (F)", fontsize=16)
    plt.tick_params(axis='both', which='major', labelsize=16)

    plt.show()

在這裏插入圖片描述

給圖表區域着色

經過着色呈現天天的氣溫範圍
使用方法fill_between(),它接受一個x值系列和兩個y值系列,並填充兩個y值系列之間

import csv
from datetime import datetime
from matplotlib import pyplot as plt
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(row[3])
        lows.append(low)

    fig = plt.figure(dpi=128, figsize=(10, 6))
    # alpha指定顏色的透明度,alpha=0表示徹底透明,1(默認設置)表示徹底
    # 不透明 
    plt.plot(dates, highs, c='red', alpha=0.5)
    plt.plot(dates, lows, c='blue', alpha=0.5)
    #實參facecolor指定了填充區域的顏色
    plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
    xlim1 = datetime.strptime("2014-1", "%Y-%m")
    xlim2 = datetime.strptime("2014-12", "%Y-%m")
    plt.xlim([xlim1, xlim2])
    plt.ylim([10, 80])
    plt.title("Daily high and low temperatures - 2014", fontsize=24)
    plt.xlabel('', fontsize=16)
    fig.autofmt_xdate()
    plt.ylabel("Temperature (F)", fontsize=16)
    plt.tick_params(axis='both', which='major', labelsize=16)

    plt.show()

在這裏插入圖片描述

錯誤檢查

在從CSV文件中讀取值時執行錯誤檢查代碼,對分析數據集時可能出現的異常進行處理

import csv
from datetime import datetime
from matplotlib import pyplot as plt
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代碼塊
        else:
            dates.append(current_date)
            highs.append(high)
            lows.append(low)

    fig = plt.figure(dpi=128, figsize=(11, 7))
    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)
    xlim1 = datetime.strptime("2014-1", "%Y-%m")
    xlim2 = datetime.strptime("2014-12", "%Y-%m")
    plt.xlim([xlim1, xlim2])
    plt.ylim([20, 120])
    plt.title("Daily high and low temperatures - 2014\nDeath Valley,CA", fontsize=24)
    plt.xlabel('', fontsize=16)
    fig.autofmt_xdate()
    plt.ylabel("Temperature (F)", fontsize=16)
    plt.tick_params(axis='both', which='major', labelsize=16)

    plt.show()

運行後顯示:
在這裏插入圖片描述
在這裏插入圖片描述

製做交易收盤價走勢圖:JSON格式

下載收盤價數據

1.使用函數urlopen來下載數據

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'
# urlopen(json_url)是將json_url網址傳入urlopen函數
response = urlopen(json_url)
# 讀取數據
req = response.read()
# 將數據寫入文件
with open('btc_close_2017_urllib.json','wb') as f:
    f.write(req)
# 加載json格式
# 用函數json.load()將文件內容轉換成Python能處理的格式
file_urllib = json.loads(req)
print(file_urllib)

2.第三方模塊requests可更簡單的下載數據

import requests

json_url = 'https://raw.githubusercontent.com/muxuezi/btc/master/btc_close_2017.json'
# requests經過get方法向GitHub服務器發送請求
# GitHub服務器響應請求後,返回的結果存儲在req變量中
req = requests.get(json_url)
# 將數據寫入文件
with open('btc_close_2017_request.json','w') as f:
# req.text屬性能夠直接讀取文件數據,返回格式是字符串
    f.write(req.text)
# 直接用req.json()可將btc_close_2017.json文件的數據轉換爲
# Python列表file_requests
file_requests = req.json()

提取相關的數據

import json
# 將數據加載到一個列表中
filename = 'btc_close_2017_request.json'
with open(filename) as f:
# 將數據存儲在btc_data中

    btc_data = json.load(f)
    
# 遍歷btc_data中的每一個元素,每一個元素都是一個字典,包含5個鍵值對
# btc_dict用於存儲字典中的每一個鍵值對,以後取出全部鍵的值

# 打印每一天的信息
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))

將字符串轉換爲數字值

Python不能直接將包含小數點的字符串轉換爲整數,需先將字符串轉換爲浮點數,再將浮點數轉換爲整數(截尾取整)

import json

filename = 'btc_close_2017_request.json'
with open(filename) as f:
    btc_data = json.load(f)
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))

繪製收盤價折線圖

使用Pygal繪製折線圖

import json
import pygal
filename = 'btc_close_2017_request.json'
with open(filename) as f:
    btc_data = json.load(f)
# 建立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'])
    close.append(int(float(btc_dict['close'])))

# 在建立Line實例時,分別設置了x_label_rotation與
# show_minor_x_labels做爲初始化參數
# x_label_rotation=20讓x軸上的日期標籤順時針旋轉20度
# show_minor_x_labels=False告知圖形不用顯示全部的x標
# 籤
line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False)
line_chart.title = '收盤價(¥)'
line_chart.x_labels = dates
N = 20
# 配置x_labels_major屬性,讓x軸座標每隔20天顯示一次
line_chart.x_labels_major = dates[::N]
line_chart.add('收盤價', close)
line_chart.render_to_file('收盤價折線圖(¥).svg')

在這裏插入圖片描述

時間序列特徵初探

利用Pyhton標準庫的數學模塊math中的半對數變換

import json
import pygal
import math
filename = 'btc_close_2017_request.json'
with open(filename) as f:
    btc_data = json.load(f)
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'])))

line_chart = pygal.Line(x_label_rotation=20, show_minor_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('收盤價', close_log)
line_chart.render_to_file('收盤價對數變換折線圖(¥).svg')

在這裏插入圖片描述

收盤價均值

繪製一段時間內的日均值
因爲需將數據按月份、週數、周幾分組,再計算每組的均值,所以導入模塊
itertools的函數groupby

from itertools import groupby


def draw_line(x_date, y_data, title, y_legend):
    xy_map = []
    # 將x與y軸的數據合併、排序,再用函數groupby分組
    for x, y in groupby(sorted(zip(x_date,y_data)), key=lambda _: _[0]):
        y_list = [v for _, v in y]
        # 求出每組的均值,存儲到xy_map變量中
        xy_map.append([x,sum(y_list) / len(y_list)])
    # 將xy_map中存儲的x與y軸數據分離
    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

在這裏插入圖片描述
繪製週日均值:

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的內容替換爲1~7的整數
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')

在這裏插入圖片描述

收盤價數據儀表盤

將前面繪製的圖整合在一塊兒

import json
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

Web API是網站的一部分,用於與使用很是具體的URL請求特定信息的程序交互。這種稱爲API調用。請求的數據將以易於處理的格式(json或csv)返回

使用API調用請求數據

https://api.github.com/search/repositories?q=language:python&sort=stars

# 此調用返回Github當前託管了多少個Python項目,
# 還有有關最受歡迎的Python倉庫的信息

# 第一部分(https://api.github.com/)將請求發送到Github網站上響應API
# 調用的部分
# 接下來的一部分(search/repositories)讓API搜索Github上的全部倉庫
# repositories後的問號指出咱們要傳遞一個實參。q表示查詢,等號讓咱們能
# 開始指定查詢。經過使用language:python,指出只想獲取主要語言爲
# Python的倉庫的信息,最後一部分(&sort=stars)指定將項目按星級排序

requests

requests包能向網站請求信息以及檢查返回的響應

處理API響應

import requests

# 執行API調用並存儲響應
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
r = requests.get(url)
# 響應對象包含一個名爲status_code的屬性,它讓咱們知道請求是否成功
# (狀態碼200表示請求成功)
print("Status code:", r.status_code)

# 將API響應存儲在一個變量中
# 方法json()將信息轉換爲一個Python字典
response_dict = r.json()
# 打印字典中的鍵
print(response_dict.keys())

處理響應字典

import requests

url = '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'])

# 與'items'相關聯的值是一個列表,其中包含不少字典,而每一個字典
# 都包含有關一個Python倉庫的信息,將此字典列表存儲在repo_dicts中
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)

提取repo_dict中與一些鍵相關聯的值:

import requests

url = '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("\nSelected information about first repository:")
print('Name:', repo_dict['name'])
print('Owner:', repo_dict['owner']['login'])
print('Stars:', repo_dict['stargazers_count'])
print('Repository:', repo_dict['html_url'])
print('Created:', repo_dict['created_at'])
print('Updated:', repo_dict['updated_at'])
print('Description:', repo_dict['description'])

打印API調用返回的信息:概述最受歡迎的倉庫

打印API調用返回的每一個倉庫的特定信息

import requests

url = '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))

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('Repository:', repo_dict['html_url'])
    print('Description:', repo_dict['description'])

使用Pygal可視化倉庫信息

繪製交互式條形圖,呈現Github上Python項目的受歡迎程度。條形的高度表示項目得到的star數,單擊條形將進入項目在Github上的主頁

import requests
import pygal
from pygal.style import LightColorizedStyle as LCS, LightenStyle as LS

url = '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'])

# 使用LightenStyle類定義了一種樣式,並將其基色設爲深藍色
# 傳遞了實參base_style,以使用LightColorizedStyle類
my_style = LS('#333366', base_style=LCS)
# 使用Bar()建立條形圖,並向它傳遞了my_style
# 還傳遞了兩個樣式實參:標籤繞x軸旋轉45度,並隱藏圖例
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')

在這裏插入圖片描述

改進Pygal圖表

建立一個配置對象,在其中包含要傳遞給Bar()的全部定製

import requests
import pygal
from pygal.style import LightColorizedStyle as LCS, LightenStyle as LS

url = '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)
# 建立一個Pygal類Config的實例my_config,經過修改它的屬性,可定製圖表的外觀
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
# 使用truncate_label將較長的項目名縮短爲15個字符
# (將鼠標指向被截短的項目名,將顯示完整的項目名)
my_config.truncate_label = 15
# 隱藏圖表中的水平線
my_config.show_y_guides = False
# 自定義寬度
my_config.width = 1000

# 將my_config做爲第一個實參,傳遞全部配置設置
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')

添加自定義工具提示

在Pygal中,將鼠標移向條形將顯示它表示的信息,此一般稱爲工具提示
建立一個自定義工具提示,以同時顯示項目的描述:

import pygal
from pygal.style import LightColorizedStyle as LCS, LightenStyle as LS

my_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的列表,其中包含3個字典,每一個字典包含2個鍵
# Pygal根據與'label'相關聯的字符串給條形建立工具提示
plot_dicts = [
    {'value': 46762, 'label': 'Description of httpie.'},
    {'value': 49445, 'label': 'Description of django.'},
    {'value': 50420, 'label': 'Description of flask.'},
    ]

# add()方法接受一個字符串和一個列表
chart.add('', plot_dicts)
chart.render_to_file('bar_descriptions.svg')

在這裏插入圖片描述

根據數據繪圖

自動生成plot_dicts:

import requests
import pygal
from pygal.style import LightColorizedStyle as LCS, LightenStyle as LS

url = '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, 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)
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('', plot_dicts)
chart.render_to_file('python_repos.svg')

在圖表中添加可單擊的連接

Pygal容許將圖表中的每一個條形用做網站的連接
在爲每一個項目建立的字典中,添加一個鍵爲’xlink’的鍵-值對

plot_dict = {
        'value': repo_dict['stargazers_count'],
        'label': repo_dict['description'],
        'xlink': repo_dict['html_url']
    }

Hacker News網站的 API調用

使用Hacker News網站的API調用
返回最熱門的文章信息:

https://hacker-news.firebaseio.com/v0/item/9884165.json

返回Hacker News上當前熱門文章的ID,再查看每篇排名靠前的文章:

import requests

from operator import itemgetter

# 執行API調用並存儲響應
# 此API調用返回hacker-news上最熱門的500篇文章的id
url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
r = requests.get(url)
print("Status code:", r.status_code)

# 將響應文本轉換爲python列表
submission_ids = r.json()
# submission_dicts用於存儲字典
submission_dicts = []
# 遍歷id,對於每篇文章都執行一次API調用
for submission_id in submission_ids[:30]:
	# url包含submission_id的當前值
    url = ('https://hacker-news.firebaseio.com/v0/item' + str(submission_id) + '.json')
    submission_r = requests.get(url)
    print(submission_r.status_code)
    response_dict = submission_r.json()
    
    # 爲當前處理的文章建立字典
    # 存儲文章標題、頁面連接、評論數
    submission_dict = {
        'title': response_dict['title'],
        'link': 'http://news.ycombinator.com/item?id=' + str(submission_id),
        # 不肯定某個鍵是否包含在字典中時,可以使用方法dict.get()
        # 它在指定的鍵存在時返回與其關聯的值,不存在時返回指定的值(此爲0)
        'comments': response_dict.get('descendants', 0)
        }
    submission_dicts.append(submission_dict)
    
# 根據評論數對字典列表排序,使用了模塊operator中的函數itemgetter()
# 向此函數傳遞了鍵'comments',它將從這個列表中的沒個字典中提取與該鍵
# 關聯的值,sorted()將根據這種值對列表進行排序(此處爲降序排列)
submission_dicts = sorted(submission_dicts, key=itemgetter('comments'), reverse = True)

# 遍歷排序後的列表,打印信息
for submission_dict in submission_dicts:
    print("\nTitle:", submission_dict['title'])
    print("Discussion link:", submission_dict['link'])
    print("Comments:", submission_dict['comments'])
相關文章
相關標籤/搜索