在
datawrapper.de
可视化服务中,可以使用“Split-Bars”图;我想使用 matplotlib (或类似的库)在 Python 中重新创建可视化绘图类型(以编程方式)。
我有一个数据集如下:
A B C D
0.52072 0.08571 0.70141 0.01849
0.46156 0.47112 0.92709 0.24230
0.82056 0.07003 0.14328 0.79489
0.64635 0.72227 0.12274 0.06919
0.83555 0.50729 0.65337 0.62428
0.38232 0.19952 0.24025 0.47434
0.97861 0.53296 0.43911 0.40135
0.93070 0.73063 0.06899 0.00429
0.08514 0.98483 0.80090 0.27527
0.93412 0.05890 0.68416 0.81203
0.78269 0.55302 0.30861 0.19934
Split-Bar
中重新创建此 matplotlib
绘图类型?问题描述:结构看起来是表格格式;每个单元格都填充有阴影区域;到给定的填充百分比。轴线被移除。值文本颜色根据背景颜色而变化。值文本位置根据百分比值而变化。
尝试:我尝试过
ax.add_patch(Rectangle(...))
,这似乎是外部“传奇”色块和内部ax
%填充色块的理想选择。
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.patches import Rectangle
import matplotlib.font_manager as font_manager
# Add every font at the specified location
font_dir = ['path/to/AppData/Local/Microsoft/Windows/Fonts/']
for font in font_manager.findSystemFonts(font_dir):
font_manager.fontManager.addfont(font)
from matplotlib.font_manager import findfont, FontProperties
font = findfont(FontProperties(family=['Roboto']))
matplotlib.rcParams['font.family'] = 'sans-serif'
matplotlib.rcParams['font.sans-serif'] = 'Roboto'
def plot_split_bar(data, metrics, categories,
colors=[(0.6431, 0.9412, 1.0),
(0.0, 0.6392, 0.6902),
(0.0, 0.349, 0.3765),
(0.2039, 0.749, 0.8118),
(0.0, 0.4392, 0.4745),
(0.3686, 0.8549, 0.9255),
(0.0, 0.5373, 0.5804)],
precision=2, fig_size=None):
numrows = data.shape[0]
numcols = data.shape[1]
data_max = np.max(data)*1.025
fig, ax = plt.subplots()
if fig_size:
fig.set_size_inches(fig_size)
# Set labels and ticks
ax.set_xticks(np.arange(len(categories))-0.14)
ax.set_xticklabels(categories, fontsize=8, fontname='Roboto', ha='left', va='center', y=1.001, weight='bold')
ax.xaxis.tick_top()
ax.xaxis.set_ticks_position('none')
ax.set_yticks(np.arange(len(metrics))+0.26)
ax.set_yticklabels(metrics, fontsize=7, fontname='Roboto', x=0.025, ha='right')
ax.spines[['right', 'top','bottom','left']].set_visible(False)
# Add text annotation
for i in range(len(data)):
for j in range(len(data[i])):
perc = data[i][j]/data_max
ax.add_patch(Rectangle((j-.29, i-.25), perc, 0.95,
facecolor = colors[j],
alpha=1,
fill=True,
))
text_pos = (j-0.26)+perc if perc < 0.5 else (j-(0.26)+.1)
text_col = '#333' if perc < 0.5 else 'white'
text_col = '#333' if text_col=='white' and np.mean(colors[j])>0.5 else text_col
text_bold = None if perc < 0.5 else 'bold'
text_perc = f'{data[i][j]:,.{precision}f}' if f'{data[i][j]:,.1f}'[-2:]!='.0' else f'{data[i][j]:,.0f}'
ax.text(text_pos, i+.15, text_perc, ha='left', va='center',
fontname='Roboto', color=text_col, fontsize=7, weight=text_bold)
ax.grid(False)
ax.set_ylim(0-0.5, numrows)
ax.set_xlim(0-0.5, numcols)
for j in range(len(categories)):
ax.add_patch(Rectangle((j-0.31, len(data)+.4), 0.15, .7,
facecolor = colors[j],
clip_on=False,
alpha=1,
fill=True,
))
plt.show()
data = pd.DataFrame(arr[1:],columns=arr[0] ).set_index('year').iloc[::-1]
plot_split_bar(data=data.astype(float).to_numpy(),
metrics=data.index.tolist(),
categories=data.columns,
precision=2,
fig_size=(5, 3)
)
cols = 3
data = pd.DataFrame( np.random.rand(5,cols), columns=[chr(65+i) for i in range(cols)]).iloc[::-1]
plot_split_bar(data=data.to_numpy(),
metrics=data.index.tolist(),
categories=data.columns,
precision=2,
fig_size=(5, 1)
)