简体   繁体   中英

How do I superimpose strip plots over bar charts in plotly?

What I would like to do: I have a set of data organized by genotype along a categorical x axis. I would like to plot the population means with associated error bars set as standard errors of the mean in a pretty standard bar chart. I would also like to have, superimposed over my bar chart, each of the mean scores of the individual animals in my population as a strip plot (or scatter plot, I'm not picky). I can get this to work if I have a single set of named categorical axes on the x axis, but what I would really like to do is have two paired traces each attached to the x axes.

The dataframe looks like this:

>>> rotDF
          ID  Day   Genotype      Dose    Direction  Rotations
0     apple1    1        Del      Sal     Left       1
1     apple2    1         WT      Sal     Left       1
2     apple3    1         WT      Sal     Left       1
3     apple4    1        Del      Sal     Left       14
4    cherry1    1        Del      Sal     Left       3

Here's an example of the two things I want to combine. First, the ideal format of each trace of the bar graph would look like this:

First, I would like the bar charts to have their associated stripcharts superimposed over each of the bar traces.

Second, I would like each xaxis category to have the two color-coded traces organized around each ticklabel on the bottom, as in this bar chart.

Here's what I currently have. The bars look fine, but both sets of traces from the strip charts are clustered together at the middle, instead of being imposed over each of the bars for the respective trait. I have considered trying to color-code each data piece by genotype, which you can see in this version, but the dots cluster at the center rather than clustering alongside their assigned bar traces.

And here's what I want to achieve. This figure was created in inkscape using transparent copies of the strip plots superimposed on the relevant bar plots. It's not ideal, but it worked for last conference--but I would really love to see something better.

The target result can be obtained by first creating a strip plot, then adding the bar chart:

import pandas as pd
import numpy as np

import plotly
import plotly.express as px
import plotly.graph_objects as go

dose_lst = ['Sal', 'Amph 0.3', 'Amph 1', 'Amph 3']  # shortened for demonstration

# generating a dummy dataset
length = 100
data = {
    'ID': np.random.choice(['apple1', 'apple2', 'apple3', 'cherry1'], length),
    'Day': np.random.randint(1, 10, length),
    'Geno': np.random.choice(['DEL', 'WT'], length),
    'Dose': np.random.choice(dose_lst , length),
    'Rotations': np.random.randint(1, 20, length),
}
df = pd.DataFrame(data)

# some data preparation
# mean and std of 'Geno','Dose'-groups
df_WT = df.loc[df['Geno']=='WT']
df_WT = df_WT.groupby(['Geno','Dose'], as_index=False).agg({'Rotations':['mean', 'std']})
df_WT.sort_values(by='Dose', key=lambda column: column.map(lambda e: dose_lst.index(e)), inplace=True)
df_DEL = df.loc[df['Geno']=='DEL']
df_DEL = df_DEL.groupby(['Geno','Dose'], as_index=False).agg({'Rotations':['mean', 'std']})
df_DEL.sort_values(by='Dose', key=lambda column: column.map(lambda e: dose_lst.index(e)), inplace=True)
# mean of 'ID' column values (?)
df_mean = df.groupby(['ID', 'Geno','Dose'], as_index=False)[['Rotations']].mean()

# plot
fig = px.strip(
    data_frame=df,
    x='Dose',
    y='Rotations',
    category_orders={'Dose':['Sal', 'Amph 0.3', 'Amph 1', 'Amph 3'], 'Geno': ['WT', 'DEL']},
    color='Geno',
    color_discrete_map={'WT':'rgba(40,68,167,0.8)' ,'DEL':'rgba(166,184,248,0.8)'},
    orientation='v', 
    stripmode='group',
)
fig.add_trace(go.Bar(
    name='WT',
    x=dose_lst, y=df_WT.Rotations.values[:, 0],
    error_y=dict(type='data', array=df_WT.Rotations.values[:, 1]),
    marker={'color': 'rgba(40,68,167,0.8)'},
    showlegend=False
))
fig.add_trace(go.Bar(
    name='DEL',
    x=dose_lst, y=df_DEL.Rotations.values[:, 0],
    error_y=dict(type='data', array=df_DEL.Rotations.values[:, 1]),
    marker={'color': 'rgba(166,184,248,0.8)'},
    showlegend=False
))
fig.update_layout(title_text='Mean distance traveled per dose', title_x=0.5, template='simple_white')
fig.show()

结果是组合条形图和条形图

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM