前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何使用Python创建美观而有见地的图表

如何使用Python创建美观而有见地的图表

作者头像
代码医生工作室
发布2019-11-26 23:06:07
3K0
发布2019-11-26 23:06:07
举报
文章被收录于专栏:相约机器人

作者 | Fabian Bosler

来源 | Medium

在今天的文章中,将研究使用Python绘制数据的三种不同方式。将通过利用《 2019年世界幸福报告》中的数据来做到这一点。用Gapminder和Wikipedia的信息丰富了《世界幸福报告》的数据,以便探索新的关系和可视化。

https://worldhappiness.report/ed/2019/

《世界幸福报告》试图回答哪些因素影响全世界的幸福。

报告中的幸福定义为对“ Cantril阶梯问题”的回答,要求被调查者以0到10的等级评估他们今天的生活,最糟糕的寿命为0,最可能的寿命为10。

在整篇文章中,将Life Ladder用作目标变量。每当谈论人生阶梯时,请思考幸福。

文章的结构

为了节省空间,有时会将多个图表合并为一张图像。但是请放心可以在此Repo或相应的Jupyter Notebook中找到所有基础代码。

https://github.com/FBosler/AdvancedPlotting

https://nbviewer.jupyter.org/github/FBosler/AdvancedPlotting/blob/master/The%20quick%2C%20the%20pretty%2C%20and%20the%20awesome.ipynb

目录

  • Python绘图历史
  • 分布的重要性
  • 加载数据和包导入
  • 快速:使用Pandas进行基本绘图
  • 漂亮:与Seaborn的高级绘图
  • 很棒:使用plotly创建很棒的交互式图

Python绘图历史

大约两年前,开始更认真地学习Python。惊叹于Python本身或生态系统中众多令人惊叹的开源库之一的简单性和易用性。熟悉的命令,模式和概念越多,那么所有事情就越有意义。

Matplotlib

使用Python进行绘图的情况恰恰相反。最初用Matplotlib创建的几乎每个图表都看起来像是八十年代逃脱的罪行。更糟糕的是要创建这些可憎的东西,通常不得不在Stackoverflow上花费数小时。例如研究nitty-gritty命令以更改x-ticks的倾斜度或类似的愚蠢行为。甚至不要开始使用多张图表。结果看起来令人印象深刻,并且以编程方式创建这些图表是一种奇妙的感觉。例如,一次生成50个针对不同变量的图表。但是,这只是很多工作,需要记住很多其他本来没用的命令。

Seaborn

https://seaborn.pydata.org/

了解Seaborn是一种解脱。Seaborn提取了很多微调。毫无疑问,最终图表的美学意义是一个巨大的飞跃。但是,它也是基于Matplotlib构建的。通常,对于非标准调整,仍然有必要深入了解机器级的matplotlib代码。

Bokeh

https://docs.bokeh.org/en/latest/

简要了解一下时间,以为Bokeh将成为首选解决方案。当从事地理空间可视化工作时遇到了Bokeh。但是,很快意识到,虽然Bokeh与众不同,但它与matplotlib一样复杂。

Plotly

https://plot.ly/python/

确实在一段时间前尝试了plot.ly(从现在开始被称为plotly)。再一次,致力于地理空间数据的可视化。那时,它似乎比前面提到的库荒谬。需要一个帐户,必须通过笔记本电脑登录,然后才能使所有内容在线呈现。然后,将下载结果图表。迅速放弃了。但是最近,看了一个有关YouTube的视频,该视频关于plotly express和plotly 4.0,最重要的是,摆脱了所有这些在线废话。玩了一下,这篇文章就是它的结果。

Kepler.gl(地理空间数据荣誉奖)

https://kepler.gl/

Kepler.gl虽然绝对不是Python库,但它是一种用于地理空间数据的基于Web的强大可视化工具。只需要CSV文件,即可使用Python轻松创建。试试看!

目前的工作流程

最终决定使用Pandas原生绘图进行快速检查,并使用Seaborn生成要在报表和演示文稿中使用的图表(在视觉上很重要)。

分布的重要性

在圣地亚哥学习期间,教过统计学(Stats 119)。统计119是统计的入门课程。该课程包括统计基础知识,例如数据汇总(视觉和定量),赔率和概率的概念,回归,抽样以及最重要的分布。这次是对数量和现象的理解几乎全部转变为基于分布表示的时间(大部分时间是高斯)。

直到今天,惊讶地发现这两个量的平均值是多少,标准差可以帮助您掌握一个现象。仅了解这两个数字,就可以简单地得出特定结果的可能性。人们立即知道大部分结果将在哪里。它提供了一个参考框架,可以快速将轶事与有统计意义的事件区分开来,而无需进行过于复杂的计算。

总体而言,面对新数据时,第一步是尝试形象化其分布,以更好地理解数据。

加载数据和导入库

请加载本文中将要使用的数据。对数据进行了一些预处理。在有意义的地方进行推断。

代码语言:javascript
复制
# Load the data
data = pd.read_csv('https://raw.githubusercontent.com/FBosler/AdvancedPlotting/master/combined_set.csv')
# this assigns labels per year
data['Mean Log GDP per capita']  = data.groupby('Year')['Log GDP per capita'].transform(
    pd.qcut,
    q=5,
    labels=(['Lowest','Low','Medium','High','Highest'])
)

数据集包含以下各列的值:

  • 年:计量年(从2007年到2018年)
  • 生命阶梯:受访者根据Cantril阶梯以0到10的量度标准(今天最好的10分)衡量他们的生命价值
  • 对数人均 GDP :根据购买力平价(PPP)调整的人均 GDP,根据世界银行于2018年11月14日发布的世界发展指标(WDI)进行了调整,以2011年国际美元不变
  • 社会支持:对问题的回答:“如果遇到麻烦,您是否有亲戚朋友可以在需要时帮助您?”
  • 出生时的健康预期寿命:出生时的预期寿命是根据世界卫生组织(WHO)全球卫生观察站数据存储库中的数据构建的,其中提供了2005、2010、2015和2016年的数据。
  • 自由选择生活:对问题的回答:“您对选择自己的生活的自由感到满意还是不满意?”
  • 慷慨:与“人均GDP”相比,对“您在过去一个月向慈善机构捐款了吗?”的回应
  • 对腐败的看法:回答“腐败是否在整个政府范围内广泛存在?”和“腐败是否在企业内部广泛分布?”
  • 积极影响:包括前一天的幸福,笑声和享受的平均频率。
  • 负面影响:包括前一天担忧,悲伤和愤怒的平均频率。
  • 对国家政府的信心:不言自明
  • 民主素质:一个国家的民主程度
  • 交付质量:一个国家兑现其政策的效果如何
  • Gapminder预期寿命:Gapminder的预期寿命
  • Gapminder人口:一个国家的人口

导入库

代码语言:javascript
复制
import plotly
import pandas as pd
import numpy as np
import seaborn as sns
import plotly.express as px
import matplotlib
%matplotlib inline
assert matplotlib.__version__ == "3.1.0","""
Please install matplotlib version 3.1.0 by running:
1) !pip uninstall matplotlib
2) !pip install matplotlib==3.1.0
"""

快速:使用Pandas进行基本绘图

Pandas具有内置的绘图功能,可以在Series或DataFrame上调用它。喜欢这些绘图功能,因为它们简洁,使用合理的默认值,并且可以快速了解发生的情况。

要创建绘图,请.plot(kind=<TYPE OF PLOT>)像这样调用数据:

代码语言:javascript
复制
np.exp(data[data['Year']==2018]['Log GDP per capita']).plot(
    kind='hist'
)

运行上面的命令将产生以下图表。

2018年:人均GDP的国家数量直方图。毫不奇怪,大多数国家都是贫穷的!

使用Pandas进行绘图时,有五个主要参数:

  • kind:Pandas必须知道要创建哪种图,可以使用以下选项hist, bar, barh, scatter, area, kde, line, box, hexbin, pie。
  • figsize:允许覆盖6英寸宽和4英寸高的默认输出尺寸。figsize期望一个元组(例如,figsize=(12,8)经常使用的)
  • title:向图表添加标题。在大多数情况下,用它来澄清图表中显示的内容,以便当回到图表上时,可以快速确定发生了什么。title需要一个字符串。
  • bins:允许覆盖直方图的bin宽度。bins需要一个列表或类似列表的值序列(例如bins=np.arange(2,8,0.25))
  • xlim/ylim:允许覆盖轴的最大值和最小值的默认值。两者,xlim并ylim期望一个元组(例如xlim=(0,5))

快速浏览各种可用的绘图类型。

垂直条形图

代码语言:javascript
复制
data[
    data['Year'] == 2018
].set_index('Country name')['Life Ladder'].nlargest(15).plot(
    kind='bar',
    figsize=(12,8)
)

2018年:15个最幸福的国家/地区名单由芬兰领导

水平条形图

代码语言:javascript
复制
np.exp(data[
    data['Year'] == 2018
].groupby('Continent')['Log GDP per capita']\
       .mean()).sort_values().plot(
    kind='barh',
    figsize=(12,8)
)

2011年按大陆平均人均国内生产总值(美元)明显以澳大利亚和新西兰为首

箱形图

代码语言:javascript
复制
data['Life Ladder'].plot(
    kind='box',
    figsize=(12,8)
)

生命阶梯分布的箱形图显示,中位数约为5.5,范围从低于3到最高8。

散点图

代码语言:javascript
复制
data[['Healthy life expectancy at birth','Gapminder Life Expectancy']].plot(
    kind='scatter',
    x='Healthy life expectancy at birth',
    y='Gapminder Life Expectancy',
    figsize=(12,8)
)

《世界幸福报告》预期寿命与Gapminder预期寿命的散点图显示了两者之间的高度相关性(预期)

六边形图

代码语言:javascript
复制
data[data['Year'] == 2018].plot(
    kind='hexbin',
    x='Healthy life expectancy at birth',
    y='Generosity',
    C='Life Ladder',
    gridsize=20,
    figsize=(12,8),
    cmap="Blues", # defaults to greenish
    sharex=False # required to get rid of a bug
)

2018年:赫克斯宾(Hexbin)图,绘制了预期寿命与慷慨的图表。垃圾箱的颜色表示各个垃圾箱中寿命梯的平均值。

饼形图

代码语言:javascript
复制
data [data ['Year'] == 2018] .groupby(
    ['Continent']
)['Gapminder人口']     .sum ()。plot(
    kind ='pie',
figsize =(12,8),
    cmap = “ Blues_r”,#默认为orangish
)

2018年:饼图显示各大洲的总人口

堆积面积图

代码语言:javascript
复制
data[data['Year'] == 2018].groupby(
    ['Continent']
)['Gapminder Population'].sum().plot(
    kind='pie',
    figsize=(12,8),
    cmap="Blues_r", # defaults to orangish
)

全球人口数量正在上升

折线图

代码语言:javascript
复制
data [
    data ['Country name'] =='Germany'
] .set_index('Year')['Life Ladder']。plot(
    kind ='line',
    figsize =(12,8)
)

折线图描绘了德国幸福的发展

关于Pandas绘图的结论

用Pandas绘图很方便。它易于访问,而且速度很快。还有其他工具可以使图表更具美学吸引力。前进到seaborn。

漂亮:与Seaborn的高级绘图

Seaborn利用绘图默认值。为了确保结果匹配,请运行以下命令。

代码语言:javascript
复制
sns.reset_defaults()
sns.set(
    rc={'figure.figsize':(7,5)},
    style="white" # nicer layout
)

绘制单变量分布

直方图和核密度分布都是可视化特定变量的关键特征的有效方法。看看如何在一个图表中为单个变量或多个变量生成分布。

左图:2018年亚洲国家“救生梯”的直方图和核密度估计;右图:人均5桶GDP的“生命阶梯”的内核密度估计-钱可以买到幸福

绘制双变量分布

每当想直观地探索两个或多个变量之间的关系时,通常都归结为某种形式的散点图和分布评估。概念上相似的图有三种变体。在每个这些图中,中心图(散点图,双变量KDE和hexbin)有助于理解两个变量之间的联合频率分布。此外,在中心图的右边界和上边界,描绘了各个变量的边际单变量分布(作为KDE或直方图)。

代码语言:javascript
复制
sns.jointplot(
    x='Log GDP per capita',
    y='Life Ladder',
    data=data,
    kind='scatter' # or 'kde' or 'hex'
)

中心图上具有散点图,双变量kde和hexbin的Seaborn关节图,中心图左侧和顶部均具有边际分布。

散点图

散点图是一种可视化两个变量的联合密度分布的方法。可以通过添加色相来添加第三个变量,并通过添加size参数来添加第四个变量。

代码语言:javascript
复制
sns.scatterplot(
    x='Log GDP per capita',
    y='Life Ladder',
    data=data[data['Year'] == 2018],    
    hue='Continent',
    size='Gapminder Population'
)
# both, hue and size are optional
sns.despine() # prettier layout

记录人均国内生产总值与生命梯的对比,颜色基于大陆和人口规模

小提琴图

小提琴图是箱形图和籽粒密度估计值的组合。它起着箱形图的作用。它显示了跨类别变量的定量数据分布,以便可以比较那些分布。

代码语言:javascript
复制
sns.set(
    rc={'figure.figsize':(18,6)},
    style="white"
)
sns.violinplot(
    x='Continent',
    y='Life Ladder',
    hue='Mean Log GDP per capita',
    data=data
)
sns.despine()

在小提琴上绘制大陆与生命梯的图,使用人均GDP GDP来对数据进行分组。看来人均GDP越高,幸福感就越强

配对图

Seaborn对图在一个大网格中绘制了两个变量散点图的所有组合。通常感觉这有点信息过载,但是它可以帮助发现模式。

代码语言:javascript
复制
sns.set(
    style="white",
    palette="muted",
    color_codes=True
)
sns.pairplot(
    data[data.Year == 2018][[
        'Life Ladder','Log GDP per capita',
        'Social support','Healthy life expectancy at birth',
        'Freedom to make life choices','Generosity',
        'Perceptions of corruption', 'Positive affect',
        'Negative affect','Confidence in national government',
        'Mean Log GDP per capita'
    ]].dropna(),
    hue='Mean Log GDP per capita'
)

Seaborn散点图网格,其中所有选定变量相对于网格下部和上部的每个其他变量均分散分布,对角线包含kde图。

FacetGrid

Seaborn的FacetGrid是使用Seaborn的最令人信服的论据之一,因为它使创建多图变得轻而易举。通过对图,已经看到了FacetGrid的示例。FacetGrid允许创建按变量分段的多个图表。例如,行可以是一个变量(人均GDP类别),列可以是另一个变量(大陆)。

它确实需要比个人更需要的自定义(即,使用matplotlib),但这仍然很引人注目。

FacetGrid —线图

代码语言:javascript
复制
g = sns.FacetGrid(
    data.groupby(['Mean Log GDP per capita','Year','Continent'])['Life Ladder'].mean().reset_index(),
    row='Mean Log GDP per capita',
    col='Continent',
    margin_titles=True
)
g = (g.map(plt.plot, 'Year','Life Ladder'))

Y轴为生命梯,X轴为年。网格的列是大陆,网格的行是人均平均GDP的不同水平。对于北美人均原木平均GDP 较低的国家和欧洲人均原木GDP 中等或较高的国家,总体情况似乎有所改善

FacetGrid —直方图

代码语言:javascript
复制
g = sns.FacetGrid(data, col="Continent", col_wrap=3,height=4)
g = (g.map(plt.hist, "Life Ladder",bins=np.arange(2,9,0.5)))

FacetGrid,按洲显示LifeLadder的直方图

FacetGrid — 带注释的KDE图

也可以向网格中的每个图表添加构面特定的符号。在下面的示例中,将平均值和标准偏差相加,并在该平均值处绘制一条垂直线(下面的代码)。

基于大陆的生命梯子内核密度估计,并带有平均值和标准差

代码语言:javascript
复制
def vertical_mean_line(x, **kwargs):
    plt.axvline(x.mean(), linestyle ="--",
                color = kwargs.get("color", "r"))
    txkw = dict(size=15, color = kwargs.get("color", "r"))

    label_x_pos_adjustment = 0.08 # this needs customization based on your data
    label_y_pos_adjustment = 5 # this needs customization based on your data
    if x.mean() < 6: # this needs customization based on your data
        tx = "mean: {:.2f}\n(std: {:.2f})".format(x.mean(),x.std())
        plt.text(x.mean() + label_x_pos_adjustment, label_y_pos_adjustment, tx, **txkw)
    else:
        tx = "mean: {:.2f}\n  (std: {:.2f})".format(x.mean(),x.std())
        plt.text(x.mean() -1.4, label_y_pos_adjustment, tx, **txkw)

_ = data.groupby(['Continent','Year'])['Life Ladder'].mean().reset_index()

g = sns.FacetGrid(_, col="Continent", height=4, aspect=0.9, col_wrap=3, margin_titles=True)
g.map(sns.kdeplot, "Life Ladder", shade=True, color='royalblue')
g.map(vertical_mean_line, "Life Ladder")

FacetGrid —热图

最喜欢的绘图类型之一是热图FacetGrid,即网格每个面上的热图。这种类型的绘图对于在一个绘图中可视化四个维度和一个度量很有用。该代码有点麻烦,但可以根据需要快速进行调整。值得注意的是,这种图表需要相对大量的数据或适当的细分,因为它不能很好地处理缺失值。

在外排显示的是一年范围,在外排显示的是人均GDP,在内排显示的是感知的腐败程度,内排则为各洲。我们看到,幸福感朝着右上角增加(即人均GDP高和感知腐败低)。时间的影响并不确定,某些大洲(欧洲和北美)似乎比其他大洲(非洲)更快乐。

代码语言:javascript
复制
def draw_heatmap(data,inner_row, inner_col, outer_row, outer_col, values, vmin,vmax):
    sns.set(font_scale=1)
    fg = sns.FacetGrid(
        data,
        row=outer_row,
        col=outer_col,
        margin_titles=True
    )

    position = left, bottom, width, height = 1.4, .2, .1, .6
    cbar_ax = fg.fig.add_axes(position)

    fg.map_dataframe(
        draw_heatmap_facet,
        x_col=inner_col,
        y_col=inner_row,
        values=values,
        cbar_ax=cbar_ax,
        vmin=vmin,
        vmax=vmax
    )

    fg.fig.subplots_adjust(right=1.3)  
    plt.show()

def draw_heatmap_facet(*args, **kwargs):
    data = kwargs.pop('data')
    x_col = kwargs.pop('x_col')
    y_col = kwargs.pop('y_col')
    values = kwargs.pop('values')
    d = data.pivot(index=y_col, columns=x_col, values=values)
    annot = round(d,4).values
    cmap = sns.color_palette("Blues",30) + sns.color_palette("Blues",30)[0::2]
    #cmap = sns.color_palette("Blues",30)
    sns.heatmap(
        d,
        **kwargs,
        annot=annot,
        center=0,
        cmap=cmap,
        linewidth=.5
    )

# Data preparation
_ = data.copy()
_['Year'] = pd.cut(_['Year'],bins=[2006,2008,2012,2018])

_['GDP per Capita'] = _.groupby(['Continent','Year'])['Log GDP per capita'].transform(
    pd.qcut,
    q=3,
    labels=(['Low','Medium','High'])
).fillna('Low')

_['Corruption'] = _.groupby(['Continent','GDP per Capita'])['Perceptions of corruption'].transform(
    pd.qcut,
    q=3,
    labels=(['Low','Medium','High'])
)

_ = _[_['Continent'] != 'Oceania'].groupby(['Year','Continent','GDP per Capita','Corruption'])['Life Ladder'].mean().reset_index()
_['Life Ladder'] = _['Life Ladder'].fillna(-10)

draw_heatmap(
    data=_,
    outer_row='Corruption',
    outer_col='GDP per Capita',
    inner_row='Year',
    inner_col='Continent',
    values='Life Ladder',
    vmin=3,
    vmax=8,
)

很棒:使用plotly创建很棒的交互式图

没有更多的Matplotlib!Plotly具有三个重要功能:

  • 悬停:将鼠标悬停在图表上时,将弹出注释
  • 互动性:无需任何其他设置即可使图表互动(即穿越时空)
  • 漂亮的地理空间图: Plotly具有一些内置的基本地图绘制功能,可以使用mapbox集成来生成惊人的图表。

散点图

通过运行调用绘图fig = x.<PLOT TYPE>(PARAMS),然后fig.show()像这样:

代码语言:javascript
复制
fig = px.scatter(
    data_frame=data[data['Year'] == 2018],
    x="Log GDP per capita",
    y="Life Ladder",
    size="Gapminder Population",
    color="Continent",
    hover_name="Country name",
    size_max=60
)
fig.show()

散布散点图,绘制人均国内生产总值对生命梯的图,其中颜色表示大陆和标记人口的大小

散点图-漫步时光

代码语言:javascript
复制
fig = px.scatter(
    data_frame=data,
    x="Log GDP per capita",
    y="Life Ladder",
    animation_frame="Year",
    animation_group="Country name",
    size="Gapminder Population",
    color="Continent",
    hover_name="Country name",
    facet_col="Continent",
    size_max=45,
    category_orders={'Year':list(range(2007,2019))}     
)
fig.show()

可视化多年来绘制的数据如何变化

平行类别-一种可视化类别的有趣方式

代码语言:javascript
复制
def q_bin_in_3(col):
    return pd.qcut(
        col,
        q=3,
        labels=['Low','Medium','High']
    )
_ = data.copy()
_['Social support'] = _.groupby('Year')['Social support'].transform(q_bin_in_3)
_['Life Expectancy'] = _.groupby('Year')['Healthy life expectancy at birth'].transform(q_bin_in_3)
_['Generosity'] = _.groupby('Year')['Generosity'].transform(q_bin_in_3)
_['Perceptions of corruption'] = _.groupby('Year')['Perceptions of corruption'].transform(q_bin_in_3)
_ = _.groupby(['Social support','Life Expectancy','Generosity','Perceptions of corruption'])['Life Ladder'].mean().reset_index()
fig = px.parallel_categories(_, color="Life Ladder", color_continuous_scale=px.colors.sequential.Inferno)
fig.show()

似乎并非所有对生活期望很高的国家都感到高兴!

条形图—交互式过滤器的示例

代码语言:javascript
复制
fig = px.bar(
    data,
    x="Continent",
    y="Gapminder Population",
    color="Mean Log GDP per capita",
    barmode="stack",
    facet_col="Year",
    category_orders={"Year": range(2007,2019)},
    hover_name='Country name',
    hover_data=[
        "Mean Log GDP per capita",
        "Gapminder Population",
        "Life Ladder"
    ]
)
fig.show()

过滤条形图很容易。毫不奇怪,韩国是亚洲富裕国家之一。

整体情节-幸福如何随着时间而变化

代码语言:javascript
复制
fig = px.choropleth(
    data,
    locations="ISO3",
    color="Life Ladder",
    hover_name="Country name",
    animation_frame="Year")
fig.show()

多年以来幸福如何演变的地图可视化。叙利亚和阿富汗处于生命阶梯范围的尽头(毫不奇怪)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 相约机器人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档