Python-matplotlib 另类散点图绘制

2021-02-22 15:17:28 浏览数 (1)

01. 引言

本期推文的主要内容是散点图的绘制教程,所使用的数据关于全球教育水平划分的师生比例,涉及到的包主要为matplotlib和seaborn,当然用于数据处理分析的pandas和 numpy也必不可少。

02. 数据处理

2.1 原始数据

本文涉及的数据主要包括两种,一种为全球各大洲的网格数据,用于绘制另类散点图例,一种为全球各州的教育水平的师生比例,用于散点图的绘图。各大洲的网格数据如下(部分):如红框所示,为所需要的数据,用于绘图。

全球各大洲师生比例数据如下(部分):所需文章为student_ratio_count 。

接下来将两个数据进行匹配合并,这里需指出下:两个数据都有关于国家编码的列(country_code和alpha.3),利用pandas的merger方法就可实现两个数据的合并。

2.2 构造数据

和一般的绘图不同,稍微复杂的突变就需要自己根据需求进行特定数据的构造。这里所构造的数据详细如下:

(1)教育平均值

通过pandas 的mean()方法就可实现全球教育水平的平均值,如下:

代码语言:javascript复制
world_avg = 23.518193030303

(2) 各大地区颜色设置

这里还是采用和之前推文Hans Rosling Charts Matplotlib 绘制等一样的字典颜色赋值,具体如下:

代码语言:javascript复制
order=["Africa", "Oceania","Asia","South America","North America","Europe"]
palette=["#0076BB", "#152769","#1AB6AF", "#E9E4A6","#FF3100","#E9A17C"]
region_color = dict(zip(order,palette))
region_color

结果如下:

(3)绘制大散点图

代码语言:javascript复制
region_y = {
    'Africa':1,
    'Oceania':2,
    'Asia':3,
    'South America':4,
    'North America':5,
    'Europe':6
}
sactter_line = student[['student_ratio_cont','region']].drop_duplicates()
sactter_line["region_y"] = [region_y[i]-1 for i in sactter_line['region']]
sactter_line

结果如下:

(4)用于构建另类图例的数据

代码语言:javascript复制
legend_data = student[['x','y','region']]
legend_data.head()

结果如下(部分):

03. 可视化绘制

本文的可视化绘制过程涉及seaborn的stripplot()方法,所需的库、总体设置及用于绘制“抖动”的散点图(类似ggplot2的position_jitter()),其目的就是为了防止散点重叠。如下:

代码语言:javascript复制
import seaborn as sns
import matplotlib.lines as mlines
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from matplotlib.patches import Rectangle

plt.rcParams['font.family'] = ['Roboto Mono']
fig, ax = plt.subplots(figsize=(10,6),dpi = 200,facecolor='#323332',edgecolor='#323332')
ax.set_facecolor("#323332")
代码语言:javascript复制
sns.stripplot(x="student_ratio", y="region",order=order,palette=palette, data=student,
              size = 8,alpha=.4,edgecolor = "white",linewidth=.8,zorder=0,ax=ax)

添加点线的连接,具体如下(部分代码也给出解释):不明白的地方可以参考我之前的推文Matplotlib 气球图 制作,或者后台发消息咨询。

代码语言:javascript复制
# #添加 点线 图层
def newline(p1, p2):
    ax = plt.gca()
    l = mlines.Line2D([p1[0],p2[0]], [p1[1],p2[1]],color='#FFFFFF',
                      lw=1.8,zorder = 0)
    ax.add_line(l)
    return l
for p1, p2 in zip(sactter_line['student_ratio_cont'], sactter_line['region_y']):
    newline([world_avg,p2], [p1,p2])
#添加散点
for i,j,c in zip(sactter_line['student_ratio_cont'], sactter_line['region_y'],sactter_line['region']):
    ax.scatter(i,j,c=region_color[c],s = 170,ec = 'white',lw=.8,zorder=1)

ax.tick_params(labelsize = 15,direction = 'out',colors = '#FFFFFF')
ax.set_xticks(np.arange(-5,100,10))
#设置轴脊颜色及宽度
for spine in ['top','bottom','left','right']:
    ax.spines[spine].set_color("#FFFFFF")
    ax.spines[spine].set_linewidth(1.5)
#隐藏xy轴的label
ax.set_xlabel('')
ax.set_ylabel('')
ax.invert_yaxis()

添加另类图例(地图图例)

代码语言:javascript复制
#添加另类图例
axins = inset_axes(ax, width=2.3, height=1.5)
for x,y,c in zip(legend_data.x,legend_data.y,legend_data.region):
    rect = Rectangle((x 1,y 1),width=.5,height=.5, color=region_color[c])
    axins.add_patch(rect)
axins.set_xticks([])
axins.set_xlim(left=-5,right=35)
axins.set_yticks([])
axins.set_ylim(top=30,bottom=-5)
axins.invert_yaxis()
axins.axis('off')

这一步用到了matplotlib的axes插入方法,绘制大小图或者中国地图十段线部分均可用此方法进行绘制。这里也用到了之前构造的lengend_data、region_color,然后使用 Rectangle()绘制矩形,再使用 axins.add_patch(rect)方法进行多矩形绘制。ggplot2的geom_tile()也可实现矩形图表的绘制。

绘制文本及指示箭头,代码如下(部分):

代码语言:javascript复制
ax.annotate(s="Worldwide average:n{} students per teacher".format(round(world_avg,1)),
            xy=(world_avg,4.5),xytext=(40,5),ha="center",va="center",size=12,c='#FFFFFF',
            family='Poppins', 
            arrowprops=dict(arrowstyle="->",
                            connectionstyle="arc3,rad=-0.3",
                            fc="gray",ec='#FFFFFF')
           )

完整代码如下:

最终可视化效果如下:

如果没用采用地图图例的绘制,而是一般的散点图图例,效果如下:

图例绘制方法如下(部分):

代码语言:javascript复制
#添加图例
region_legend = ax.legend(fontsize=10,markerscale =1.2,title = 'Region',frameon=False,
                         title_fontsize = 15)
#region_legend.get_title().set_fontsize(fontsize = 13)#面向对象
region_legend.get_title().set_color("#FFFFFF")
region_legend.get_frame().set_facecolor('#323332')
#修改图例属性颜色:图例文字颜色设置
for text in region_legend.get_texts():
    text.set_color('#FFFFFF')

04. 总结

Matplotlib对绘制大多数图表还是比较友好的,也是比较容易定制化自己的绘图需求(需熟悉太多的绘图函数

),但涉及统计图表的绘制,可以结合seaborn进行绘制,使绘图事半功倍哦!!绘图的颜色搭配对绘图结果至关重要,自己现阶段也是在摸索和模仿,有好的颜色搭配学习网站或者资源,可以进群交流。本文能力有限,有错误的地方或者不理解的地方,可以后台咨询或者进行讨论,期待你的加入。

0 人点赞