绘图提高篇 | Python/R 双Y轴绘制

最近有很多小伙伴私信我关于双Y轴图的绘制方法? 这里我就直接给出Python-matplotlib绘制方法和R-ggplot2的绘制方法,主要的知识点如下:

  • Matplotlib-Axes.twinx()方法添加副轴

  • ggplot2-sec.axis()绘制双轴

  • 所有内容都已免费新增到我们的系统可视化课程中,有需要可以咨询呀!

Matplotlib-Axes.twinx()方法添加副轴

这里我们直接就给出数据预览和可视化设计的代码,图中部分代码我们再做详细解释,数据预览如下:

自定义的颜色字典year_color构造代码如下:

color = ("#51C1C8", "#E96279", "#44A2D6", "#536D84",
         "#51C1C8", "#E96279", "#44A2D6", "#536D84")
year = artist_01.index.to_list()
year_color = dict(zip(year,color))
year_color

可视化代码如下:

plt.style.use('fivethirtyeight')
fig,ax = plt.subplots(figsize=(8,4),dpi=200,facecolor='white',edgecolor='white')
ax.set_facecolor('white')

x = np.arange(0,len(artist_01),1)
y = artist_01['data01'].values

#绘制连接点的线
line = ax.plot(x,y,color='#333333',lw=1.,zorder=2)
#绘制不同散点图
scatter_out = ax.scatter(x,y,s=500,zorder=1,color='white',ec='grey',alpha=.7,lw=.5)
for i in artist_01.index.to_list():
    scatter = ax.scatter(x[i],y[i],s=180,zorder=3,ec='k',lw=.4,color=year_color[i])
scatter_in = ax.scatter(x,y,s=30,zorder=3,color="#333333")

#定制化绘制(设置图表风格)
ax.grid(color='gray',lw=.5,alpha=.5) #设置网格
ax.tick_params(left=False,bottom=False,labelbottom=False,labelsize=10,colors='gray')#设置刻度
ax.set_ylim(bottom=-3,top=43)#设置轴范围
ax.set_yticks(np.arange(0, 45, step=5)) #设置刻度标签
ax.set_xticks(np.arange(-.5, 8, step=.5))
#添加横线(修饰)
ax.axhline(y=0,color='#45627C',lw=3)
#添加数字标签
label_text = {"size":13,"color":"k",'weight':'semibold'}
for a,b in zip(x,y):
    ax.text(a, b+2.5, '%.0f' % b, ha='center', va= 'bottom',fontdict=label_text,color=year_color[a])
#设置轴脊(spine)
for spine in ['top','bottom','left','right']:
    ax.spines[spine].set_color("#FFFFFF") #设置颜色/set_visible()设置显示与否
for i in artist_01.index.to_list()[:3]:
    axins.scatter(x[i],y[i],s=80,color=year_color[i],zorder=2)
    
#添加标题处小图
#添加小散点图:重点掌握   
axins = inset_axes(ax, width=.4, height=.4,loc='upper left',
                   bbox_to_anchor=(0.01, 0.22, 1, 1),
                   bbox_transform=ax.transAxes,
                   borderpad=0)
axins.set_ylim(bottom=8,top=35)
axins.set_xlim(left=-.5,right=2.5)
axins.plot(x[:3],y[:3],color='#333333',lw=1.,zorder=1)
for i in artist_01.index.to_list()[:3]:
    axins.scatter(x[i],y[i],s=80,color=year_color[i],zorder=2)
axins.axis('off')
#绘制小横线:原理同上
line = inset_axes(ax,width=5.3, height=.4,loc='upper left',
                  bbox_to_anchor=(-0.015, 0.15, 1, 1),
                  bbox_transform=ax.transAxes,
                  borderpad=0)
line.plot([.1,.7],[.1,.1],color='#45627C',lw=2)
line.axis('off')

#添加阴影效果
for i in artist_01.index.to_list():
    ax.axvspan(i-.35, i+.35, facecolor='gray',alpha=.1,zorder=0)
    
#添加双y轴:使用Axes.twinx()方法绘制
second_plot = ax.twinx()
second_plot.set_ylim(bottom=-3,top=43)
second_plot.set_yticks(np.arange(0, 50, step=10))
second_plot.set_xticks(np.arange(-.5, 8, step=.5))
second_plot.tick_params(left=False,bottom=False,labelbottom=False,labelsize=10,colors='k')
second_plot.grid(color="none",zorder=0)
second_plot.set_axisbelow(True)
for spine in ['top','bottom','left','right']:
    second_plot.spines[spine].set_visible(False) #("#FFFFFF")

y2 = artist_01['data02'].values
label_text = {"size":28,"color":"white",'weight':'light'}
for x,y2 in zip(np.arange(len(artist_01)).tolist(),artist_01['data02'].to_list()):
    second_plot.plot([x,x],[0,y2],lw=20,color=color[x],solid_capstyle='round')
    #绘制空心圆
    second_plot.scatter(x,0,s=150,c='white',zorder=3)
    second_plot.scatter(x,0,s=60,c=color[x],zorder=4)
    second_plot.scatter(x,0,s=15,c='white',zorder=5)
   
# 添加文本信息
label_font = {"size":15,'weight':'bold'}
for i,x,text in zip(artist_01.index.to_list(),np.arange(0,len(artist_01),1),artist_01['year'].values):
    ax.text(x, -8,text ,ha='center', va= 'bottom',fontdict=label_font,color=year_color[i],zorder=2)

ax.text(.39,1.2,'\nSecond Y Axes Plot Exercise',transform = ax.transAxes,
        ha='center', va='center',fontsize = 20,color='k',fontweight="bold")
ax.text(.02,1.04,'Use the Matplotlib axes.Axes.twinx()',
        transform = ax.transAxes,
        ha='left', va='center',fontsize = 9,color='#45627C')

ax.text(.91,.02,'\nVisualization by DataCharm',transform = ax.transAxes,
        ha='center', va='center',fontsize = 7,color='black')
plt.savefig(r'double_y_axis_plot.png',width=6,height=3,
            dpi=900,bbox_inches='tight',facecolor='white')
#ax.set_axisbelow(True)
plt.show()

解释:

1. 添加横线(修饰)

ax.axhline(y=0,color='#45627C',lw=3)

2. 添加标题处小图

axins = inset_axes(ax, width=.4, height=.4,loc='upper left',
                   bbox_to_anchor=(0.01, 0.22, 1, 1),
                   bbox_transform=ax.transAxes,
                   borderpad=0)
axins.set_ylim(bottom=8,top=35)
axins.set_xlim(left=-.5,right=2.5)
axins.plot(x[:3],y[:3],color='#333333',lw=1.,zorder=1)
for i in artist_01.index.to_list()[:3]:
    axins.scatter(x[i],y[i],s=80,color=year_color[i],zorder=2)
axins.axis('off')

3. 添加双y轴:使用Axes.twinx()方法绘制:重点

#添加双y轴:使用Axes.twinx()方法绘制
second_plot = ax.twinx()
second_plot.set_ylim(bottom=-3,top=43)
second_plot.set_yticks(np.arange(0, 50, step=10))
second_plot.set_xticks(np.arange(-.5, 8, step=.5))
second_plot.tick_params(left=False,bottom=False,labelbottom=False,labelsize=10,colors='k')
second_plot.grid(color="none",zorder=0)
second_plot.set_axisbelow(True)
for spine in ['top','bottom','left','right']:
    second_plot.spines[spine].set_visible(False) #("#FFFFFF")

y2 = artist_01['data02'].values
label_text = {"size":28,"color":"white",'weight':'light'}
for x,y2 in zip(np.arange(len(artist_01)).tolist(),artist_01['data02'].to_list()):
    second_plot.plot([x,x],[0,y2],lw=20,color=color[x],solid_capstyle='round')
    #绘制空心圆
    second_plot.scatter(x,0,s=150,c='white',zorder=3)
    second_plot.scatter(x,0,s=60,c=color[x],zorder=4)
    second_plot.scatter(x,0,s=15,c='white',zorder=5)

最终的可视化结果如下:

总结: Python-matplotlib 绘制双Y轴的关键就是使用Axes.twinx()方法 再次添加一个绘图对象,再把要绘制的对象在此绘图对象上绘制即可,其他和正常的matplotlib语法一样。

ggplot2-sec.axis()绘制双轴

在介绍完Python-matplotlib 绘制双Y轴后,我们再次介绍R-ggplot2如何绘制双Y轴,由于绘制上面的可视化结果较为繁琐,这里我们直接生成样例数据进行双Y轴的讲解。主要涉及的知识点就是scale_y_continuous() 或scale_x_continuous()中的sec.axis()属性设置。

构建数据

这里我们构建虚拟数据,代码如下:

data <- data.frame(
  day = as.Date("2019-01-01") + 0:99,
  temperature = runif(100) + seq(1,100)^2.5 / 10000,
  price = runif(100) + seq(100,1)^1.5 / 10
)
head(data)

数据预览如下(部分):

可视化绘制

这里我们直接给出代码,大家不懂的可以参考ggplot2官网,代码如下:

coeff <- 10
temperatureColor <- "#75B8D1"
priceColor <- "#D175B8"

double_y <-ggplot(data, aes(x=day)) +
 geom_line(aes(y=temperature), size=1.5, color=temperatureColor) + 
 geom_line(aes(y=price / coeff), size=1.5, color=priceColor) +
 #设置双轴关键代码
 scale_y_continuous(
   # first axis name
   name = "Temperature (C°)",
   # 定制化设置第二个图例属性
   sec.axis = sec_axis(trans = ~.*coeff, name="Price ($)")
 ) + 
 labs(x="",
      title = "R Charts Exercise: <span style='color:#D20F26'>Double Y Axis</span>",
      subtitle = "processed charts with <span style='color:#1A73E8'>scale_y/x_continuous:sec_axis()</span>",
      caption = "Visualization by <span style='color:#DD6449'>DataCharm</span>") +
 theme_ft_rc()+
 theme(
   axis.title.y = element_text(color = temperatureColor, size=13),
   axis.title.y.right = element_text(color = priceColor, size=13),
   plot.title = element_markdown(hjust = 0.5,vjust = .5,color = "black",
                                 size = 20, margin = margin(t = 1, b = 12)),
   plot.subtitle = element_markdown(hjust = 0,vjust = .5,size=15),
   plot.caption = element_markdown(face = 'bold',size = 12),
 ) 

设置双轴代码:

 #设置双轴关键代码
 scale_y_continuous(
   # first axis name
   name = "Temperature (C°)",
   # 定制化设置第二个图例属性
   sec.axis = sec_axis(trans = ~.*coeff, name="Price ($)")
 ) + 

最终可视化代码如下:

总结

本期推文我们简单介绍了Python-matplotlibR-ggplot2 绘制双Y轴的绘制方法,希望可以帮助到有需要的小伙伴。我们基础系列的图表绘制教程还在继续中哦,感谢大家持续支持和关注。

相关推荐
女王の专属领地9 分钟前
深入浅出《钉钉AI》产品体验报告
人工智能·钉钉·语音识别·ai协同办公
新智元10 分钟前
Grok 3证明黎曼猜想,训练遭灾难性事件?数学家称不夸张,两年内AI将解出千禧年难题
人工智能·后端
摆烂仙君15 分钟前
论文《基于现实迷宫地形的电脑鼠设计》深度分析(三)——环境感知驱动算法
人工智能·计算机视觉
B站计算机毕业设计超人15 分钟前
计算机毕业设计Python美食推荐系统 美团爬虫 美食可视化 机器学习 深度学习 混合神经网络推荐算法 Hadoop Spark 人工智能 大数据毕业设计
大数据·人工智能·爬虫·python·深度学习·机器学习·课程设计
刀鋒偏冷19 分钟前
python核心语法(二)
python
说私域19 分钟前
社交电商的优势及其与 AI 智能名片小程序、S2B2C 商城系统的融合发展
人工智能·小程序
小远yyds22 分钟前
微信小程序进行md5加密 ,base64 转码
开发语言·前端·微信小程序·小程序
Clown9524 分钟前
go-zero(四) 错误处理(统一响应信息)
开发语言·golang·lua
资源补给站29 分钟前
论文6—《基于YOLOv5s的深度学习在自然场景苹果花朵检测中的应用》文献阅读分析报告
人工智能·深度学习·yolo