点击下方“智影双全”卡片,每日获取AI医学影像科研前沿动态及技术实战干货! ⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇关注(最下方)公众号【智影双全】可免费获取文章⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
本文总结了 Matplotlib 以及 Seaborn 用的最多最全图表,掌握这些图形的绘制,对于数据分析的可视化有莫大的作用,强烈推荐大家阅读后续内容。
如果觉得内容不错,欢迎分享到您的朋友圈。
点击下方“智影双全”卡片,每日获取AI医学影像科研前沿动态及技术实战干货! ⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇关注(最下方)公众号【智影双全】可免费获取文章⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
介绍
这些图表根据可视化目标的7个不同情景进行分组。 例如,如果要想象两个变量之间的关系,请查看“关联”部分下的图表。 或者,如果您想要显示值如何随时间变化,请查看“变化”部分,依此类推。
有效图表的重要特征:
-
在不歪曲事实的情况下传达正确和必要的信息。
-
设计简单,您不必太费力就能理解它。
-
从审美角度支持信息而不是掩盖信息。
-
信息没有超负荷。
准备工作
在代码运行前先引入下面的设置内容。 当然,单独的图表,可以重新设置显示要素。
# !pip install brewer2mpl
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
import warnings; warnings.filterwarnings(action=\’once\’)
large = 22; med = 16; small = 12
params = {\’axes.titlesize\’: large,
\’legend.fontsize\’: med,
\’figure.figsize\’: (16, 10),
\’axes.labelsize\’: med,
\’axes.titlesize\’: med,
\’xtick.labelsize\’: med,
\’ytick.labelsize\’: med,
\’figure.titlesize\’: large}
plt.rcParams.update(params)
plt.style.use(\’seaborn-whitegrid\’)
sns.set_style(\”white\”)
%matplotlib inline
# Version
print(mpl.__version__) #> 3.0.0
print(sns.__version__) #> 0.9.0
一、关联 (Correlation)
关联图表用于可视化2个或更多变量之间的关系。 也就是说,一个变量如何相对于另一个变化。
1. 散点图(Scatter plot)
散点图是用于研究两个变量之间关系的经典的和基本的图表。 如果数据中有多个组,则可能需要以不同颜色可视化每个组。 在 matplotlib 中,您可以使用 plt.scatterplot() 方便地执行此操作。
# Import dataset
midwest = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv\”)
# Prepare Data
# Create as many colors as there are unique midwest[\’category\’]
categories = np.unique(midwest[\’category\’])
colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))]
# Draw Plot for Each Category
plt.figure(figsize=(16, 10), dpi= 80, facecolor=\’w\’, edgecolor=\’k\’)
for i, category in enumerate(categories):
plt.scatter(\’area\’, \’poptotal\’,
data=midwest.loc[midwest.category==category, :],
s=20, cmap=colors[i], label=str(category))
# \”c=\” 修改为 \”cmap=\”,智影双全 备注
# Decorations
plt.gca().set(xlim=(0.0, 0.1), ylim=(0, 90000),
xlabel=\’Area\’, ylabel=\’Population\’)
plt.xticks(fontsize=12); plt.yticks(fontsize=12)
plt.title(\”Scatterplot of Midwest Area vs Population\”, fontsize=22)
plt.legend(fontsize=12)
plt.show()

图1
2. 带边界的气泡图(Bubble plot with Encircling)
有时,您希望在边界内显示一组点以强调其重要性。 在这个例子中,你从数据框中获取记录,并用下面代码中描述的 encircle() 来使边界显示出来。
from matplotlib import patches
from scipy.spatial import ConvexHull
import warnings; warnings.simplefilter(\’ignore\’)
sns.set_style(\”white\”)
# Step 1: Prepare Data
midwest = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv\”)
# As many colors as there are unique midwest[\’category\’]
categories = np.unique(midwest[\’category\’])
colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))]
# Step 2: Draw Scatterplot with unique color for each category
fig = plt.figure(figsize=(16, 10), dpi= 80, facecolor=\’w\’, edgecolor=\’k\’)
for i, category in enumerate(categories):
plt.scatter(\’area\’, \’poptotal\’, data=midwest.loc[midwest.category==category, :],
s=\’dot_size\’, cmap=colors[i], label=str(category), edgecolors=\’black\’, linewidths=.5)
# \”c=\” 修改为 \”cmap=\”,智影双全 备注
# Step 3: Encircling
# https://stackoverflow.com/questions/44575681/how-do-i-encircle-different-data-sets-in-scatter-plot
def encircle(x,y, ax=None, **kw):
if not ax: ax=plt.gca()
p = np.c_[x,y]
hull = ConvexHull(p)
poly = plt.Polygon(p[hull.vertices,:], **kw)
ax.add_patch(poly)
# Select data to be encircled
midwest_encircle_data = midwest.loc[midwest.state==\’IN\’, :]
# Draw polygon surrounding vertices
encircle(midwest_encircle_data.area, midwest_encircle_data.poptotal, ec=\”k\”, fc=\”gold\”, alpha=0.1)
encircle(midwest_encircle_data.area, midwest_encircle_data.poptotal, ec=\”firebrick\”, fc=\”none\”, linewidth=1.5)
# Step 4: Decorations
plt.gca().set(xlim=(0.0, 0.1), ylim=(0, 90000),
xlabel=\’Area\’, ylabel=\’Population\’)
plt.xticks(fontsize=12); plt.yticks(fontsize=12)
plt.title(\”Bubble Plot with Encircling\”, fontsize=22)
plt.legend(fontsize=12)
plt.show()

图2
3. 带线性回归最佳拟合线的散点图 (Scatter plot with linear regression line of best fit)
如果你想了解两个变量如何相互改变,那么最佳拟合线就是常用的方法。 下图显示了数据中各组之间最佳拟合线的差异。 要禁用分组并仅为整个数据集绘制一条最佳拟合线,请从下面的 sns.lmplot() 调用中删除 hue =\’cyl\’ 参数。
# Import Data
df = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv\”)
df_select = df.loc[df.cyl.isin([4,8]), :]
# Plot
sns.set_style(\”white\”)
gridobj = sns.lmplot(x=\”displ\”, y=\”hwy\”, hue=\”cyl\”, data=df_select,
height=7, aspect=1.6, robust=True, palette=\’tab10\’,
scatter_kws=dict(s=60, linewidths=.7, edgecolors=\’black\’))
# Decorations
gridobj.set(xlim=(0.5, 7.5), ylim=(0, 50))
plt.title(\”Scatterplot with line of best fit grouped by number of cylinders\”, fontsize=20)
plt.show()

图3
针对每列绘制线性回归线
或者,可以在其每列中显示每个组的最佳拟合线。 可以通过在 sns.lmplot() 中设置 col=groupingcolumn 参数来实现,如下:
# Import Data
df = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv\”)
df_select = df.loc[df.cyl.isin([4,8]), :]
# Each line in its own column
sns.set_style(\”white\”)
gridobj = sns.lmplot(x=\”displ\”, y=\”hwy\”,
data=df_select,
height=7,
robust=True,
palette=\’Set1\’,
col=\”cyl\”,
scatter_kws=dict(s=60, linewidths=.7, edgecolors=\’black\’))
# Decorations
gridobj.set(xlim=(0.5, 7.5), ylim=(0, 50))
plt.show()

图3-2
4. 抖动图 (Jittering with stripplot)
通常,多个数据点具有完全相同的 X 和 Y 值。 结果,多个点绘制会重叠并隐藏。 为避免这种情况,请将数据点稍微抖动,以便您可以直观地看到它们。 使用 seaborn 的 stripplot() 很方便实现这个功能。
# Import Data
df = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv\”)
# Draw Stripplot
fig, ax = plt.subplots(figsize=(16,10), dpi= 80)
sns.stripplot(df.cty, df.hwy, jitter=0.25, size=8, ax=ax, linewidth=.5)
# Decorations
plt.title(\’Use jittered plots to avoid overlapping of points\’, fontsize=22)
plt.show()

图4
5. 计数图 (Counts Plot)
避免点重叠问题的另一个选择是增加点的大小,这取决于该点中有多少点。 因此,点的大小越大,其周围的点的集中度越高。
# Import Data
df = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv\”)
df_counts = df.groupby([\’hwy\’, \’cty\’]).size().reset_index(name=\’counts\’)
# Draw Stripplot
fig, ax = plt.subplots(figsize=(16,10), dpi= 80)
sns.stripplot(df_counts.cty, df_counts.hwy, size=df_counts.counts*2, ax=ax)
# Decorations
plt.title(\’Counts Plot – Size of circle is bigger as more points overlap\’, fontsize=22)
plt.show()

图5
6. 边缘直方图 (Marginal Histogram)
边缘直方图具有沿 X 和 Y 轴变量的直方图。 这用于可视化 X 和 Y 之间的关系以及单独的 X 和 Y 的单变量分布。 这种图经常用于探索性数据分析(EDA)。
# Import Data
df = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv\”)
# Create Fig and gridspec
fig = plt.figure(figsize=(16, 10), dpi= 80)
grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.2)
# Define the axes
ax_main = fig.add_subplot(grid[:-1, :-1])
ax_right = fig.add_subplot(grid[:-1, -1], xticklabels=[], yticklabels=[])
ax_bottom = fig.add_subplot(grid[-1, 0:-1], xticklabels=[], yticklabels=[])
# Scatterplot on main ax
ax_main.scatter(\’displ\’, \’hwy\’, s=df.cty*4, c=df.manufacturer.astype(\’category\’).cat.codes, alpha=.9, data=df, cmap=\”tab10\”, edgecolors=\’gray\’, linewidths=.5)
# histogram on the right
ax_bottom.hist(df.displ, 40, histtype=\’stepfilled\’, orientation=\’vertical\’, color=\’deeppink\’)
ax_bottom.invert_yaxis()
# histogram in the bottom
ax_right.hist(df.hwy, 40, histtype=\’stepfilled\’, orientation=\’horizontal\’, color=\’deeppink\’)
# Decorations
ax_main.set(title=\’Scatterplot with Histograms \\n displ vs hwy\’, xlabel=\’displ\’, ylabel=\’hwy\’)
ax_main.title.set_fontsize(20)
for item in ([ax_main.xaxis.label, ax_main.yaxis.label] + ax_main.get_xticklabels() + ax_main.get_yticklabels()):
item.set_fontsize(14)
xlabels = ax_main.get_xticks().tolist()
ax_main.set_xticklabels(xlabels)
plt.show()

图6
7. 边缘箱形图 (Marginal Boxplot)
边缘箱图与边缘直方图具有相似的用途。 然而,箱线图有助于精确定位 X 和 Y 的中位数、第25和第75百分位数。
# Import Data
df = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv\”)
# Create Fig and gridspec
fig = plt.figure(figsize=(16, 10), dpi= 80)
grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.2)
# Define the axes
ax_main = fig.add_subplot(grid[:-1, :-1])
ax_right = fig.add_subplot(grid[:-1, -1], xticklabels=[], yticklabels=[])
ax_bottom = fig.add_subplot(grid[-1, 0:-1], xticklabels=[], yticklabels=[])
# Scatterplot on main ax
ax_main.scatter(\’displ\’, \’hwy\’, s=df.cty*5, c=df.manufacturer.astype(\’category\’).cat.codes, alpha=.9, data=df, cmap=\”Set1\”, edgecolors=\’black\’, linewidths=.5)
# Add a graph in each part
sns.boxplot(df.hwy, ax=ax_right, orient=\”v\”)
sns.boxplot(df.displ, ax=ax_bottom, orient=\”h\”)
# Decorations ——————
# Remove x axis name for the boxplot
ax_bottom.set(xlabel=\’\’)
ax_right.set(ylabel=\’\’)
# Main Title, Xlabel and YLabel
ax_main.set(title=\’Scatterplot with Histograms \\n displ vs hwy\’, xlabel=\’displ\’, ylabel=\’hwy\’)
# Set font size of different components
ax_main.title.set_fontsize(20)
for item in ([ax_main.xaxis.label, ax_main.yaxis.label] + ax_main.get_xticklabels() + ax_main.get_yticklabels()):
item.set_fontsize(14)
plt.show()

图7
8. 相关图 (Correllogram)
相关图用于直观地查看给定数据框(或二维数组)中所有可能的数值变量对之间的相关度量。
# Import Dataset
df = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/mtcars.csv\”)
# Plot
plt.figure(figsize=(12,10), dpi= 80)
sns.heatmap(df.corr(), xticklabels=df.corr().columns, yticklabels=df.corr().columns, cmap=\’RdYlGn\’, center=0, annot=True)
# Decorations
plt.title(\’Correlogram of mtcars\’, fontsize=22)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()

图8
9. 矩阵图 (Pairwise Plot)
矩阵图是探索性分析中的最爱,用于理解所有可能的数值变量对之间的关系。 它是双变量分析的必备工具。
# Load Dataset
df = sns.load_dataset(\’iris\’)
# Plot
plt.figure(figsize=(10,8), dpi= 80)
sns.pairplot(df, kind=\”scatter\”, hue=\”species\”, plot_kws=dict(s=80, edgecolor=\”white\”, linewidth=2.5))
plt.show()

# Load Dataset
df = sns.load_dataset(\’iris\’)
# Plot
plt.figure(figsize=(10,8), dpi= 80)
sns.pairplot(df, kind=\”reg\”, hue=\”species\”)
plt.show()

10. 热力图 (General Heatmap)
不同于相关系数图,这是展示“类别 vs 类别”指标的利器。
# — Heatmap —# 场景:展示一周内不同时段的网站流量
data = np.random.rand(7, 24)
days = [\’Mon\’, \’Tue\’, \’Wed\’, \’Thu\’, \’Fri\’, \’Sat\’, \’Sun\’]
hours = [f\'{i}:00\’ for i in range(24)]
df_heat = pd.DataFrame(data, index=days, columns=hours)
plt.figure(figsize=(18, 6))
sns.heatmap(df_heat, annot=False, cmap=\”YlGnBu\”, cbar_kws={\’label\’: \’Traffic Intensity\’})
plt.title(\”Website Traffic Heatmap by Hour of Day\”, fontsize=20)
plt.xlabel(\”Hour of Day\”)
plt.ylabel(\”Day of Week\”)
plt.show()

11. PCA Biplot (主成分分析双标图)
在降维的同时,展示原始变量对主成分的贡献(载荷)以及样本的分布。
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
import numpy as np
iris = load_iris()
pca = PCA(n_components=2)
components = pca.fit_transform(iris.data)
loadings = pca.components_.T * np.sqrt(pca.explained_variance_)
plt.figure(figsize=(10, 8))
# 绘制样本点
plt.scatter(components[:, 0], components[:, 1], c=iris.target, cmap=\’viridis\’, alpha=0.5)
# 绘制变量特征向量
for i, feature in enumerate(iris.feature_names):
plt.arrow(0, 0, loadings[i, 0], loadings[i, 1], color=\’r\’, alpha=0.8, head_width=0.05)
plt.text(loadings[i, 0]*1.2, loadings[i, 1]*1.2, feature, color=\’r\’, fontsize=12)
plt.xlabel(\”PC1\”)
plt.ylabel(\”PC2\”)
plt.title(\”PCA Biplot: Samples and Feature Loadings\”, fontsize=18)
plt.show()

二、偏差 (Deviation)
12. 发散型条形图 (Diverging Bars)
如果您想根据单个指标查看项目的变化情况,并可视化此差异的顺序和数量,那么散型条形图 (Diverging Bars) 是一个很好的工具。 它有助于快速区分数据中组的性能,并且非常直观,并且可以立即传达这一点。
# Prepare Data
df = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/mtcars.csv\”)
x = df.loc[:, [\’mpg\’]]
df[\’mpg_z\’] = (x – x.mean())/x.std()
df[\’colors\’] = [\’red\’ if x < 0 else \’green\’ for x in df[\’mpg_z\’]]
df.sort_values(\’mpg_z\’, inplace=True)
df.reset_index(inplace=True)
# Draw plot
plt.figure(figsize=(14,10), dpi= 80)
plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z, color=df.colors, alpha=0.4, linewidth=5)
# Decorations
plt.gca().set(ylabel=\’$Model$\’, xlabel=\’$Mileage$\’)
plt.yticks(df.index, df.cars, fontsize=12)
plt.title(\’Diverging Bars of Car Mileage\’, fontdict={\’size\’:20})
plt.grid(linestyle=\’–\’, alpha=0.5)
plt.show()

图10
13. 发散型文本 (Diverging Texts)
发散型文本 (Diverging Texts)与发散型条形图 (Diverging Bars)相似,如果你想以一种漂亮和可呈现的方式显示图表中每个项目的价值,就可以使用这种方法。
# Prepare Data
df = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/mtcars.csv\”)
x = df.loc[:, [\’mpg\’]]
df[\’mpg_z\’] = (x – x.mean())/x.std()
df[\’colors\’] = [\’red\’ if x < 0 else \’green\’ for x in df[\’mpg_z\’]]
df.sort_values(\’mpg_z\’, inplace=True)
df.reset_index(inplace=True)
# Draw plot
plt.figure(figsize=(14,14), dpi= 80)
plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z)
for x, y, tex in zip(df.mpg_z, df.index, df.mpg_z):
t = plt.text(x, y, round(tex, 2), horizontalalignment=\’right\’ if x < 0 else \’left\’,
verticalalignment=\’center\’, fontdict={\’color\’:\’red\’ if x < 0 else \’green\’, \’size\’:14})
# Decorations
plt.yticks(df.index, df.cars, fontsize=12)
plt.title(\’Diverging Text Bars of Car Mileage\’, fontdict={\’size\’:20})
plt.grid(linestyle=\’–\’, alpha=0.5)
plt.xlim(-2.5, 2.5)
plt.show()

图11
14. 发散型包点图 (Diverging Dot Plot)
发散型包点图 (Diverging Dot Plot)也类似于发散型条形图 (Diverging Bars)。 然而,与发散型条形图 (Diverging Bars)相比,条的缺失减少了组之间的对比度和差异。
# Prepare Data
df = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/mtcars.csv\”)
x = df.loc[:, [\’mpg\’]]
df[\’mpg_z\’] = (x – x.mean())/x.std()
df[\’colors\’] = [\’red\’ if x < 0 else \’darkgreen\’ for x in df[\’mpg_z\’]]
df.sort_values(\’mpg_z\’, inplace=True)
df.reset_index(inplace=True)
# Draw plot
plt.figure(figsize=(14,16), dpi= 80)
plt.scatter(df.mpg_z, df.index, s=450, alpha=.6, color=df.colors)
for x, y, tex in zip(df.mpg_z, df.index, df.mpg_z):
t = plt.text(x, y, round(tex, 1), horizontalalignment=\’center\’,
verticalalignment=\’center\’, fontdict={\’color\’:\’white\’})
# Decorations
# Lighten borders
plt.gca().spines[\”top\”].set_alpha(.3)
plt.gca().spines[\”bottom\”].set_alpha(.3)
plt.gca().spines[\”right\”].set_alpha(.3)
plt.gca().spines[\”left\”].set_alpha(.3)
plt.yticks(df.index, df.cars)
plt.title(\’Diverging Dotplot of Car Mileage\’, fontdict={\’size\’:20})
plt.xlabel(\’$Mileage$\’)
plt.grid(linestyle=\’–\’, alpha=0.5)
plt.xlim(-2.5, 2.5)
plt.show()

图12
15. 带标记的发散型棒棒糖图 (Diverging Lollipop Chart with Markers)
带标记的棒棒糖图通过强调您想要引起注意的任何重要数据点并在图表中适当地给出推理,提供了一种对差异进行可视化的灵活方式。
# Prepare Data
df = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/mtcars.csv\”)
x = df.loc[:, [\’mpg\’]]
df[\’mpg_z\’] = (x – x.mean())/x.std()
df[\’colors\’] = \’black\’
# color fiat differently
df.loc[df.cars == \’Fiat X1-9\’, \’colors\’] = \’darkorange\’
df.sort_values(\’mpg_z\’, inplace=True)
df.reset_index(inplace=True)
# Draw plot
import matplotlib.patches as patches
plt.figure(figsize=(14,16), dpi= 80)
plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z, color=df.colors, alpha=0.4, linewidth=1)
plt.scatter(df.mpg_z, df.index, color=df.colors, s=[600 if x == \’Fiat X1-9\’ else 300 for x in df.cars], alpha=0.6)
plt.yticks(df.index, df.cars)
plt.xticks(fontsize=12)
# Annotate
plt.annotate(\’Mercedes Models\’, xy=(0.0, 11.0), xytext=(1.0, 11), xycoords=\’data\’,
fontsize=15, ha=\’center\’, va=\’center\’,
bbox=dict(boxstyle=\’square\’, fc=\’firebrick\’),
arrowprops=dict(arrowstyle=\’-[, widthB=2.0, lengthB=1.5\’, lw=2.0, color=\’steelblue\’), color=\’white\’)
# Add Patches
p1 = patches.Rectangle((-2.0, -1), width=.3, height=3, alpha=.2, facecolor=\’red\’)
p2 = patches.Rectangle((1.5, 27), width=.8, height=5, alpha=.2, facecolor=\’green\’)
plt.gca().add_patch(p1)
plt.gca().add_patch(p2)
# Decorate
plt.title(\’Diverging Bars of Car Mileage\’, fontdict={\’size\’:20})
plt.grid(linestyle=\’–\’, alpha=0.5)
plt.show()

图13
16. 面积图 (Area Chart)
通过对轴和线之间的区域进行着色,面积图不仅强调峰和谷,而且还强调高点和低点的持续时间。 高点持续时间越长,线下面积越大。
import numpy as np
import pandas as pd
# Prepare Data
df = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/economics.csv\”, parse_dates=[\’date\’]).head(100)
x = np.arange(df.shape[0])
y_returns = (df.psavert.diff().fillna(0)/df.psavert.shift(1)).fillna(0) * 100
# Plot
plt.figure(figsize=(16,10), dpi= 80)
plt.fill_between(x[1:], y_returns[1:], 0, where=y_returns[1:] >= 0, facecolor=\’green\’, interpolate=True, alpha=0.7)
plt.fill_between(x[1:], y_returns[1:], 0, where=y_returns[1:] <= 0, facecolor=\’red\’, interpolate=True, alpha=0.7)
# Annotate
plt.annotate(\’Peak \\n1975\’, xy=(94.0, 21.0), xytext=(88.0, 28),
bbox=dict(boxstyle=\’square\’, fc=\’firebrick\’),
arrowprops=dict(facecolor=\’steelblue\’, shrink=0.05), fontsize=15, color=\’white\’)
# Decorations
xtickvals = [str(m)[:3].upper()+\”-\”+str(y) for y,m in zip(df.date.dt.year, df.date.dt.month_name())]
plt.gca().set_xticks(x[::6])
plt.gca().set_xticklabels(xtickvals[::6], rotation=90, fontdict={\’horizontalalignment\’: \’center\’, \’verticalalignment\’: \’center_baseline\’})
plt.ylim(-35,35)
plt.xlim(1,100)
plt.title(\”Month Economics Return %\”, fontsize=22)
plt.ylabel(\’Monthly returns %\’)
plt.grid(alpha=0.5)
plt.show()

图14
三、排序 (Ranking)
17. 有序条形图 (Ordered Bar Chart)
有序条形图有效地传达了项目的排名顺序。 但是,在图表上方添加度量标准的值,用户可以从图表本身获取精确信息。
# Prepare Data
df_raw = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv\”)
df = df_raw[[\’cty\’, \’manufacturer\’]].groupby(\’manufacturer\’).apply(lambda x: x.mean())
df.sort_values(\’cty\’, inplace=True)
df.reset_index(inplace=True)
# Draw plot
import matplotlib.patches as patches
fig, ax = plt.subplots(figsize=(16,10), facecolor=\’white\’, dpi= 80)
ax.vlines(x=df.index, ymin=0, ymax=df.cty, color=\’firebrick\’, alpha=0.7, linewidth=20)
# Annotate Text
for i, cty in enumerate(df.cty):
ax.text(i, cty+0.5, round(cty, 1), horizontalalignment=\’center\’)
# Title, Label, Ticks and Ylim
ax.set_title(\’Bar Chart for Highway Mileage\’, fontdict={\’size\’:22})
ax.set(ylabel=\’Miles Per Gallon\’, ylim=(0, 30))
plt.xticks(df.index, df.manufacturer.str.upper(), rotation=60, horizontalalignment=\’right\’, fontsize=12)
# Add patches to color the X axis labels
p1 = patches.Rectangle((.57, -0.005), width=.33, height=.13, alpha=.1, facecolor=\’green\’, transform=fig.transFigure)
p2 = patches.Rectangle((.124, -0.005), width=.446, height=.13, alpha=.1, facecolor=\’red\’, transform=fig.transFigure)
fig.add_artist(p1)
fig.add_artist(p2)
plt.show()

图15
18. 棒棒糖图 (Lollipop Chart)
棒棒糖图表以一种视觉上令人愉悦的方式提供与有序条形图类似的目的。
# Prepare Data
df_raw = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv\”)
df = df_raw[[\’cty\’, \’manufacturer\’]].groupby(\’manufacturer\’).apply(lambda x: x.mean())
df.sort_values(\’cty\’, inplace=True)
df.reset_index(inplace=True)
# Draw plot
fig, ax = plt.subplots(figsize=(16,10), dpi= 80)
ax.vlines(x=df.index, ymin=0, ymax=df.cty, color=\’firebrick\’, alpha=0.7, linewidth=2)
ax.scatter(x=df.index, y=df.cty, s=75, color=\’firebrick\’, alpha=0.7)
# Title, Label, Ticks and Ylim
ax.set_title(\’Lollipop Chart for Highway Mileage\’, fontdict={\’size\’:22})
ax.set_ylabel(\’Miles Per Gallon\’)
ax.set_xticks(df.index)
ax.set_xticklabels(df.manufacturer.str.upper(), rotation=60, fontdict={\’horizontalalignment\’: \’right\’, \’size\’:12})
ax.set_ylim(0, 30)
# Annotate
for row in df.itertuples():
ax.text(row.Index, row.cty+.5, s=round(row.cty, 2), horizontalalignment= \’center\’, verticalalignment=\’bottom\’, fontsize=14)
plt.show()

图16
19. 包点图 (Dot Plot)
包点图表传达了项目的排名顺序,并且由于它沿水平轴对齐,因此您可以更容易地看到点彼此之间的距离。
# Prepare Data
df_raw = pd.read_csv(\”https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv\”)
df = df_raw[[\’cty\’, \’manufacturer\’]].groupby(\’manufacturer\’).apply(lambda x: x.mean())
df.sort_values(\’cty\’, inplace=True)
df.reset_index(inplace=True)
# Draw plot
fig, ax = plt.subplots(figsize=(16,10), dpi= 80)
ax.hlines(y=df.index, xmin=11, xmax=26, color=\’gray\’, alpha=0.7, linewidth=1, linestyles=\’dashdot\’)
ax.scatter(y=df.index, x=df.cty, s=75, color=\’firebrick\’, alpha=0.7)
# Title, Label, Ticks and Ylim
ax.set_title(\’Dot Plot for Highway Mileage\’, fontdict={\’size\’:22})
ax.set_xlabel(\’Miles Per Gallon\’)
ax.set_yticks(df.index)
ax.set_yticklabels(df.manufacturer.str.title(), fontdict={\’horizontalalignment\’: \’right\’})
ax.set_xlim(10, 27)
plt.show()

图17
20. 坡度图 (Slope Chart)
坡度图最适合比较给定人/项目的“前”和“后”位置。
import matplotlib.lines as mlines
# Import Data
df = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/gdppercap.csv\”)
left_label = [str(c) + \’, \’+ str(round(y)) for c, y in zip(df.continent, df[\’1952\’])]
right_label = [str(c) + \’, \’+ str(round(y)) for c, y in zip(df.continent, df[\’1957\’])]
klass = [\’red\’ if (y1-y2) < 0 else \’green\’ for y1, y2 in zip(df[\’1952\’], df[\’1957\’])]
# draw line
# https://stackoverflow.com/questions/36470343/how-to-draw-a-line-with-matplotlib/36479941
def newline(p1, p2, color=\’black\’):
ax = plt.gca()
l = mlines.Line2D([p1[0],p2[0]], [p1[1],p2[1]], color=\’red\’ if p1[1]-p2[1] > 0 else \’green\’, marker=\’o\’, markersize=6)
ax.add_line(l)
return l
fig, ax = plt.subplots(1,1,figsize=(14,14), dpi= 80)
# Vertical Lines
ax.vlines(x=1, ymin=500, ymax=13000, color=\’black\’, alpha=0.7, linewidth=1, linestyles=\’dotted\’)
ax.vlines(x=3, ymin=500, ymax=13000, color=\’black\’, alpha=0.7, linewidth=1, linestyles=\’dotted\’)
# Points
ax.scatter(y=df[\’1952\’], x=np.repeat(1, df.shape[0]), s=10, color=\’black\’, alpha=0.7)
ax.scatter(y=df[\’1957\’], x=np.repeat(3, df.shape[0]), s=10, color=\’black\’, alpha=0.7)
# Line Segmentsand Annotation
for p1, p2, c in zip(df[\’1952\’], df[\’1957\’], df[\’continent\’]):
newline([1,p1], [3,p2])
ax.text(1-0.05, p1, c + \’, \’ + str(round(p1)), horizontalalignment=\’right\’, verticalalignment=\’center\’, fontdict={\’size\’:14})
ax.text(3+0.05, p2, c + \’, \’ + str(round(p2)), horizontalalignment=\’left\’, verticalalignment=\’center\’, fontdict={\’size\’:14})
# \’Before\’ and \’After\’ Annotations
ax.text(1-0.05, 13000, \’BEFORE\’, horizontalalignment=\’right\’, verticalalignment=\’center\’, fontdict={\’size\’:18, \’weight\’:700})
ax.text(3+0.05, 13000, \’AFTER\’, horizontalalignment=\’left\’, verticalalignment=\’center\’, fontdict={\’size\’:18, \’weight\’:700})
# Decoration
ax.set_title(\”Slopechart: Comparing GDP Per Capita between 1952 vs 1957\”, fontdict={\’size\’:22})
ax.set(xlim=(0,4), ylim=(0,14000), ylabel=\’Mean GDP Per Capita\’)
ax.set_xticks([1,3])
ax.set_xticklabels([\”1952\”, \”1957\”])
plt.yticks(np.arange(500, 13000, 2000), fontsize=12)
# Lighten borders
plt.gca().spines[\”top\”].set_alpha(.0)
plt.gca().spines[\”bottom\”].set_alpha(.0)
plt.gca().spines[\”right\”].set_alpha(.0)
plt.gca().spines[\”left\”].set_alpha(.0)
plt.show()

图18
21. 哑铃图 (Dumbbell Plot)
哑铃图表传达了各种项目的“前”和“后”位置以及项目的等级排序。 如果您想要将特定项目/计划对不同对象的影响可视化,那么它非常有用。
import matplotlib.lines as mlines
# Import Data
df = pd.read_csv(\”https://raw.githubusercontent.com/selva86/datasets/master/health.csv\”)
df.sort_values(\’pct_2014\’, inplace=True)
df.reset_index(inplace=True)
# Func to draw line segment
def newline(p1, p2, color=\’black\’):
ax = plt.gca()
l = mlines.Line2D([p1[0],p2[0]], [p1[1],p2[1]], color=\’skyblue\’)
ax.add_line(l)
return l
# Figure and Axes
fig, ax = plt.subplots(1,1,figsize=(14,14), facecolor=\’#f7f7f7\’, dpi= 80)
# Vertical Lines
ax.vlines(x=.05, ymin=0, ymax=26, color=\’black\’, alpha=1, linewidth=1, linestyles=\’dotted\’)
ax.vlines(x=.10, ymin=0, ymax=26, color=\’black\’, alpha=1, linewidth=1, linestyles=\’dotted\’)
ax.vlines(x=.15, ymin=0, ymax=26, color=\’black\’, alpha=1, linewidth=1, linestyles=\’dotted\’)
ax.vlines(x=.20, ymin=0, ymax=26, color=\’black\’, alpha=1, linewidth=1, linestyles=\’dotted\’)
# Points
ax.scatter(y=df[\’index\’], x=df[\’pct_2013\’], s=50, color=\’#0e668b\’, alpha=0.7)
ax.scatter(y=df[\’index\’], x=df[\’pct_2014\’], s=50, color=\’#a3c4dc\’, alpha=0.7)
# Line Segments
for i, p1, p2 in zip(df[\’index\’], df[\’pct_2013\’], df[\’pct_2014\’]):
newline([p1, i], [p2, i])
# Decoration
ax.set_facecolor(\’#f7f7f7\’)
ax.set_title(\”Dumbell Chart: Pct Change – 2013 vs 2014\”, fontdict={\’size\’:22})
ax.set(xlim=(0,.25), ylim=(-1, 27), ylabel=\’Mean GDP Per Capita\’)
ax.set_xticks([.05, .1, .15, .20])
ax.set_xticklabels([\’5%\’, \’15%\’, \’20%\’, \’25%\’])
ax.set_xticklabels([\’5%\’, \’15%\’, \’20%\’, \’25%\’])
plt.show()

图19
22. 凸点图 (Bump Chart)
专门用于展示排名随时间的变化。它可以清晰地看到某个项目在多个时间节点中“名次”的起伏,而不是数值。
import pandas as pd
# Data: Team rankings over 4 weeks
data = {
\’Team A\’: [1, 2, 2, 1],
\’Team B\’: [2, 1, 3, 2],
\’Team C\’: [3, 3, 1, 3]
}
df = pd.DataFrame(data, index=[\’Week 1\’, \’Week 2\’, \’Week 3\’, \’Week 4\’])
plt.figure(figsize=(10, 6))
for column in df.columns:
plt.plot(df.index, df[column], marker=\’o\’, lw=3, label=column)
plt.gca().invert_yaxis() # 排名第一在最上方
plt.title(\’Team Rankings Over Time (Bump Chart)\’, fontsize=18)
plt.yticks([1, 2, 3])
plt.legend()
plt.grid(axis=\’x\’, linestyle=\’–\’, alpha=0.6)
plt.show()

23. 帕累托图 (Pareto Chart)
质量管理 80/20 原则的经典图表。结合了条形图(频数)和折线图(累计百分比)。
data = {\’Issue A\’: 50, \’Issue B\’: 30, \’Issue C\’: 15, \’Issue D\’: 5}
df = pd.DataFrame(list(data.items()), columns=[\’Problem\’, \’Count\’])
df = df.sort_values(by=\’Count\’, ascending=False)
df[\’cum_percentage\’] = df[\’Count\’].cumsum() / df[\’Count\’].sum() * 100
fig, ax1 = plt.subplots(figsize=(10, 6))
ax1.bar(df.Problem, df.Count, color=\”C0\”)
ax2 = ax1.twinx()
ax2.plot(df.Problem, df.cum_percentage, color=\”C1\”, marker=\”D\”, ms=7)
ax2.set_ylim(0, 110)
plt.title(\’Pareto Chart: 80/20 Rule Analysis\’, fontsize=18)
plt.show()
