什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了

导读:什么是气泡图?可以用来呈现哪些数据关系?在数据分析过程中可以解决哪些问题?怎样用Python绘制气泡图?本文逐一为你解答。

作者:屈希峰

来源:大数据DT(ID:bigdatadt)

什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了_第1张图片

01 概述

气泡图(Bubble)是一种多变量图表,是散点图的变体,也可以认为是散点图和百分比区域图的组合。其可用于展示三个变量之间的关系,和散点图一样,绘制时将一个变量放在横轴,另一个变量放在纵轴,而第三个变量则用气泡的大小来表示。

排列在工作表的列中的数据(第一列中列出x值,在相邻列中列出相应的y值和气泡大小的值)可以绘制在气泡图中。

气泡图与散点图相似,不同之处在于:气泡图允许在图表中额外加入一个表示大小的变量进行对比,而第四维度的数据则可以通过不同的颜色来表示(甚至在渐变中使用阴影来表示)。

另一种使用气泡元素的流行方法是使用气泡地图。在气泡地图中,x和y分别代表一个地理位置的经纬坐标。在不要求定位非常精确的情况下,气泡地图可以将数据的相对集中度完美地体现在地理背景中。

此外,表示时间维度的数据时,可以将时间维度作为直角坐标系中的一个维度,或者结合动画来表现数据随着时间的变化情况。

气泡图通常用于比较和展示不同类别圆点(这里我们称为气泡)之间的关系,通过气泡的位置以及面积大小。从整体上看,气泡图可用于分析数据之间的相关性。

但需要注意的是,气泡图的数据大小容量有限,气泡太多会使图表难以阅读。但是可以通过增加一些交互行为弥补:隐藏一些信息,当鼠标点击或者悬浮时显示,或者添加一个选项用于重组或者过滤分组类别。

最后,气泡的大小是映射面积而非半径或直径,如果是基于半径或者直径,圆的大小不仅会呈现指数级的变化,而且还会导致视觉上的误差。如图1所示。

什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了_第2张图片

▲图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)

运行结果如图2所示。

什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了_第3张图片

▲图2 代码示例①运行结果

从代码示例①中的第6行可以看出,气泡图的绘制仍使用散点图法,稍微不同的是在该方法中定义了散点数据的尺寸(size)大小。除此之外,可以再增加一个维度,用不同的气泡颜色进行数据分类。

代码示例②

  1# 复杂气泡图,完整代码  
  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  
 14
 15    # 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))  
 19
 20    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())  
 25
 26    # 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)  
 31
 32    return fertility, life_expectancy, population_size, regions, years, regions_list  
 33
 34# 数据预处理,感兴趣的读者可以在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# 画布参数  
 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# 坐标轴参数  
 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",  
 70
 71        axis_line_color='#AAAAAA',  
 72        major_tick_line_color='#AAAAAA',  
 73        major_label_text_color='#666666',  
 74
 75        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# 数据回调  
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'))  

运行结果如图3所示。

什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了_第4张图片

▲图3 代码示例②运行结果

代码示例②第92行采用models接口进行气泡绘制,并使用滑块控件进行不同年份数据的回调,拖动图中的滑动块可以动态显示不同年份的数据;鼠标悬停在气泡上可以查看是哪个国家的数据。

如果年份数据足够多,则可以使用while循环回调加载不同年份的数据,其展示效果就是一幅类似于Gif效果的动图。

关于作者:屈希峰,资深Python工程师,Bokeh领域的实践者和布道者,对Bokeh有深入的研究。擅长Flask、MongoDB、Sklearn等技术,实践经验丰富。知乎多个专栏(Python中文社区、Python程序员、大数据分析挖掘)作者,专栏累计关注用户十余万人。

本文摘编自《Python数据可视化:基于Bokeh的可视化绘图》,经出版方授权发布。

什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了_第5张图片

延伸阅读《Python数据可视化》

长按上方二维码了解及购买

转载请联系微信:DoctorData

推荐语:从图形绘制、数据动态展示、Web交互等维度全面讲解Bokeh功能和使用,不含复杂数据处理和算法,深入浅出,适合零基础入门,包含大量案例。

有话要说????

Q: 你用气泡图展示哪些数据?

欢迎留言与大家分享

猜你想看????

  • 50年后的地球什么样?大数据、AI、量子计算的书单给你答案

  • 数据中台VS业务中台、数据中台VS数据仓库,到底有什么区别?

  • 企业数字化转型与中台建设全攻略:什么阶段进行?有哪些方法?

  • 数据中台必备的4个核心能力,你让数据创造价值了吗?

更多精彩????

在公众号对话框输入以下关键词

查看更多优质内容!

PPT | 报告 | 读书 | 书单 | 干货 

大数据 | 揭秘 | Python | 可视化

AI | 人工智能 | 5G | 中台

机器学习 | 深度学习 | 神经网络

合伙人 1024 | 段子 | 数学

据统计,99%的大咖都完成了这个神操作

????

什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了_第6张图片

觉得不错,请把这篇文章分享给你的朋友

转载 / 投稿请联系:[email protected]

更多精彩,请在后台点击“历史文章”查看

什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了_第7张图片

什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了_第8张图片点击阅读原文,了解更多

你可能感兴趣的:(什么是气泡图?怎样用Python绘制?怎么用?终于有人讲明白了)