如何使用 matplotlib 在 Python 中创建“分割条”图?

问题描述 投票:0回答:1

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

我想制作一个情节,例如: enter image description here

如何在
Split-Bar
中重新创建此
matplotlib
绘图类型?


寻找解决方案所采取的步骤:

  • SO上没有找到相关问题。
  • 谷歌搜索不会返回具有此绘图类型的开源代码或库来重现该绘图。
  • 使用生成式人工智能服务未产生正确的输出。
  • 开始寻找解决方案,定义问题并指定解决方案:

问题描述:结构看起来是表格格式;每个单元格都填充有阴影区域;到给定的填充百分比。轴线被移除。值文本颜色根据背景颜色而变化。值文本位置根据百分比值而变化。

尝试:我尝试过

ax.add_patch(Rectangle(...))
,这似乎是外部“传奇”色块和内部
ax
%填充色块的理想选择。

python matplotlib visualization diagram
1个回答
1
投票

图书馆代码:

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)
              )

enter image description here

与伪随机生成的数据一起使用:

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)
              )

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.