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

python

前言

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

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


 

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

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

前言

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

 

数据准备

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

import matplotlib.pyplot as plt

import pandas as pd

import os

os.chdir(r"E:PythonSeabornOthers")

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加个标题,底部再加点看不懂的小文字显得高端,然后基本上就大功告成了。

以上是 Python数据可视化:一张很漂亮的商业图[Python基础] 的全部内容, 来源链接: utcz.com/z/530661.html

回到顶部