什么是气泡图?怎样用Python绘制?有什么用?终于有人讲明白了
導(dǎo)讀:什么是氣泡圖?可以用來呈現(xiàn)哪些數(shù)據(jù)關(guān)系?在數(shù)據(jù)分析過程中可以解決哪些問題?怎樣用Python繪制氣泡圖?本文逐一為你解答。
作者:屈希峰
來源:大數(shù)據(jù)DT(ID:bigdatadt)
01 概述
氣泡圖(Bubble)是一種多變量圖表,是散點圖的變體,也可以認(rèn)為是散點圖和百分比區(qū)域圖的組合。其可用于展示三個變量之間的關(guān)系,和散點圖一樣,繪制時將一個變量放在橫軸,另一個變量放在縱軸,而第三個變量則用氣泡的大小來表示。
排列在工作表的列中的數(shù)據(jù)(第一列中列出x值,在相鄰列中列出相應(yīng)的y值和氣泡大小的值)可以繪制在氣泡圖中。
氣泡圖與散點圖相似,不同之處在于:氣泡圖允許在圖表中額外加入一個表示大小的變量進(jìn)行對比,而第四維度的數(shù)據(jù)則可以通過不同的顏色來表示(甚至在漸變中使用陰影來表示)。
另一種使用氣泡元素的流行方法是使用氣泡地圖。在氣泡地圖中,x和y分別代表一個地理位置的經(jīng)緯坐標(biāo)。在不要求定位非常精確的情況下,氣泡地圖可以將數(shù)據(jù)的相對集中度完美地體現(xiàn)在地理背景中。
此外,表示時間維度的數(shù)據(jù)時,可以將時間維度作為直角坐標(biāo)系中的一個維度,或者結(jié)合動畫來表現(xiàn)數(shù)據(jù)隨著時間的變化情況。
氣泡圖通常用于比較和展示不同類別圓點(這里我們稱為氣泡)之間的關(guān)系,通過氣泡的位置以及面積大小。從整體上看,氣泡圖可用于分析數(shù)據(jù)之間的相關(guān)性。
但需要注意的是,氣泡圖的數(shù)據(jù)大小容量有限,氣泡太多會使圖表難以閱讀。但是可以通過增加一些交互行為彌補(bǔ):隱藏一些信息,當(dāng)鼠標(biāo)點擊或者懸浮時顯示,或者添加一個選項用于重組或者過濾分組類別。
最后,氣泡的大小是映射面積而非半徑或直徑,如果是基于半徑或者直徑,圓的大小不僅會呈現(xiàn)指數(shù)級的變化,而且還會導(dǎo)致視覺上的誤差。如圖1所示。
▲圖1 氣泡圖
02 實例
氣泡圖的代碼如代碼示例①所示。
代碼示例①
1#?簡單氣泡圖?? 2x=[1,2,3,4]?? 3y=[2,4,6,8]?? 4sizes?=?np.array(y)*5?#?氣泡大小,單位屏幕像素?? 5p?=?figure(title="bubble?chart")?? 6p.scatter(x,?y,?marker="circle",?size=sizes,?color="navy",?? 7#?????fill_color=None,?line_width=2?? 8?????????)?? 9show(p)運行結(jié)果如圖2所示。
▲圖2 代碼示例①運行結(jié)果
從代碼示例①中的第6行可以看出,氣泡圖的繪制仍使用散點圖法,稍微不同的是在該方法中定義了散點數(shù)據(jù)的尺寸(size)大小。除此之外,可以再增加一個維度,用不同的氣泡顏色進(jìn)行數(shù)據(jù)分類。
代碼示例②
1#?復(fù)雜氣泡圖,完整代碼??2import?pandas?as?pd??3from?bokeh.embed?import?file_html??4from?bokeh.io?import?output_notebook,?show??5from?bokeh.layouts?import?layout??6from?bokeh.models?import?(??7???????ColumnDataSource,?Plot,?Circle,?Range1d,?LinearAxis,?HoverTool,???8?????Text,?SingleIntervalTicker,?Slider,?CustomJS,?Legend,?LegendItem,?CategoricalColorMapper)??#?底層樣式??9from?bokeh.palettes?import?Spectral6??10#?from?data?import?process_data??11import?numpy?as?np??12def?process_data():??13????from?bokeh.sampledata.gapminder?import?fertility,?life_expectancy,?population,?regions??1415????#?Make?the?column?names?ints?not?strings?for?handling??16????columns?=?list(fertility.columns)??17????years?=?list(range(int(columns[0]),?int(columns[-1])))??18????rename_dict?=?dict(zip(columns,?years))??1920????fertility?=?fertility.rename(columns=rename_dict)??21????life_expectancy?=?life_expectancy.rename(columns=rename_dict)??22????population?=?population.rename(columns=rename_dict)??23????regions?=?regions.rename(columns=rename_dict)??24????regions_list?=?list(regions.Group.unique())??2526????#?Turn?population?into?bubble?sizes.?Use?min_size?and?factor?to?tweak.??27????scale_factor?=?200??28????population_size?=?np.sqrt(population?/?np.pi)?/?scale_factor??29????min_size?=?3??30????population_size?=?population_size.where(population_size?>=?min_size).fillna(min_size)??3132????return?fertility,?life_expectancy,?population_size,?regions,?years,?regions_list??3334#?數(shù)據(jù)預(yù)處理,感興趣的讀者可以在Pandas提前處理好直接加載??35fertility_df,?life_expectancy_df,?population_df_size,?regions_df,?years,?regions_list?=?process_data()??36sources?=?{}??37region_name?=?regions_df.Group??38region_name.name?=?'region'??39for?year?in?years:??40???????fertility?=?fertility_df[year]??41???????fertility.name?=?'fertility'??42???????life?=?life_expectancy_df[year]??43???????life.name?=?'life'???44???????population?=?population_df_size[year]??45???????population.name?=?'population'???46???????new_df?=?pd.concat([fertility,?life,?population,?region_name],?axis=1)??47???????sources['_'?+?str(year)]?=?ColumnDataSource(new_df)??48dictionary_of_sources?=?dict(zip([x?for?x?in?years],?['_%s'?%?x?for?x?in?years]))49js_source_array?=?str(dictionary_of_sources).replace("'",?"")??50#?畫布參數(shù)??51xdr?=?Range1d(1,?9)??52ydr?=?Range1d(20,?100)??53plot?=?Plot(??54????????x_range=xdr,??55????????y_range=ydr,??56????????plot_width=800,??57????????plot_height=400,??58????????outline_line_color=None,??59????????toolbar_location=None,???60????????min_border=20,??61)??62#?坐標(biāo)軸參數(shù)??63AXIS_FORMATS?=?dict(??64????????minor_tick_in=None,??65????????minor_tick_out=None,??66????????major_tick_in=None,??67????????major_label_text_font_size="10pt",??68????????major_label_text_font_style="normal",??69????????axis_label_text_font_size="10pt",??7071????????axis_line_color='#AAAAAA',??72????????major_tick_line_color='#AAAAAA',??73????????major_label_text_color='#666666',??7475????????major_tick_line_cap="round",??76????????axis_line_cap="round",??77????????axis_line_width=1,??78????????major_tick_line_width=1,??79)??80xaxis?=?LinearAxis(ticker=SingleIntervalTicker(interval=1),?axis_label="Children?per?woman?(total?fertility)",?**AXIS_FORMATS)??81yaxis?=?LinearAxis(ticker=SingleIntervalTicker(interval=20),?axis_label="Life?expectancy?at?birth?(years)",?**AXIS_FORMATS)?????82plot.add_layout(xaxis,?'below')??83plot.add_layout(yaxis,?'left')??84#?添加年份圖層(最底層)??85text_source?=?ColumnDataSource({'year':?['%s'?%?years[0]]})??86text?=?Text(x=2,?y=35,?text='year',?text_font_size='150pt',?text_color='#EEEEEE')??87plot.add_glyph(text_source,?text)??88#?色盤,分類映射??89color_mapper?=?CategoricalColorMapper(palette=Spectral6,?factors=regions_list)?90#?繪制氣泡(散點)??91renderer_source?=?sources['_%s'?%?years[0]]??92circle_glyph?=?Circle(??93????????x='fertility',?y='life',?size='population',??94????????fill_color={'field':?'region',?'transform':?color_mapper},???95????????fill_alpha=0.8,???96????????line_color='#7c7e71',?line_width=0.5,?line_alpha=0.5)??97#?添加圖層??98circle_renderer?=?plot.add_glyph(renderer_source,?circle_glyph)??99#?添加hover工具?? 100tooltips?=?"@index"?? 101plot.add_tools(HoverTool(tooltips=tooltips,?renderers=[circle_renderer]))?? 102#?添加滾動條空間?? 103code?=?"""? 104????var?year?=?slider.value,? 105???????????sources?=?%s,? 106???????????new_source_data?=?sources[year].data;? 107????renderer_source.data?=?new_source_data;? 108????text_source.data?=?{'year':?[String(year)]};? 109"""?%?js_source_array?? 110#?數(shù)據(jù)回調(diào)?? 111callback?=?CustomJS(args=sources,?code=code)?? 112slider?=?Slider(start=years[0],?end=years[-1],?value=1,?step=1,?title="Year",?callback=callback)?? 113callback.args["renderer_source"]?=?renderer_source?? 114callback.args["slider"]?=?slider?? 115callback.args["text_source"]?=?text_source?? 116#?顯示?? 117show(layout([[plot],?[slider]],?sizing_mode='scale_width'))??運行結(jié)果如圖3所示。
▲圖3 代碼示例②運行結(jié)果
代碼示例②第92行采用models接口進(jìn)行氣泡繪制,并使用滑塊控件進(jìn)行不同年份數(shù)據(jù)的回調(diào),拖動圖中的滑動塊可以動態(tài)顯示不同年份的數(shù)據(jù);鼠標(biāo)懸停在氣泡上可以查看是哪個國家的數(shù)據(jù)。
如果年份數(shù)據(jù)足夠多,則可以使用while循環(huán)回調(diào)加載不同年份的數(shù)據(jù),其展示效果就是一幅類似于Gif效果的動圖。
關(guān)于作者:屈希峰,資深Python工程師,Bokeh領(lǐng)域的實踐者和布道者,對Bokeh有深入的研究。擅長Flask、MongoDB、Sklearn等技術(shù),實踐經(jīng)驗豐富。知乎多個專欄(Python中文社區(qū)、Python程序員、大數(shù)據(jù)分析挖掘)作者,專欄累計關(guān)注用戶十余萬人。
本文摘編自《Python數(shù)據(jù)可視化:基于Bokeh的可視化繪圖》,經(jīng)出版方授權(quán)發(fā)布。
延伸閱讀《Python數(shù)據(jù)可視化》
長按上方二維碼了解及購買
轉(zhuǎn)載請聯(lián)系微信:DoctorData
推薦語:從圖形繪制、數(shù)據(jù)動態(tài)展示、Web交互等維度全面講解Bokeh功能和使用,不含復(fù)雜數(shù)據(jù)處理和算法,深入淺出,適合零基礎(chǔ)入門,包含大量案例。
數(shù)據(jù)中臺VS業(yè)務(wù)中臺、數(shù)據(jù)中臺VS數(shù)據(jù)倉庫,到底有什么區(qū)別?
“讓數(shù)據(jù)用起來”:解讀數(shù)據(jù)中臺必備的4個核心能力
Python數(shù)據(jù)可視化:5段代碼搞定散點圖繪制與使用,值得收藏
企業(yè)數(shù)字化轉(zhuǎn)型與中臺建設(shè)全攻略:什么階段進(jìn)行?采用哪些方法?
據(jù)統(tǒng)計,99%的大咖都完成了這個神操作
????
點擊閱讀原文,了解更多
總結(jié)
以上是生活随笔為你收集整理的什么是气泡图?怎样用Python绘制?有什么用?终于有人讲明白了的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是数字孪生?有哪些关键技术?现在怎么
- 下一篇: 搜索引擎的竞价排名是怎样实现的?