Două fețe grupate barplots cu Python seaborn

0

Problema

Încerc să deseneze o față-verso grafic similar cu piramida explicat aici și aici. Problema este că trebuie variabile categoriale (masculin/feminin) pe care vreau să le grupați:

import pandas as pd
import seaborn as sns

# data
data = {'species': ['X', 'X', 'Y', 'Y', 'Z', 'Z', 'X', 'X', 'Y', 'Y', 'Z', 'Z'],
        'sex': ['male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female'], 
        'mass (g)': [4000, 3500, 3800, 3200, 5500, 4900, 2500, 2100, 2400, 2000, 4200, 3800],
        'age': ['adult', 'adult', 'adult', 'adult', 'adult', 'adult', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile']}
df = pd.DataFrame(data)

# convert juvenile mass to negative
df.loc[df.age.eq('juvenile'), 'mass (g)'] = df['mass (g)'].mul(-1)

# plot
sns.set_theme(style="whitegrid")
fig, ax = plt.subplots(figsize=(10,5))
sns.barplot(data=df, x='mass (g)', y='species', hue='sex', ci=False, orient='horizontal', dodge=True)
ax.yaxis.tick_right()
ax.yaxis.set_label_position("right")
plt.show()

Figura de mai jos este ceea ce încerc să fac. Diferite bare de culoare sunt de sex masculin/de sex feminin. Specii diferite X, Y, Z sunt separate categoric grupuri. Barele de pe partea dreapta a figurii arată în masă a adulților pentru fiecare specie.

Am schițat în roșu barele de pe partea stângă pentru a arăta masa de puiet pentru fiecare specie. Cum fac acest complot? Eu nu pot găsi ceva util în seaborn docs sau pe ATÂT.

enter image description here

matplotlib pandas plot python
2021-11-23 21:44:10
3

Cel mai bun răspuns

2

Incearca ceva de genul asta:

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# data
data = {'species': ['X', 'X', 'Y', 'Y', 'Z', 'Z', 'X', 'X', 'Y', 'Y', 'Z', 'Z'],
        'sex': ['male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female'], 
        'mass (g)': [4000, 3500, 3800, 3200, 5500, 4900, 2500, 2100, 2400, 2000, 4200, 3800],
        'age': ['adult', 'adult', 'adult', 'adult', 'adult', 'adult', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile']}
df = pd.DataFrame(data)

# convert juvenile mass to negative
df.loc[df.age.eq('juvenile'), 'mass (g)'] = df['mass (g)'].mul(-1)

# plot
sns.set_theme(style="whitegrid")
fig, ax = plt.subplots(figsize=(10,5))
df_reshape = df.set_index(['species','sex','age']).unstack(['age','sex'])['mass (g)']
df_reshape.loc[:, 'adult'].plot.barh(ax=ax)
df_reshape.loc[:, 'juvenile'].plot.barh(legend=False, ax=ax)
plt.show()

Ieșire:

enter image description here


import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# data
data = {'species': ['X', 'X', 'Y', 'Y', 'Z', 'Z', 'X', 'X', 'Y', 'Y', 'Z', 'Z'],
        'sex': ['male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female'], 
        'mass (g)': [4000, 3500, 3800, 3200, 5500, 4900, 2500, 2100, 2400, 2000, 4200, 3800],
        'age': ['adult', 'adult', 'adult', 'adult', 'adult', 'adult', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile']}
df = pd.DataFrame(data)

# convert juvenile mass to negative
df.loc[df.age.eq('juvenile'), 'mass (g)'] = df['mass (g)'].mul(-1)

# plot
sns.set_theme(style="whitegrid")
fig, ax = plt.subplots(figsize=(10,5))
df_reshape = df.set_index(['species','sex','age']).unstack(['age','sex'])['mass (g)']
df_reshape.loc[:, ['adult']].plot.barh(ax=ax, edgecolor='k')
df_reshape.loc[:, ['juvenile']].plot.barh(ax=ax, label='Juvenile', color=['navy','red'], alpha=.6, edgecolor='k', hatch='/')
plt.show()

Ieșire:

enter image description here

2021-11-23 22:18:43
1

Dacă se amestecă valori pozitive și negative, în mod implicit seaborn barplot vor medie-le.

Ai putea desena două barplots spate în spate și invers la stânga:

from matplotlib import pyplot as plt
import seaborn as sns
import pandas as pd

data = {'species': ['X', 'X', 'Y', 'Y', 'Z', 'Z', 'X', 'X', 'Y', 'Y', 'Z', 'Z'],
        'sex': ['male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female'],
        'mass (g)': [4000, 3500, 3800, 3200, 5500, 4900, 2500, 2100, 2400, 2000, 4200, 3800],
        'age': ['adult', 'adult', 'adult', 'adult', 'adult', 'adult', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile']}
df = pd.DataFrame(data)
df['sex'] = pd.Categorical(df['sex'])  # make hue column categorical, forcing a fixed order

sns.set_theme(style='whitegrid')
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 5), sharey=True, gridspec_kw={'wspace': 0})


# draw adult subplot at the right
sns.barplot(data=df[df['age'] == 'adult'], x='mass (g)', y='species', hue='sex',
            ci=False, orient='horizontal', dodge=True, ax=ax2)
ax2.yaxis.set_label_position('right')
ax2.tick_params(axis='y', labelright=True, right=True)
ax2.set_title('  '+'adult', loc='left')
ax2.legend_.remove()  # remove the legend; the legend will be in ax1

# draw juvenile subplot at the left
sns.barplot(data=df[df['age'] == 'juvenile'], x='mass (g)', y='species', hue='sex',
            ci=False, orient='horizontal', dodge=True, ax=ax1)

# optionally use the same scale left and right
xmax = max(ax1.get_xlim()[1], ax2.get_xlim()[1])
ax1.set_xlim(xmax=xmax)
ax2.set_xlim(xmax=xmax)

ax1.invert_xaxis()  # reverse the direction
ax1.tick_params(labelleft=False, left=False)
ax1.set_ylabel('')
ax1.set_title('juvenile'+'  ', loc='right')

plt.tight_layout()
plt.show()

two sns.barplots, back to back

O caracteristică interesantă a seaborn barplots este că se va face, de asemenea, activitatea de determinare a mediei valorilor dat un dataframe cu un rând pentru fiecare individ (și calcula un interval de încredere).

2021-11-23 22:11:31

Pe dezavantaj al acestei abordări este că barele de pe cele doua intr-o parte nu sunt legate la aceeași scară, care pot fi înșelătoare.
Quang Hoang

@johanC pentru un motiv oarecare, sub cod # optionally use the same scale left and right nu are nici un efect (pentru codul meu real, nu MWE în postul meu). de exemplu. barele de pe partea stângă și dreaptă a graficului nu sunt aliniate în mod corespunzător
Medulla Oblongata

multumesc, asta e ceea ce am făcut, dar e inca nealiniate
Medulla Oblongata

da, am copiat codul si mi-a folosit propriul set de date pentru toate comenzile sunt neschimbate. Se pare ca barele de pe graficul din stânga au lățimi mai mari decât pe dreapta - puteți aplica o lățime de bara pentru ambele ax1 și ax2?
Medulla Oblongata

Ai putea edita întrebarea dumneavoastră și de a adăuga o imagine din care teren? Poate acolo sunt mai mult de nuanță valorile disponibile într-un singur vs alt set? Poate specia coloană ar trebui să, de asemenea, în mod explicit fi făcut de categoric? (df['species'] = pd.Categorical(df['species']))
JohanC

S-ar putea posta o întrebare separată pentru acest lucru, vă mulțumim pentru ajutorul tău.
Medulla Oblongata
1

Am folosit `pivot pentru a modela datele corect

import pandas as pd
import seaborn as sns

# data
data = {'species': ['X', 'X', 'Y', 'Y', 'Z', 'Z', 'X', 'X', 'Y', 'Y', 'Z', 'Z'],
        'sex': ['male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female', 'male', 'female'], 
        'mass (g)': [4000, 3500, 3800, 3200, 5500, 4900, 2500, 2100, 2400, 2000, 4200, 3800],
        'age': ['adult', 'adult', 'adult', 'adult', 'adult', 'adult', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile', 'juvenile']}
df = pd.DataFrame(data)

# convert juvenile mass to negative
df.loc[df.age.eq('juvenile'), 'mass (g)'] = df['mass (g)'].mul(-1)

# pivot data
df=df.pivot(columns=['age'], index=['species', 'sex'], values=['mass (g)']).reset_index()
df = df.set_index(['species', 'sex'])['mass (g)'].reset_index()

# plot
sns.set_theme(style="whitegrid")
fig, ax = plt.subplots(figsize=(10,5))
sns.barplot(data=df, x='adult', y='species', hue='sex', ci=False, orient='horizontal', dodge=True)
sns.barplot(data=df, x='juvenile', y='species', hue='sex', ci=False, orient='horizontal', dodge=True)

enter image description here

2021-11-24 00:32:50

În alte limbi

Această pagină este în alte limbi

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................