超全代码详解 Python 制作精美炫酷图表教程
The following article is from 读芯术 Author 读芯术
(给Python开发者加星标,提升Python技能)
转自:读芯术
生活阶梯(幸福指数)与人均GDP(金钱)正相关的正则图
本文将探讨三种用Python可视化数据的不同方法。以可视化《2019年世界幸福报告》的数据为例,本文用Gapminder和Wikipedia的信息丰富了《世界幸福报告》数据,以探索新的数据关系和可视化方法。
《世界幸福报告》试图回答世界范围内影响幸福的因素。
报告根据对“坎特里尔阶梯问题”的回答来确定幸福指数,被调查者需对自己的生活状况进行打分,10分为最佳状态,0分为最差。
本文将使用Life Ladder作为目标变量。Life Ladder就是指幸福指数。
文章结构
图片来源:Nik MacMillan/Unsplash
本文旨在提供代码指南和参考点,以便在查找特定类型的图表时进行参考。为了节省空间,有时会将多个图表合并到一张图上。但是请放心,你可以在这个Repo或相应的Jupyter Notebook中找到所有基本代码。
目录
· 我使用Python进行绘图的经历
· 分布的重要性
· 加载数据和包导入
· 迅速:使用Pandas进行基本绘图
· 美观:使用Seaborn进行高级绘图
· 精彩:用plotly创造精彩的互动情节
1. 我使用Python进行绘图的经历
图片来源:Krys Amon/Unsplash
大约两年前,我开始更认真地学习Python。从那时起,Python几乎每周都会给我一些惊喜,它不仅自身简单易用,而且其生态系统中还有很多令人惊叹的开源库。我对命令、模式和概念越熟悉,就越能充分利用其功能。
Matplotlib
与用Python绘图正好相反。最初,我用matplotlib创建的几乎每个图表看起来都很过时。更糟糕的是,为了创建这些讨厌的东西,我不得不在Stackoverflow上花费数小时。例如,研究改变x斜度的基本命令或者类似这些的蠢事。我一点也不想做多图表。以编程的方式创建这些图表是非常奇妙的,例如,一次生成50个不同变量的图表,结果令人印象深刻。然而,其中涉及大量的工作,需要记住一大堆无用的指令。
Seaborn
学习Seaborn能够节省很多精力。Seaborn可以抽象出大量的微调。毫无疑问,这使得图表在美观上得到巨大的改善。然而,它也是构建在matplotlib之上的。通常,对于非标准的调整,仍然有必要使用机器级的matplotlib代码。
Bokeh
一时间,我以为Bokeh会成为一个后援解决方案。我在做地理空间可视化的时候发现了Bokeh。然而,我很快就意识到,虽然Bokeh有所不同,但还是和matplotlib一样复杂。
Plotly
不久前我确实尝试过 plot.ly (后面就直接用plotly来表示)同样用于地理空间可视化。那个时候,plotly比前面提到的库还要麻烦。它必须通过笔记本账户登录,然后plotly可以在线呈现,接着下载最终图表。我很快就放弃了。但是,我最近看到了一个关于plotlyexpress和plotly4.0的Youtube视频,重点是,他们把那些在线的废话都删掉了。我尝试了一下,本篇文章就是尝试的成果。我想,知道得晚总比不知道的好。
Kepler.gl (地理空间数据优秀奖)
Kepler.gl不是一个Python库,而是一款强大的基于web的地理空间数据可视化工具。只需要CSV文件,就可以使用Python轻松地创建文件。试试吧!
当前工作流程
最后,我决定使用Pandas本地绘图进行快速检查,并使用Seaborn绘制要在报告和演示中使用的图表(视觉效果很重要)。
2. 分布的重要性
图片来源:Jonny Caspari/Unsplash
我在圣地亚哥从事研究期间,负责教授统计学(Stats119)。Stats119是统计学的入门课程,包括统计的基础知识,如数据聚合(可视化和定量)、概率的概念、回归、抽样、以及最重要的分布。这一次,我对数量和现象的理解几乎完全转变为基于分布的理解(大多数时候是高斯分布)。
直到今天,我仍然惊讶于这两个量的作用,标准差能帮助人理解现象。只要知道这两个量,就可以直接得出具体结果的概率,用户马上就知道大部分的结果的分布情况。它提供了一个参考框架,无需进行过于复杂的计算,就可以快速找出有统计意义的事件。
一般来说,面对新数据时,我的第一步是尝试可视化其分布,以便更好地理解数据。
3. 加载数据和包导入
图片来源:Kelli Tungay/Unsplash
先加载本文使用的数据。我已经对数据进行了预处理。并对它的意义进行了探究和推断。
# Loadthe 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)
· 生活阶梯:受访者根据坎特里尔阶梯(CantrilLadder),用0~10分(最满意的为10分)来衡量他们今天的生活
· 人均GDP:根据世界银行2018年11月14日发布的《世界发展指标》(WDI),将人均GDP调整为PPP(2011年不变价国际元)
· 社会支持:对下面问题的回答:“遇到困难时,是否可以随时获得亲戚或朋友的帮助?”
· 出生时预期健康寿命:出生时预期健康寿命是根据世界卫生组织(WHO)全球卫生观察站(GHO)数据库构建的,数据分别来自2005年、2010年、2015年和2016年。
· 自由选择权:回答下面这个问题:“你是否对自己生活的选择自由感到满意?”
· 慷慨:对“过去一个月是否给慈善机构捐过款?”与人均GDP相比
· 政治清廉:回答“腐败现象在政府中是否普遍?”“腐败在企业内部是否普遍?”
· 积极影响:包括前一天快乐、欢笑和享受的平均频率。
· 负面影响:包括前一天焦虑、悲伤和愤怒的平均频率。
· 对国家政府的信心:不言自明
· 民主质量:一个国家的民主程度
· 执行质量:一个国家的政策执行情况
· Gapminder预期寿命:Gapminder的预期寿命
· Gapminder人口: 国家人口
导入
import plotlyimport pandas as pdimport numpy as npimport seaborn as snsimport plotly.express as pximport matplotlib%matplotlib inlineassertmatplotlib.__version__ == "3.1.0","""Please install matplotlib version 3.1.0 by running:1) !pip uninstall matplotlib2) !pip install matplotlib==3.1.0"""
4. 迅速:使用Pandas进行基本绘图
np.exp(data[data[ Year ]==2018][ LogGDP per capita ]).plot(
kind= hist
)
data[
data[ Year ] == 2018
].set_index( Country name )[ Life Ladder ].nlargest(15).plot(
kind= bar ,
figsize=(12,8)
)
np.exp(data[
data[ Year ] == 2018
].groupby( Continent )[ Log GDP per capita ]
.mean()).sort_values().plot(
kind= barh ,
figsize=(12,8)
)
data[ Life Ladder ].plot(
kind= box ,
figsize=(12,8)
)
data[[ Healthy life expectancyat birth , Gapminder Life Expectancy ]].plot(
kind= scatter ,
x= Healthy life expectancy at birth ,
y= Gapminder Life Expectancy ,
figsize=(12,8)
)
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 togreenish sharex=False # required to get rid ofa bug)
data[data[ Year ] == 2018].groupby(
[ Continent ]
)[ Gapminder Population ].sum().plot(
kind= pie ,
figsize=(12,8),
cmap="Blues_r", # defaultsto orangish
)
data.groupby(
[ Year , Continent ]
)[ Gapminder Population ].sum().unstack().plot(
kind= area ,
figsize=(12,8),
cmap="Blues", # defaults toorangish
)
data[ data[ Country name ] == Germany ].set_index( Year )[ Life Ladder ].plot( kind= line , figsize=(12,8))
sns.reset_defaults()
sns.set(
rc={ figure.figsize :(7,5)},
style="white" # nicerlayout
)
sns.jointplot(
x= Log GDP per capita ,
y= Life Ladder ,
data=data,
kind= scatter # or kde or hex
)
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
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()
sns.set(
style="white",
palette="muted",
color_codes=True
)sns.pairplot(
data[data.Year == 2018][[
Life Ladder , Log GDP percapita ,
Social support , Healthy lifeexpectancy at birth ,
Freedom to make lifechoices , Generosity ,
Perceptions of corruption , Positive affect ,
Negative affect , Confidence innational government ,
Mean Log GDP per capita
]].dropna(),
hue= Mean Log GDP per capita
)
g = sns.FacetGrid(
data.groupby([ Mean Log GDP percapita , 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 ))
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)))
defvertical_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}(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} (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")
heatmap_facetgrid.py
defdraw_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()
defdraw_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,
)
6. 精彩:用plotly创造精彩的互动情节
fig = x.<PLOTTYPE>(PARAMS)然后是 fig.show() ,像这样:
fig = px.scatter(
data_frame=data[data[ Year ] ==2018],
x="Log GDP per capita",
y="Life Ladder",
size="GapminderPopulation",
color="Continent",
hover_name="Country name",
size_max=60
)
fig.show()
fig = px.scatter(
data=data,
x="Log GDP per capita",
y="Life Ladder",
animation_frame="Year",
animation_group="Countryname",
size="GapminderPopulation",
color="Continent",
hover_name="Country name",
facet_col="Continent",
size_max=45,
category_orders={ Year :list(range(2007,2019))}
)fig.show()
def q_bin_in_3(col):
return pd.qcut(
col,
q=3,
labels=[ Low , Medium , High ]
)_ = data.copy()
_[ Social support ] = _.groupby( Year )[ Socialsupport ].transform(q_bin_in_3)_[ Life Expectancy ] =_.groupby( Year )[ Healthy life expectancy atbirth ].transform(q_bin_in_3)_[ Generosity ] =_.groupby( Year )[ Generosity ].transform(q_bin_in_3)_[ Perceptions ofcorruption ] = _.groupby( Year )[ Perceptions ofcorruption ].transform(q_bin_in_3)_ = _.groupby([ Social support , LifeExpectancy , Generosity , Perceptions of corruption ])[ LifeLadder ].mean().reset_index()fig = px.parallel_categories(_, color="LifeLadder", color_continuous_scale=px.colors.sequential.Inferno)
fig.show()
fig = px.bar(
data,
x="Continent",
y="Gapminder Population",
color="Mean Log GDP percapita",
barmode="stack",
facet_col="Year",
category_orders={"Year":range(2007,2019)},
hover_name= Country name ,
hover_data=[
"Mean Log GDP percapita",
"Gapminder Population",
"Life Ladder"
]
)
fig.show()
fig = px.choropleth( data, locations="ISO3", color="Life Ladder", hover_name="Country name", animation_frame="Year")fig.show()
结束语
推荐阅读
(点击标题可跳转阅读)
觉得本文对你有帮助?请分享给更多人
关注「Python开发者」加星标,提升Python技能
好文章,我在看❤️