您現在的位置是:首頁 > 垂釣
Python資料視覺化:一文看懂折線圖繪製與使用,值得收藏
- 由 華章科技 發表于 垂釣
- 2022-02-03
折線是什麼
導讀:資料分析時經常用到的折線圖,你真的懂了嗎?可以用來呈現哪些資料關係?在資料分析過程中可以解決哪些問題?怎樣用Python繪製折線圖?本文逐一為你解答。
作者:屈希峰,資深Python工程師,知乎多個專欄作者
01 概述
折線圖(Line)是將排列在工作表的列或行中的資料進行繪製後形成的線狀圖形。折線圖可以顯示隨時間(根據常用比例設定)而變化的連續資料,非常適用於顯示在相等時間間隔下資料的趨勢。
在折線圖中,資料是遞增還是遞減、增減的速率、增減的規律(週期性、螺旋性等)、峰值等特徵都可以清晰地反映出來。所以,
折線圖常用來分析資料隨時間的變化趨勢,也可用來分析多組資料隨時間變化的相互作用和相互影響。
例如,可用來分析某類商品或是某幾類相關的商品隨時間變化的銷售情況,從而進一步預測未來的銷售情況。在折線圖中,一般水平軸(x軸)用來表示時間的推移,並且間隔相同;而垂直軸(y軸)代表不同時刻的資料的大小。如圖0所示。
▲圖0 折線圖
02 例項
折線圖程式碼示例如下所示。
程式碼示例①
1# 資料 2x = [1, 2, 3, 4, 5, 6, 7] 3y = [6, 7, 2, 4, 5, 10, 4] 4# 畫布:座標軸標籤,畫布大小 5p = figure(title=“line example”, x_axis_label=‘x’, y_axis_label=‘y’, width=400, height=400) 6# 繪圖:資料、圖例、線寬 7p。line(x, y, legend=“Temp。”, line_width=2) # 折線 8# 顯示9show(p)
執行結果如圖1所示。
▲圖1 程式碼示例①執行結果
程式碼示例①仍以最簡單的方式繪製第一張折線圖。line()方法的引數說明如下。
p.line(x, y, **kwargs)引數說明
x
(:class:`~bokeh。core。properties。NumberSpec` ) : x座標。
y
(:class:`~bokeh。core。properties。NumberSpec` ) : y座標。
line_alpha
(:class:`~bokeh。core。properties。NumberSpec` ) : (default: 1。0) 輪廓線透明度。
line_cap
( :class:`~bokeh。core。enums。LineCap` ) : (default: ‘butt’) 線端。
line_color
(:class:`~bokeh。core。properties。ColorSpec` ) : (default: ‘black’) 輪廓線顏色,預設:黑色。
line_dash
(:class:`~bokeh。core。properties。DashPattern` ) : (default: []) 虛線,型別可以是序列,也可以是字串(‘solid’, ‘dashed’, ‘dotted’, ‘dotdash’, ‘dashdot’)。
line_dash_offset
(:class:`~bokeh。core。properties。Int` ) : (default: 0) 虛線偏移。
line_join
(:class:`~bokeh。core。enums。LineJoin` ) : (default: ‘bevel’)。
line_width
(:class:`~bokeh。core。properties。NumberSpec` ) : (default: 1) 線寬。
name
(:class:`~bokeh。core。properties。String` ) : 圖元名稱。
tags
(:class:`~bokeh。core。properties。Any` ) :圖元標籤。
alpha
(float) : 一次性設定所有線條的透明度。
color
(Color) : 一次性設定所有線條的顏色。
source
(ColumnDataSource) : Bokeh特有資料格式(類似於Pandas Dataframe)。
legend
(str) : 圖元的圖例。
x_range_name
(str) : x軸範圍名稱。
y_range_name
(str) : y軸範圍名稱。
level
(Enum) : 圖元渲染級別。
程式碼示例②
1p = figure(plot_width=400, plot_height=400) 2# 線段x、y位置點均為列表;兩段線的顏色、透明度、線寬 3p。multi_line([[1, 3, 2], [3, 4, 6, 6]], [[2, 1, 4], [4, 7, 8, 5]], 4color=[“firebrick”, “navy”], alpha=[0。8, 0。3], line_width=4) # 多條折(曲)線5show(p)
執行結果如圖2所示。
▲圖2 程式碼示例②執行結果
程式碼示例②第3行使用multi_line()方法,實現一次性繪製兩條折線,同時,在引數中定義不同折線的顏色。如果使用Pandas Dataframe,則可以同時繪製不同列的資料。multi_line()方法的引數說明如下。
p.multi_line(xs, ys, **kwargs)引數說明
xs
(:class:`~bokeh。core。properties。NumberSpec` ) :x座標,列表。
ys
(:class:`~bokeh。core。properties。NumberSpec` ) :y座標,列表。
其他引數同line。
程式碼示例③
1# 準備資料 2x = [0。1, 0。5, 1。0, 1。5, 2。0, 2。5, 3。0] 3y0 = [i**2 for i in x] 4y1 = [10**i for i in x] 5y2 = [10**(i**2) for i in x] 6# 建立畫布 7p = figure( 8 tools=“pan,box_zoom,reset,save”, 9 y_axis_type=“log”, title=“log axis example”, 10 x_axis_label=‘sections’, y_axis_label=‘particles’, 11 width=700, height=350) 12# 增加圖層,繪圖 13p。line(x, x, legend=“y=x”) 14p。circle(x, x, legend=“y=x”, fill_color=“white”, size=8) 15p。line(x, y0, legend=“y=x^2”, line_width=3) 16p。line(x, y1, legend=“y=10^x”, line_color=“red”) 17p。circle(x, y1, legend=“y=10^x”, fill_color=“red”, line_color=“red”, size=6) 18p。line(x, y2, legend=“y=10^x^2”, line_color=“orange”, line_dash=“4 4”) 19# 顯示 20show(p)
執行結果如圖3所示。
▲圖3 程式碼示例③執行結果
程式碼示例③第13、15、16行使用line()方法逐一繪製折線,該方法的優點是基本資料清晰,可在不同線條繪製過程中直接定義圖例。讀者也可以使用multi_line()方法一次性繪製三條折線,然後再繪製折線上的資料點。同樣,既可以在函式中預定義圖例,也可以用Lengend方法單獨進行定義,在後會對圖例進行詳細說明。
程式碼示例④
1p。legend。location = “top_left” # 圖例位於左上 2p。legend。click_policy=“hide” # 點選圖例顯示、隱藏圖形 3show(p) # 自行測試效果
執行結果如圖4所示。
▲圖4 程式碼示例④執行結果
程式碼示例④在程式碼示例③的基礎上增加了圖例的位置、顯示或隱藏圖形屬性;透過點選圖例,可實現圖形的顯示或隱藏,當折線數目較多或者顏色干擾閱讀時,可以透過該方法實現對某一條折線資料的重點關注。這種透過圖例、工具條、控制元件實現資料人機互動的視覺化方式,正是Bokeh得以在GitHub火熱的原因,建議在工作實踐中予以借鑑。
程式碼示例⑤
1# 資料 2import numpy as np 3x = np。linspace(0, 4*np。pi, 200) 4y1 = np。sin(x) 5y2 = np。cos(x) 6# 將y1+—0。9範圍外的資料設定為無窮大 7y1[y1>+0。9] = +np。inf 8y1[y1<-0。9] = -np。inf 9# 將y2+—0。9範圍外的資料採用掩碼陣列或NAN值替換 10y2 = np。ma。masked_array(y2, y2<-0。9) 11y2[y2>0。9] = np。nan 12# 圖層 13p = figure(title=“lines with missing/inf values”) 14# 繪圖x,y1 15p。line(x, y1, color=“firebrick”, line_width=2) # 磚紅色 16# 繪圖x,y2 17p。line(x, y2, color=“blue”, line_width=2) # 藍色 18show(p)
執行結果如圖5所示。
▲圖5 程式碼示例⑤執行結果
程式碼示例⑤第15、16行使用line()方法繪製兩組不同顏色的曲線。
程式碼示例⑥
1import numpy as np 2from collections import defaultdict 3from scipy。stats import norm 4from bokeh。models import HoverTool, TapTool 5from bokeh。layouts import gridplot 6from bokeh。palettes import Viridis6 7# 資料 8mass_spec = defaultdict(list) #defaultdict類的初始化函式接受一個list型別作為引數,當所訪問的鍵不存在時,可以例項化一個值作為預設值 9RT_x = np。linspace(118, 123, num=50) 10norm_dist = norm(loc=120。4)。pdf(RT_x) # loc均值;pdf輸入x,返回機率密度函式 1112# 生成6組高斯分佈的曲線 13for scale, mz in [(1。0, 83), (0。9, 55), (0。6, 98), (0。4, 43), (0。2, 39), (0。12, 29)]: 14 mass_spec[“RT”]。append(RT_x) 15 mass_spec[“RT_intensity”]。append(norm_dist * scale) 16 mass_spec[“MZ”]。append([mz, mz]) 17 mass_spec[“MZ_intensity”]。append([0, scale]) 18 mass_spec[‘MZ_tip’]。append(mz) 19 mass_spec[‘Intensity_tip’]。append(scale) 20# 線條顏色 21mass_spec[‘color’] = Viridis6 22# 畫布引數 23figure_opts = dict(plot_width=450, plot_height=300) 24hover_opts = dict( 25 tooltips=[(‘MZ’, ‘@MZ_tip’), (‘Rel Intensity’, ‘@Intensity_tip’)], # 滑鼠懸停在曲線上動態顯示資料 26 show_arrow=False, 27 line_policy=‘next’ 28) 29line_opts = dict( 30 line_width=5, line_color=‘color’, line_alpha=0。6, 31 hover_line_color=‘color’, hover_line_alpha=1。0, 32 source=mass_spec # 線條資料 33) 34# 畫布1 35rt_plot = figure(tools=[HoverTool(**hover_opts), TapTool()], **figure_opts) 36# 同時繪製多條折(曲)線 37rt_plot。multi_line(xs=‘RT’, ys=‘RT_intensity’, legend=“Intensity_tip”, **line_opts) 38# x,y軸標籤 39rt_plot。xaxis。axis_label = “Retention Time (sec)” 40rt_plot。yaxis。axis_label = “Intensity” 41# 畫布2 42mz_plot = figure(tools=[HoverTool(**hover_opts), TapTool()], **figure_opts) 43mz_plot。multi_line(xs=‘MZ’, ys=‘MZ_intensity’, legend=“Intensity_tip”, **line_opts) 44mz_plot。legend。location = “top_center” 45mz_plot。xaxis。axis_label = “MZ” 46mz_plot。yaxis。axis_label = “Intensity” 47# 顯示 48show(gridplot([[rt_plot, mz_plot]]))
執行結果如圖6所示。
▲圖6 程式碼示例⑥執行結果
程式碼示例⑥第19行中,生成繪圖資料時,同時生成圖例名稱列表;第37、43行使用multi_line()方法一次性繪製6條曲線,並預定義圖例。
程式碼示例⑦
1import numpy as np 2# 資料 3x = np。linspace(0。1, 5, 80) 4# 畫布 5p = figure(title=“log axis example”, y_axis_type=“log”, 6 x_range=(0, 5), y_range=(0。001, 10**22), 7 background_fill_color=“#fafafa”) 8# 繪圖 9p。line(x, np。sqrt(x), legend=“y=sqrt(x)”, 10 line_color=“tomato”, line_dash=“dashed”) 11p。line(x, x, legend=“y=x”) 12p。circle(x, x, legend=“y=x”) 13p。line(x, x**2, legend=“y=x**2”) 14p。circle(x, x**2, legend=“y=x**2”, 15 fill_color=None, line_color=“olivedrab”) 16p。line(x, 10**x, legend=“y=10^x”, 17 line_color=“gold”, line_width=2) 18p。line(x, x**x, legend=“y=x^x”, 19 line_dash=“dotted”, line_color=“indigo”, line_width=2) 20p。line(x, 10**(x**2), legend=“y=10^(x^2)”, 21 line_color=“coral”, line_dash=“dotdash”, line_width=2) 22# 其他 23p。legend。location = “top_left” 24# 顯示 25show(p)
執行結果如圖7所示。
▲圖7 程式碼示例⑦執行結果
程式碼示例⑦與程式碼示例③相似,第10、19、21行對曲線的屬性進行自定義,注意虛線的幾種形式(‘solid’, ‘dashed’, ‘dotted’, ‘dotdash’, ‘dashdot’),讀者可以自行替換測試。
程式碼示例⑧
1from bokeh。models import ColumnDataSource, NumeralTickFormatter, SingleIntervalTicker 2from bokeh。sampledata。us_marriages_divorces import data 3# 資料 4data = data。interpolate(method=‘linear’, axis=0)。ffill()。bfill() 5source = ColumnDataSource(data=dict( 6 year=data。Year。values, 7 marriages=data。Marriages_per_1000。values, 8 divorces=data。Divorces_per_1000。values, 9)) 10# 工具條 11TOOLS = ‘pan,wheel_zoom,box_zoom,reset,save’ 12# 畫布 13p = figure(tools=TOOLS, plot_width=800, plot_height=500, 14 tooltips=‘@$name{0。0} $name per 1,000 people in @year’) 15# 其他自定義屬性 16p。hover。mode = ‘vline’ 17p。xaxis。ticker = SingleIntervalTicker(interval=10, num_minor_ticks=0) 18p。yaxis。formatter = NumeralTickFormatter(format=‘0。0a’) 19p。yaxis。axis_label = ‘# per 1,000 people’ 20p。title。text = ‘144 years of marriage and divorce in the U。S。’ 21# 繪圖 22p。line(‘year’, ‘marriages’, color=‘#1f77b4’, line_width=3, source=source, name=“marriages”) 23p。line(‘year’, ‘divorces’, color=‘#ff7f0e’, line_width=3, source=source, name=“divorces”) 24# 顯示 25show(p)
執行結果如圖8所示。
▲圖8 程式碼示例⑧執行結果
程式碼示例⑧第22、23行透過line()方法繪製兩條曲線,嚴格上講這兩條曲線並不是Bokeh時間序列的標準繪製方法。第17行定義了x軸刻度的間隔以及中間刻度數,讀者可以嘗試將num_minor_ticks=10的顯示效果與圖8進行對比;第18行定義了y軸的資料顯示格式。
程式碼示例⑨
1import numpy as np 2from scipy。integrate import odeint 3# 資料 4sigma = 10 5rho = 28 6beta = 8。0/3 7theta = 3 * np。pi / 4 8# 洛倫茲空間向量點生成函式 9def lorenz(xyz, t): 10 x, y, z = xyz 11 x_dot = sigma * (y - x) 12 y_dot = x * rho - x * z - y 13 z_dot = x * y - beta* z 14 return [x_dot, y_dot, z_dot] 15initial = (-10, -7, 35) 16t = np。arange(0, 100, 0。006) 17solution = odeint(lorenz, initial, t) 18x = solution[:, 0] 19y = solution[:, 1] 20z = solution[:, 2] 21xprime = np。cos(theta) * x - np。sin(theta) * y 22# 調色 23colors = [“#C6DBEF”, “#9ECAE1”, “#6BAED6”, “#4292C6”, “#2171B5”, “#08519C”, “#08306B”,] 24# 畫布 25p = figure(title=“Lorenz attractor example”, background_fill_color=“#fafafa”) 26# 繪圖 洛倫茲空間向量 27p。multi_line(np。array_split(xprime, 7), np。array_split(z, 7), 28 line_color=colors, line_alpha=0。8, line_width=1。5) 29# 顯示 30show(p)
執行結果如圖9所示。
▲圖9 程式碼示例⑨執行結果
程式碼示例⑨使用multi_line()方法在二維空間展示洛倫茲空間向量,示例中的資料生成稍微有點複雜,可以直觀感受視覺化之下的資料之美,有興趣的讀者可以深入瞭解。
程式碼示例⑩
1import numpy as np 2from bokeh。layouts import row 3from bokeh。palettes import Viridis3 4from bokeh。models import CheckboxGroup, CustomJS 5# 資料 6x = np。linspace(0, 4 * np。pi, 100) 7# 畫布 8p = figure() 9# 折線屬性 10props = dict(line_width=4, line_alpha=0。7) 11# 繪圖 12l0 = p。line(x, np。sin(x), color=Viridis3[0], legend=“Line 0”, **props) 13l1 = p。line(x, 4 * np。cos(x), color=Viridis3[1], legend=“Line 1”, **props) 14l2 = p。line(x, np。tan(x), color=Viridis3[2], legend=“Line 2”, **props) 15# 複選框啟用顯示 16checkbox = CheckboxGroup(labels=[“Line 0”, “Line 1”, “Line 2”], 17 active=[0, 1, 2], width=100) 18checkbox。callback = CustomJS(args=dict(l0=l0, l1=l1, l2=l2, checkbox=checkbox), code=“”“ 19l0。visible = 0 in checkbox。active; 20l1。visible = 1 in checkbox。active; 21l2。visible = 2 in checkbox。active; 22”“”) 23# 新增圖層 24layout = row(checkbox, p) 25# 顯示 26show(layout)
執行結果如圖10所示。
▲圖10 程式碼示例⑩執行結果
程式碼示例⑩增加了Bokeh控制元件複選框,第12、13、14行使用line()方法繪製3條曲線;第16行定義複選框,並在18行定義回撥函式,透過該回調函式控制3條曲線的可視狀態;第24行將複選框、繪圖並在一行進行顯示。
程式碼示例⑪
1from bokeh。models import TapTool, CustomJS, ColumnDataSource 2# 資料 3t = np。linspace(0, 0。1, 100) 4# 回撥函式 5code = “”“ 6// cb_data = {geometries: 。。。, source: 。。。} 7const view = cb_data。source。selected。get_view(); 8const data = source。data; 9if (view) { 10 const color = view。model。line_color; 11 data[‘text’] = [‘Selected the ’ + color + ‘ line’]; 12 data[‘text_color’] = [color]; 13 source。change。emit(); 14} 15”“” 16source = ColumnDataSource(data=dict(text=[‘No line selected’], text_color=[‘black’])) 17# 畫布 18p = figure(width=600, height=500) 19# 繪圖 20l1 = p。line(t, 100*np。sin(t*50), color=‘goldenrod’, line_width=30) 21l2 = p。line(t, 100*np。sin(t*50+1), color=‘lightcoral’, line_width=20) 22l3 = p。line(t, 100*np。sin(t*50+2), color=‘royalblue’, line_width=10) 23# 文字,注意選擇線條時候的文字變化 24p。text(0, -100, text_color=‘text_color’, source=source) 25# 呼叫回撥函式進行動態互動 26p。add_tools(TapTool(callback=CustomJS(code=code, args=dict(source=source)))) 27# 顯示 28show(p)
執行結果如圖11所示。
▲圖11 程式碼示例⑪執行結果
程式碼示例⑪增加點選曲線的互動效果,第20、21、22行使用line()方法繪製3條曲線;第26行定義曲線再次被點選時的效果:圖11中左下方會動態顯示當前選中的是哪條顏色的曲線。
程式碼示例⑫
1import numpy as np 2from bokeh。models import ColumnDataSource, Plot, LinearAxis, Grid 3from bokeh。models。glyphs import Line 4# 資料 5N = 30 6x = np。linspace(-2, 2, N) 7y = x**2 8source = ColumnDataSource(dict(x=x, y=y)) 9# 畫布 10plot = Plot( 11 title=None, plot_width=300, plot_height=300, 12# min_border=0, 13# toolbar_location=None 14) 15# 繪圖 16glyph = Line(x=“x”, y=“y”, line_color=“#f46d43”, line_width=6, line_alpha=0。6)17plot。add_glyph(source, glyph) 18# x軸單獨設定(預設) 19xaxis = LinearAxis() 20plot。add_layout(xaxis, ‘below’) 21# y軸單獨設定(預設) 22yaxis = LinearAxis() 23plot。add_layout(yaxis, ‘left’) 24# 座標軸刻度 25plot。add_layout(Grid(dimension=0, ticker=xaxis。ticker)) 26plot。add_layout(Grid(dimension=1, ticker=yaxis。ticker)) 27# 顯示 28show(plot)
執行結果如圖12所示。
▲圖12 程式碼示例⑫執行結果
程式碼示例⑫使用models介面進行曲線繪製,注意第10、17、20行的繪製方法,這種繪圖方式在實踐中基本很少用到,僅作了解。
本文摘編自《Python資料視覺化:基於Bokeh的視覺化繪圖》,經出版方授權釋出。
延伸閱讀《Python資料視覺化》
推薦語:
從圖形繪製、資料動態展示、Web互動等維度全面講解Bokeh功能和使用,不含複雜資料處理和演算法,深入淺出,適合零基礎入門,包含大量案例。
上一篇:將美好留於心底,將悲傷置於腦後
下一篇:國珍酒 | 醬酒高質量發展