今天,我将向您展示如何创建口红图表,以可视化值越低的指标进度,
越好。我已经准备了一个关于死亡率和疾病的简单数据集,因此您可以专注于创建可视化。
数据来自World Bank,如果您想了解更多信息,我已经在新的免费新闻Abiaoqian中写了有关可视化的文章。
让我们开始。
步骤1-导入库
第一个也是最简单的部分是导入所需的库,例如pandas和matplotlib。
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.lines import Line2D
恭喜,您刚刚完成了步骤1! ð¥³
步骤2-创建海洋风格
接下来,我想创建一个颜色和选择字体。在寻找美丽的颜色时,例如Coolors和Colorhunt等网站是很棒的资源。
这是我为本教程创建海洋风格的代码和设置。
FONT_FAMILY = "serif"
BACKGROUND_COLOR = "#FAE8E0"
TEXT_COLOR = "#33261D"
BAR_COLOR = "#EF7C8E"
sns.set_style({
"axes.facecolor": BACKGROUND_COLOR,
"figure.facecolor": BACKGROUND_COLOR,
"text.color": TEXT_COLOR,
"font.family": FONT_FAMILY,
"xtick.bottom": False,
"xtick.top": False,
"ytick.left": False,
"ytick.right": False,
"axes.spines.left": False,
"axes.spines.bottom": False,
"axes.spines.right": False,
"axes.spines.top": False,
})
我正在删除所有的刻度和线条以创建一个干净的可视化,并且网格不会在我们的口红图中添加任何有价值的信息。
步骤3-阅读数据
您可以像我在下面的代码中一样直接从URL读取CSV。
df = pd.read_csv(
"https://raw.githubusercontent.com/oscarleoo/matplotlib-tutorial-data/main/mortality-and-decease.csv"
)
这是数据框的外观。
大多数值除了per
外,它都是自称的,它显示了每行的比例。例如,最新的“产妇死亡率”价值为100,000个出生中的223个。
步骤4-添加条
现在是时候添加一些数据了。
我正在为2000和最新值添加条。由于我的目标是显示每个值的相对减小,因此我将每一行除以其2000值。
这意味着2000的每个栏将达到1,因此它只是一个视觉助手,不会添加任何其他信息。
这是我添加条的功能。
def add_bars(ax, x, width, alpha, label):
sns.barplot(
ax=ax, x=x, y=[i for i in range(len(x))], label=label,
width=width, alpha=alpha,
color=BAR_COLOR,
edgecolor=TEXT_COLOR,
orient="h"
)
我创建一个图形并像这样运行add_bars()
函数。
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df)))
add_bars(
ax=ax, x=df["2000"] / df["2000"],
width=0.55, alpha=0.2, label="2000"
)
add_bars(
ax=ax, x=df["latest_value"] / df["2000"],
width=0.7, alpha=1, label="Latest"
)
我们到目前为止的代码的结果。
让我们继续。
步骤5-格式化轴
每行的名称在没有线路破坏的情况下可以使用。这就是为什么我创建以下功能将\n
添加到几个地方的字符串的原因。
def split_name(name, limit=20):
split = name.split()
s = ""
for s_ in split:
if len(s.split("\n")[-1] + s_) > limit:
s += "\n" + s_
else:
s += " " + s_
return s.strip()
我还希望增加字体大小并删除不必要的信息以使图表可读。现在创建可视化的代码现在看起来像这样。
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df)))
...
ax.set(xlabel=None, ylabel=None, xticks=[])
ax.tick_params("y", labelsize=28, pad=32)
ax.tick_params("x", labelsize=20, pad=16)
ax.set_yticks(
ticks=[i for i in range(len(df))],
labels=[split_name(n, limit=19) for n in df["indicator_name"]],
linespacing=1.7, va="center"
)
这是更新的结果。
让我们添加一些其他信息。
步骤5-添加有用的信息
您始终想确保用户了解他们在看什么。现在,我们没有这样的信息。
对于启动器,我想添加当前值,我使用以下功能进行。
def add_info_text(ax, row, index):
value = round(row["latest_value"], 1)
per = row["per"]
year = row["latest_year"]
text = "{:,} out of\n{:,} ({})".format(value, per, year)
ax.annotate(
text=text,
xy=(0.02, index),
color="#fff",
fontsize=24,
va="center",
linespacing=1.7
)
,并且由于目的是显示每个度量的相对减小与2000年相比其值,所以我有另一个函数显示每行的变化。
def add_change_text(ax, row, index):
change = round(100 * row["change"], 1)
text = "{:,}%".format(change)
x = row["latest_value"] / row["2000"] + 0.02
ax.annotate(
text="{:,}%".format(change), xy=(x, index), fontsize=22,
va="center", linespacing=1.7
)
我在循环下添加两个功能。
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df)))
...
for index, row in df.reset_index().iterrows():
add_info_text(ax, row, index)
add_change_text(ax, row, index)
这是输出。
它开始看起来不错。
步骤6-添加标题和传奇
在此步骤中,我只是使用一些内置的matplotlib函数来添加标题和传奇。由于我们在add_bars()
中定义了label
,因此许多样式都是自动的。
除了定义标题和传奇外,我还使用Line2D
添加了一个边框以进行视觉效果。
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df)))
...
line = Line2D([-0.33, 1.0], [-0.9, -0.9], color=TEXT_COLOR)
line.set_clip_on(False)
ax.add_artist(line)
title = "Lipstick Chart - Relative\nDecreases Compared\nto 2000"
plt.title(title, x=-0.32, y=1.11, fontsize=58, ha="left", linespacing=1.6)
plt.legend(bbox_to_anchor=(0.75, 1.14), loc='lower center', borderaxespad=0, ncol=1, fontsize=44, edgecolor="#FAE8E0")
这是图表现在的样子。
步骤7-创建图像并添加填充
图表看起来有些局促,因此最后一步是添加一些填充。我是通过将图形变成具有以下功能的PIL图像来做到这一点。
def create_image_from_figure(fig):
plt.tight_layout()
fig.canvas.draw()
data = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
data = data.reshape((fig.canvas.get_width_height()[::-1]) + (3,))
plt.close()
return Image.fromarray(data)
这是添加填充的功能。
def add_padding_to_chart(chart, left, top, right, bottom, background):
size = chart.size
image = Image.new("RGB", (size[0] + left + right, size[1] + top + bottom), background)
image.paste(chart, (left, top))
return image
我们现在编写了创建我们针对的数据可视化所需的所有代码。
这是使用所有功能创建最终口红图的完整代码段。
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df)))
add_bars(
ax=ax, x=df["2000"] / df["2000"],
width=0.55, alpha=0.2, label="2000"
)
add_bars(
ax=ax, x=df["latest_value"] / df["2000"],
width=0.7, alpha=1, label="Latest"
)
ax.set(xlabel=None, ylabel=None, xticks=[])
ax.tick_params("y", labelsize=28, pad=32)
ax.tick_params("x", labelsize=20, pad=16)
ax.set_yticks(
ticks=[i for i in range(len(df))],
labels=[split_name(n, limit=20) for n in df["indicator_name"]],
linespacing=1.7, va="center"
)
for index, row in df.reset_index().iterrows():
add_info_text(ax, row, index)
add_change_text(ax, row, index)
line = Line2D([-0.35, 1.0], [-0.9, -0.9], color=TEXT_COLOR)
line.set_clip_on(False)
ax.add_artist(line)
title = "Lipstick Chart - Relative\nDecreases Compared\nto 2000"
plt.title(title, x=-0.32, y=1.11, fontsize=58, ha="left", linespacing=1.6)
plt.legend(bbox_to_anchor=(0.75, 1.14), loc='lower center', borderaxespad=0, ncol=1, fontsize=44, edgecolor="#FAE8E0")
image = create_image_from_figure(fig)
image = add_padding_to_chart(image, 20, 50, 10, 50, BACKGROUND_COLOR)
这是成品。
我们完成了!
结论
感谢您阅读本教程;希望您学会了一些技巧,可以重用数据可视化项目。
如果您想查看更多教程和美丽的数据可视化,请在此处关注我,订阅Data Wonder,并在Twitter上订阅oscarl3o。
下次见。