Python数据可视化:一张很漂亮的商业图

前言

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理

以下文章来源于Lin王发林,作者:WangFalin

Python数据分析:零基础入门教学(讲解+实战)

https://www.bilibili.com/video/BV18f4y1i7q9/

前言

上个月的时候看到一张很漂亮的商业图,很喜欢,然后就忘了。刚好前两天看到一篇文章来临摹此图,于是学习了一下其思路和代码,然后拿来实践了一下,效果还可以,特此纪念,以后应该还有用得上的地方。那商业图我就不放了,然后把我的图放在这里↓

数据准备

可以看到,图中主要有4列数据组成,分别是公司logo、公司名称、所属工具和市值增长值。于是先准备数据,就是我常用的软件工具列举了一下,共20个,然后数值是使用率吧,Type是用来标记颜色的,最后一列分类是次软件的主要作用,&符号连接两个或多个主要用途。如下↓

import matplotlib.pyplot as pltimport pandas as pdimport osos.chdir(r'E:\Python\Seaborn\Others')mydata = pd.read_excel('不规则条形图数据.xlsx')

设置中文字体正常显示

mycolor = {    'Green': '#8ABD25',    'Pink': '#F57FEF',    'Yellow': '#EBE639',    'Red': '#EB3939',    'Orange': '#EBAF39',    'Blue': '#39A4EB',    'Black': '#4D6E83',    'Gray': '#A3A4A5',}

自定义颜色,后面直接根据Type类型进行调用就行了

logosize = 0.037 #软件图标大小right_height = 20 #右边矩形填充的高度,建议和数据行数一样多ratio = 0.05 #这个系数会影响右边矩形整体的偏移情况,建议值是(1/行数)ratio2 = 0.8 #这个系数影响右边矩形上面的下移程度ratio3 = 0.005 #分类图标的水平位置ratio4 = 0.01 #数影响右边矩形下面的上移程度ratio5 = 0.01 #影响软件文字的上下水平

一些影响的参数,因为涉及多处,所以提出来统一修改了,还有一些参数需要里面改。

def create_fill_area(row):    # 初始化包围填充区域的上下线条y坐标    line1, line2 = [1 - ratio*row, 1 - ratio*row], [1- ratio*(row+1), 1- ratio*(row+1)]    # 追加阴影段y坐标    line1.append(ratio4 + (right_height - row) * (ratio2 - ratio4) / right_height)    line2.append(ratio4 + (right_height - row - 1) * (ratio2 - ratio4) / right_height)    # 追加最后一段平行段y坐标    line1.append(ratio4 + (right_height - row) * (ratio2 - ratio4) / right_height)    line2.append(ratio4 + (right_height - row - 1) * (ratio2 - ratio4) / right_height)    return line1, line2

为了创建出不同条带,配合matplotlib中的fill_between。为了处理好左侧与右侧的竖直方向等分区域,我们可以在对原数据每一行循环的过程中,自定义下列函数来计算区域范围↓

fig, ax = plt.subplots(figsize=(4.8, 6))ax.set_xlim(0, 1.11)ax.set_ylim(0, 1)for row in range(mydata.shape[0]):    # 定义区域填充对应的x坐标    x = [0, 0.15, 0.215, 0.6+mydata.at[row, 'Values'] / 1000]    # 生成区域填充对应的y坐标    line1, line2 = create_fill_area(row)    # 对指定区域进行填充    ax.fill_between(x,                    line1,                    line2,                    color=mycolor[mydata.at[row, 'Type']],                    edgecolor='none')        # 从logo文件夹下读取对应logo图片    try:        logo = plt.imread(f'logo/{mydata.at[row, "Tools"]}.png')    except FileNotFoundError:        logo = plt.imread(f'logo/{mydata.at[row, "Tools"]}.jpg')        # 插入软件logo    ax_logo = ax.inset_axes((0.05, 1 - ratio*(row+1)+0.005, 0.08, logosize))    ax_logo.imshow(logo)        ax_logo.axis('off')    ax_logo.set_facecolor(mycolor[mydata.at[row, 'Type']])        # 处理单个及多个功能情况下的绘制    for idx, Category in enumerate(mydata.at[row, 'Category'].split('&')[::-1]):                # 读取对应功能图片        flag = plt.imread(f'flag/{Category}.png')        # 插入功能子图        ax_flag = ax.inset_axes((0.545-idx*0.06, 0.013+(right_height - row - 1)*((ratio2 - ratio3) / right_height), 0.1, 0.025))        ax_flag.imshow(flag)        ax_flag.axis('off')        ax_flag.set_facecolor(mycolor[mydata.at[row, 'Type']])    # 绘制排名    ax.text(0.025, (1 - ratio*row + 1 - ratio*(row+1)) / 2, str(row+1),             ha='center', va='center',            fontsize=9, color='black')    # 绘制软件名称    ax.text(0.215+ratio5, 0.5 * (ratio5 + (right_height - row - 1) * (ratio2 - ratio5) / right_height + ratio5 + (right_height - row) * (ratio2 - ratio5) / right_height),             mydata.at[row, 'Tools'],             ha='left', va='center',            fontsize=9, color='#FFFFFF',             weight='bold')    # 处理第一名文字在填充区域内部,其余文字在填充区域外的情况    if mydata.at[row, 'Tools'] == 'Exce1l':        ax.text(1, 0.5 * (ratio3 + (right_height - row) * (ratio2 - ratio3) / right_height                           + ratio3 + (right_height - row - 1) * (ratio2 - ratio3) / right_height)-0.0025,                ''+str(mydata.at[row, 'Values']/4)+'%',                color='white',                fontsize=10,                ha='right',                va='center',                weight='bold')    else:        # 配合归一化对字体进行大小映射        ax.text(0.6+mydata.at[row, 'Values'] / 1000 + ratio3,                 0.5 * (ratio3 + (right_height - row) * (ratio2 - ratio3) / right_height + ratio3 + (right_height - row - 1) * (ratio2 - ratio3) / right_height)-0.0025,                ''+str(int(mydata.at[row, 'Values']/4))+'%',                color=mycolor[mydata.at[row, 'Type']],                fontsize=7+((mydata.at[row, 'Values'] - mydata['Values'].min())                             / (mydata['Values'].max() - mydata['Values'].min())) * 5,                ha='left',                va='center',                weight='bold')# 对指定区域进行带透明度的黑色蒙版,以达到阴影效果ax.fill_between([0.15, 0.215],                [0, ratio4],                [1, ratio2],                color='black',                alpha=0.2, # 设置透明度                edgecolor='none')# 补充其余文字标注ax.text(0.215+ratio5, 0.805, '软件名称',         color='#565555', fontsize=6,        ha='left')ax.text(0.67, 0.805, '软件类型',         color='#565555', fontsize=6,        ha='center')#补充上方数值刻度ax.text(0.6, 0.825, '0',         color='#a9a8a8', fontsize=8,        ha='center')    for i in range(1, 5):    print(i)    ax.text(0.6+0.1*i, 0.825, f'{i*25}%',             color='#a9a8a8', fontsize=9,            ha='center')       ax.vlines(0.6+0.1*i, 0.01, 0.82,               color='#dcdcdb', linewidth=0.2)ax.set_xticks([])ax.set_yticks([])ax.spines['left'].set_color('none')ax.spines['right'].set_color('none')ax.spines['top'].set_color('none')ax.spines['bottom'].set_color('none')# 补充下排图例ax_bar1 = ax.inset_axes((0.215, 0.88, 0.57, 0.02), transform=ax.transAxes)ax_bar1.set_xlim(-0.45, 3.6)ax_bar1.bar(range(4), height=1, width=0.8,             color=['#8ABD25', '#F57FEF', '#EBE639', '#EB3939'])ax_bar1.set_xticks(range(4))ax_bar1.set_xticklabels(['绿色系', '紫色系', '黄色系', '红色系'],                        fontsize=7, color='#4f4e4e', weight='bold')ax_bar1.set_yticks([])ax_bar1.spines['left'].set_color('none')ax_bar1.spines['right'].set_color('none')ax_bar1.spines['top'].set_color('none')ax_bar1.spines['bottom'].set_color('none')ax_bar1.tick_params(color='none', pad=-2)ax_bar1.set_facecolor('#f8f8f8')# 补充上排图例ax_bar2 = ax.inset_axes((0.215, 0.98, 0.57, 0.02), transform=ax.transAxes)ax_bar2.set_xlim(-0.45, 3.6)ax_bar2.bar(range(4), height=1, width=0.8,             color=['#EBAF39', '#39A4EB', '#4D6E83', '#A3A4A5'])ax_bar2.set_xticks(range(4))ax_bar2.set_xticklabels(['橙色系', '蓝色系', '黑色系', '灰色系'],                        fontsize=7, color='#4f4e4e', weight='bold')ax_bar2.set_yticks([])ax_bar2.spines['left'].set_color('none')ax_bar2.spines['right'].set_color('none')ax_bar2.spines['top'].set_color('none')ax_bar2.spines['bottom'].set_color('none')ax_bar2.tick_params(color='none', pad=-2)ax_bar2.set_facecolor('#f8f8f8')ax.set_facecolor('#f8f8f8')fig.set_facecolor('#f8f8f8')fig.savefig('输出结果.png', dpi=800, bbox_inches='tight')

下面是绘图代码,都有注释说明,读一遍应该都能读懂,只是一些巧妙计算的逻辑需要理一下。这里没有绘制标题,可以借助PS添加一个完美的标题。

fig, ax = plt.subplots(figsize=(4.8, 6))ax.set_xlim(0, 1.11)ax.set_ylim(0, 1)for row in range(mydata.shape[0]):    # 定义区域填充对应的x坐标    x = [0, 0.15, 0.215, 0.6+mydata.at[row, 'Values'] / 1000]    # 生成区域填充对应的y坐标    line1, line2 = create_fill_area(row)    # 对指定区域进行填充    ax.fill_between(x,                    line1,                    line2,                    color=mycolor[mydata.at[row, 'Type']],                    edgecolor='none')        # 从logo文件夹下读取对应logo图片    try:        logo = plt.imread(f'logo/{mydata.at[row, "Tools"]}.png')    except FileNotFoundError:        logo = plt.imread(f'logo/{mydata.at[row, "Tools"]}.jpg')        # 插入软件logo    ax_logo = ax.inset_axes((0.05, 1 - ratio*(row+1)+0.005, 0.08, logosize))    ax_logo.imshow(logo)        ax_logo.axis('off')    ax_logo.set_facecolor(mycolor[mydata.at[row, 'Type']])        # 处理单个及多个功能情况下的绘制    for idx, Category in enumerate(mydata.at[row, 'Category'].split('&')[::-1]):                # 读取对应功能图片        flag = plt.imread(f'flag/{Category}.png')        # 插入功能子图        ax_flag = ax.inset_axes((0.545-idx*0.06, 0.013+(right_height - row - 1)*((ratio2 - ratio3) / right_height), 0.1, 0.025))        ax_flag.imshow(flag)        ax_flag.axis('off')        ax_flag.set_facecolor(mycolor[mydata.at[row, 'Type']])    # 绘制排名    ax.text(0.025, (1 - ratio*row + 1 - ratio*(row+1)) / 2, str(row+1),             ha='center', va='center',            fontsize=9, color='black')    # 绘制软件名称    ax.text(0.215+ratio5, 0.5 * (ratio5 + (right_height - row - 1) * (ratio2 - ratio5) / right_height + ratio5 + (right_height - row) * (ratio2 - ratio5) / right_height),             mydata.at[row, 'Tools'],             ha='left', va='center',            fontsize=9, color='#FFFFFF',             weight='bold')    # 处理第一名文字在填充区域内部,其余文字在填充区域外的情况    if mydata.at[row, 'Tools'] == 'Exce1l':        ax.text(1, 0.5 * (ratio3 + (right_height - row) * (ratio2 - ratio3) / right_height                           + ratio3 + (right_height - row - 1) * (ratio2 - ratio3) / right_height)-0.0025,                ''+str(mydata.at[row, 'Values']/4)+'%',                color='white',                fontsize=10,                ha='right',                va='center',                weight='bold')    else:        # 配合归一化对字体进行大小映射        ax.text(0.6+mydata.at[row, 'Values'] / 1000 + ratio3,                 0.5 * (ratio3 + (right_height - row) * (ratio2 - ratio3) / right_height + ratio3 + (right_height - row - 1) * (ratio2 - ratio3) / right_height)-0.0025,                ''+str(int(mydata.at[row, 'Values']/4))+'%',                color=mycolor[mydata.at[row, 'Type']],                fontsize=7+((mydata.at[row, 'Values'] - mydata['Values'].min())                             / (mydata['Values'].max() - mydata['Values'].min())) * 5,                ha='left',                va='center',                weight='bold')# 对指定区域进行带透明度的黑色蒙版,以达到阴影效果ax.fill_between([0.15, 0.215],                [0, ratio4],                [1, ratio2],                color='black',                alpha=0.2, # 设置透明度                edgecolor='none')# 补充其余文字标注ax.text(0.215+ratio5, 0.805, '软件名称',         color='#565555', fontsize=6,        ha='left')ax.text(0.67, 0.805, '软件类型',         color='#565555', fontsize=6,        ha='center')#补充上方数值刻度ax.text(0.6, 0.825, '0',         color='#a9a8a8', fontsize=8,        ha='center')    for i in range(1, 5):    print(i)    ax.text(0.6+0.1*i, 0.825, f'{i*25}%',             color='#a9a8a8', fontsize=9,            ha='center')       ax.vlines(0.6+0.1*i, 0.01, 0.82,               color='#dcdcdb', linewidth=0.2)ax.set_xticks([])ax.set_yticks([])ax.spines['left'].set_color('none')ax.spines['right'].set_color('none')ax.spines['top'].set_color('none')ax.spines['bottom'].set_color('none')# 补充下排图例ax_bar1 = ax.inset_axes((0.215, 0.88, 0.57, 0.02), transform=ax.transAxes)ax_bar1.set_xlim(-0.45, 3.6)ax_bar1.bar(range(4), height=1, width=0.8,             color=['#8ABD25', '#F57FEF', '#EBE639', '#EB3939'])ax_bar1.set_xticks(range(4))ax_bar1.set_xticklabels(['绿色系', '紫色系', '黄色系', '红色系'],                        fontsize=7, color='#4f4e4e', weight='bold')ax_bar1.set_yticks([])ax_bar1.spines['left'].set_color('none')ax_bar1.spines['right'].set_color('none')ax_bar1.spines['top'].set_color('none')ax_bar1.spines['bottom'].set_color('none')ax_bar1.tick_params(color='none', pad=-2)ax_bar1.set_facecolor('#f8f8f8')# 补充上排图例ax_bar2 = ax.inset_axes((0.215, 0.98, 0.57, 0.02), transform=ax.transAxes)ax_bar2.set_xlim(-0.45, 3.6)ax_bar2.bar(range(4), height=1, width=0.8,             color=['#EBAF39', '#39A4EB', '#4D6E83', '#A3A4A5'])ax_bar2.set_xticks(range(4))ax_bar2.set_xticklabels(['橙色系', '蓝色系', '黑色系', '灰色系'],                        fontsize=7, color='#4f4e4e', weight='bold')ax_bar2.set_yticks([])ax_bar2.spines['left'].set_color('none')ax_bar2.spines['right'].set_color('none')ax_bar2.spines['top'].set_color('none')ax_bar2.spines['bottom'].set_color('none')ax_bar2.tick_params(color='none', pad=-2)ax_bar2.set_facecolor('#f8f8f8')ax.set_facecolor('#f8f8f8')fig.set_facecolor('#f8f8f8')fig.savefig('输出结果.png', dpi=800, bbox_inches='tight')

这个颜色有点艳丽,可以调整一下颜色就行了,然后用PS加个标题,底部再加点看不懂的小文字显得高端,然后基本上就大功告成了。

(0)

相关推荐

  • python画双y轴图像

    很多时候可能需要在一个图中画出多条函数图像,但是可能y轴的物理含义不一样,或是数值范围相差较大,此时就需要双y轴. matplotlib和seaborn都可以画双y轴图像.一个例子: import s ...

  • 数据可视化:疫情期间市值增长top25公司

    数据可视化:疫情期间市值增长top25公司

  • 如何使用Matplotlib制作出动画??

    动画是描述现象的工具,相比于静态图,我们人类经常执迷于动画和交互图表.在探求时间序列数据时,诸如股价趋势.气候变化.季节等, 动画更有洞感.今天让我们尝试绘制以下三种动图 前期准备 matplotli ...

  • 深度盘点 | 史上最全python数据可视化库

    有多少同学和小编一样,学习python的主要目的,是为了实现数据可视化?

  • (2条消息) 数据可视化技术:python数据可视化工具库汇总(共21个)

    Python数据可视化库 在数据分析中最好展示数据的方式就是形象地绘制对应的图像,让人能够更好地理解数据.什么样的数据.什么样的场景用什么样的图表都是有一定的规定的.(这个以后写一篇博客来记录一下.当 ...

  • Python数据可视化的完整版操作指南(建议收藏)

    让我们看一下使用Python进行数据可视化的主要库以及可以使用它们完成的所有类型的图表.我们还将看到建议在每种情况下使用哪个库以及每个库的独特功能. 我们将从最基本的可视化开始,直接查看数据,然后继续 ...

  • Python数据可视化:数据分析中的6个常用图

    折线图: 折线图用于显示数据在一个连续的时间间隔或者时间跨度上的变化,它的特点是反映事物随时间或有序类别而变化的趋势.示例图如下: 折线图应用场景: 折线图适合X轴是一个连续递增或递减的,对于没有规律 ...

  • Python数据可视化库有哪些?Python入门

    现如今,数据已经渗透到每一个行业和业务职能领域,成为重要的生产因素,正因如此数据分析岗位变得异常火爆.而Python作为数据分析的首选语言,它不仅有着独特的优势,还为数据分析提供了很多库,那么常见的P ...

  • 编程干货|这么多Python数据可视化库,你最喜欢哪个?

    而这个问题就正好涉及到了Python的数据可视化了. 很多同学学习Python的主要目的就是为了实现数据可视化. 而如何将我们的数据的特征更好的.更直观的展示出来,Python给出了很多解决方案. 今 ...

  • 盘点12个Python数据可视化库,通吃任何领域

    大家普遍第一次接触到的Python数据可视化库基本上都是Matplotlib.Python还有很多数据可视化库,本文盘点了12款常用的Python数据可视化库,挑选适合自己业务的那一款吧! 深入学习P ...

  • python|数据可视化之matplotlib画图

    前言相信大家在现阶段被大数据时代带来大量的数据和一些文章而不能清楚直观地了解其中真正关键的数据,所以小编给大家带来一种简单的数据可视化的解决方案-利用matplotlib函数来制作简单的直方图.运行环 ...

  • Python数据可视化库seaborn的使用总结

    seaborn是python中的一个非常强大的数据可视化库,它集成了matplotlib,下图为seaborn的官网,如果遇到疑惑的地方可以到官网查看.http://seaborn.pydata.or ...