绘图提高篇 | 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轴的绘制方法,希望可以帮助到有需要的小伙伴。我们基础系列的图表绘制教程还在继续中哦,感谢大家持续支持和关注。

相关推荐
我们的五年几秒前
DeepSeek 和 ChatGPT 在特定任务中的表现:逻辑推理与创意生成
人工智能·chatgpt·ai作画·deepseek
Yan-英杰1 分钟前
百度搜索和文心智能体接入DeepSeek满血版——AI搜索的新纪元
图像处理·人工智能·python·深度学习·deepseek
Fuweizn3 分钟前
富唯智能可重构柔性装配产线:以智能协同赋能制造业升级
人工智能·智能机器人·复合机器人
weixin_307779131 小时前
Azure上基于OpenAI GPT-4模型验证行政区域数据的设计方案
数据仓库·python·云计算·aws
玩电脑的辣条哥2 小时前
Python如何播放本地音乐并在web页面播放
开发语言·前端·python
taoqick2 小时前
对PosWiseFFN的改进: MoE、PKM、UltraMem
人工智能·pytorch·深度学习
suibian52352 小时前
AI时代:前端开发的职业发展路径拓宽
前端·人工智能
预测模型的开发与应用研究3 小时前
数据分析的AI+流程(个人经验)
人工智能·数据挖掘·数据分析
源大模型3 小时前
OS-Genesis:基于逆向任务合成的 GUI 代理轨迹自动化生成
人工智能·gpt·智能体
多想和从前一样4 小时前
Django 创建表时 “__str__ ”方法的使用
后端·python·django