Как аннотировать сгруппированные столбцы в фасетной сетке с помощью пользовательских строк

Мой морской сюжет показан ниже. Есть ли способ добавить информацию в столбец flag (который всегда будет одним символом или пустой строкой) в центре (или вверху) полос? Надеясь, что есть ответ, который также не потребует переделки сюжета.

В этом ответе, кажется, есть некоторые указатели, но я не уверен, как подключить его обратно к исходному фрейму данных, чтобы получить информацию в столбце flag.

import matplotlib.pyplot as plt
import seaborn as sns

df = pd.DataFrame([
    ['C', 'G1', 'gbt',    'auc', 0.7999, "†"],
    ['C', 'G1', 'gbtv2',  'auc', 0.8199, "*"],
    ['C', 'G1', 'gbt',  'pr@2%', 0.0883, "*"],
    ['C', 'G1', 'gbt', 'pr@10%', 0.0430,  ""],
    ['C', 'G2', 'gbt',    'auc', 0.7554,  ""],
    ['C', 'G2', 'gbt',  'pr@2%', 0.0842,  ""],
    ['C', 'G2', 'gbt', 'pr@10%', 0.0572,  ""],
    ['C', 'G3', 'gbt',    'auc', 0.7442,  ""],
    ['C', 'G3', 'gbt',  'pr@2%', 0.0894,  ""],
    ['C', 'G3', 'gbt', 'pr@10%', 0.0736,  ""],
    ['E', 'G1', 'gbt',    'auc', 0.7988,  ""],
    ['E', 'G1', 'gbt',  'pr@2%', 0.0810,  ""],
    ['E', 'G1', 'gbt', 'pr@10%', 0.0354,  ""],
    ['E', 'G1', 'gbtv3','pr@10%',0.0454,  ""],
    ['E', 'G2', 'gbt',    'auc', 0.7296,  ""],
    ['E', 'G2', 'gbt',  'pr@2%', 0.1071,  ""],
    ['E', 'G2', 'gbt', 'pr@10%', 0.0528,  "†"],
    ['E', 'G3', 'gbt',    'auc', 0.6958,  ""],
    ['E', 'G3', 'gbt',  'pr@2%', 0.1007,  ""],
    ['E', 'G3', 'gbt', 'pr@10%', 0.0536,  "†"],
  ], columns=["src","grp","model","metric","val","flag"])

cat = sns.catplot(data=df, x = "grp", y = "val", hue = "model", kind = "bar", sharey=False, 
            col = "metric", row = "src")
plt.show()
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
115
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  • Проблема в том, что для каждого axes и каждого container в заданном axes должны быть выбраны соответствующие данные. Например:
    • Первый facet содержит src = C и metric = auc, а facet состоит из 3 контейнеров, соответствующих уникальным значениям 'model'.
  • Параметр label= в .bar_label ожидает list с таким же количеством значений, сколько делений на оси x, даже если в этом пространстве нет полосы.
    • Понимание списка labels = [...] помещает соответствующую метку в правильный индекс и заполняет отсутствующие метки ''.
  • Протестировано в python 3.11.2, pandas 2.0.0, matplotlib 3.7.1, seaborn 0.12.2
import pandas as pd
import seaborn as sns
import numpy as np

# plot the dataframe from the OP
g = sns.catplot(data=df, x = "grp", y = "val", hue = "model", kind = "bar", sharey=False, col = "metric", row = "src")

# get the unique values from the grp column, which corresponds to the x-axis tick labels
grp_unique = df.grp.unique()

# iterate through axes
for ax in g.axes.flat:
    
    # get the components of the title to filter the current data
    src, metric = [s.split(' = ')[1] for s in ax.get_title().split(' | ')]
    
    # iterate through the containers of the current axes
    for c in ax.containers:
        
        # get the hue label of the current container
        model = c.get_label()
        
        # filter the corresponding data
        data = df.loc[df.src.eq(src) & df.metric.eq(metric) & df.model.eq(model)]
        
        # if the DataFrame, data, isn't empty (e.g. there are bars for the current model
        if not data.empty:
            
            # for each grp on the x-axis, get the corresponding bar height (value, nan, 0)
            # this is to show the corresponding data and labels - this can be removed
            gh = {grp: (h := v.get_height(), data.loc[data.grp.eq(grp), 'flag'].tolist()[0] if not np.isnan(h) else '') for v, grp in zip(c, grp_unique)}

            # custom labels from the flag column
            labels = [data.loc[data.grp.eq(grp), 'flag'].tolist()[0] if not np.isnan(v.get_height()) else '' for v, grp in zip(c, grp_unique)]

            # shows the different data being used - can be removed
            print(src, metric, model)
            display(data)
            print(gh)
            print(labels)
            print('\n')
            
            # add the labels
            ax.bar_label(c, labels=labels, label_type='edge')
    ax.margins(y=0.2)

Печатный вывод

C auc gbt
|    | src   | grp   | model   | metric   |    val | flag   |
|---:|:------|:------|:--------|:---------|-------:|:-------|
|  0 | C     | G1    | gbt     | auc      | 0.7999 | †      |
|  4 | C     | G2    | gbt     | auc      | 0.7554 |        |
|  7 | C     | G3    | gbt     | auc      | 0.7442 |        |
{'G1': (0.7999, '†'), 'G2': (0.7554, ''), 'G3': (0.7442, '')}
['†', '', '']


C auc gbtv2
|    | src   | grp   | model   | metric   |    val | flag   |
|---:|:------|:------|:--------|:---------|-------:|:-------|
|  1 | C     | G1    | gbtv2   | auc      | 0.8199 | *      |
{'G1': (0.8199, '*'), 'G2': (nan, ''), 'G3': (nan, '')}
['*', '', '']


C pr@2% gbt
|    | src   | grp   | model   | metric   |    val | flag   |
|---:|:------|:------|:--------|:---------|-------:|:-------|
|  2 | C     | G1    | gbt     | pr@2%    | 0.0883 | *      |
|  5 | C     | G2    | gbt     | pr@2%    | 0.0842 |        |
|  8 | C     | G3    | gbt     | pr@2%    | 0.0894 |        |
{'G1': (0.0883, '*'), 'G2': (0.0842, ''), 'G3': (0.0894, '')}
['*', '', '']


C pr@10% gbt
|    | src   | grp   | model   | metric   |    val | flag   |
|---:|:------|:------|:--------|:---------|-------:|:-------|
|  3 | C     | G1    | gbt     | pr@10%   | 0.043  |        |
|  6 | C     | G2    | gbt     | pr@10%   | 0.0572 |        |
|  9 | C     | G3    | gbt     | pr@10%   | 0.0736 |        |
{'G1': (0.043, ''), 'G2': (0.0572, ''), 'G3': (0.0736, '')}
['', '', '']


E auc gbt
|    | src   | grp   | model   | metric   |    val | flag   |
|---:|:------|:------|:--------|:---------|-------:|:-------|
| 10 | E     | G1    | gbt     | auc      | 0.7988 |        |
| 14 | E     | G2    | gbt     | auc      | 0.7296 |        |
| 17 | E     | G3    | gbt     | auc      | 0.6958 |        |
{'G1': (0.7988, ''), 'G2': (0.7296, ''), 'G3': (0.6958, '')}
['', '', '']


E pr@2% gbt
|    | src   | grp   | model   | metric   |    val | flag   |
|---:|:------|:------|:--------|:---------|-------:|:-------|
| 11 | E     | G1    | gbt     | pr@2%    | 0.081  |        |
| 15 | E     | G2    | gbt     | pr@2%    | 0.1071 |        |
| 18 | E     | G3    | gbt     | pr@2%    | 0.1007 |        |
{'G1': (0.081, ''), 'G2': (0.1071, ''), 'G3': (0.1007, '')}
['', '', '']


E pr@10% gbt
|    | src   | grp   | model   | metric   |    val | flag   |
|---:|:------|:------|:--------|:---------|-------:|:-------|
| 12 | E     | G1    | gbt     | pr@10%   | 0.0354 |        |
| 16 | E     | G2    | gbt     | pr@10%   | 0.0528 | †      |
| 19 | E     | G3    | gbt     | pr@10%   | 0.0536 | †      |
{'G1': (0.0354, ''), 'G2': (0.0528, '†'), 'G3': (0.0536, '†')}
['', '†', '†']


E pr@10% gbtv3
|    | src   | grp   | model   | metric   |    val | flag   |
|---:|:------|:------|:--------|:---------|-------:|:-------|
| 13 | E     | G1    | gbtv3   | pr@10%   | 0.0454 |        |
{'G1': (0.0454, ''), 'G2': (nan, ''), 'G3': (nan, '')}
['', '', '']

Другие вопросы по теме