Plotly:带有下拉菜单的散点图,用于更改数据和计算的注释

Plotly: Scatter plot with dropdown menu to change data and calculated annotation

我正在尝试使用 2 个下拉菜单制作一个散点图,其中 select 一个数据列(来自 pandas 数据框)用于绘制 x 轴和 y 轴。我还希望绘图具有随下拉列表 selection 变化的相关统计注释,因为注释是根据 x 和 y 数据作为参数计算的。第一部分我已经设法用下面的代码示例完成了,但我正在努力处理注释。

import pandas as pd
import numpy as np
import plotly.graph_objects as go

# Prep random data
data = pd.DataFrame(dict(
    A=np.random.randint(11, size=10),
    B=np.random.randint(11, size=10),
    C=np.random.randint(11, size=10),
    D=np.random.randint(11, size=10) 
))

# Create figure and add one scatter trace
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=data['A'], 
    y=data['A'],
    visible=True,
    mode='markers',
    )
              )

# Create x and y buttons
x_buttons = []
y_buttons = []

for column in data.columns:
    x_buttons.append(dict(method='restyle',
                        label=column,
                        args=[{'x': [data[column]]}]
                        )
                )
    
    y_buttons.append(dict(method='restyle',
                        label=column,
                        args=[{'y': [data[column]]}]
                        )
                )

# Pass buttons to the updatemenus argument
fig.update_layout(updatemenus=[dict(buttons=x_buttons, direction='up', x=0.5, y=-0.1),
                               dict(buttons=y_buttons, direction='right', x=-0.01, y=0.5)])

我的想法是首先定义一个函数,它将从 figure data structure (hoping that the dropdown selection change this attributes) and returns the text annotation. Then, based on the plotly reference example 中获取 x 和 y 属性,将注释添加到 args 并将按钮的方法更改为 'update'.但是,情况似乎并非如此,注释是静态的。任何人都知道我如何实现这一目标?这是函数和最终代码:

from scipy import stats

def corr_annotation(x, y):
    pearsonr = stats.pearsonr(x, y)
    return 'r = {:.2f} (p = {:.3f})'.format(pearsonr[0], pearsonr[1])
import pandas as pd
import numpy as np
import plotly.graph_objects as go

# Prep random data
data = pd.DataFrame(dict(
    A=np.random.randint(11, size=10),
    B=np.random.randint(11, size=10),
    C=np.random.randint(11, size=10),
    D=np.random.randint(11, size=10) 
))

# Create figure and add one scatter trace
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=data['A'], 
    y=data['A'],
    visible=True,
    mode='markers',
    )
              )

fig.add_annotation(dict(text=corr_annotation(fig['data'][0]['x'], fig['data'][0]['y']),
                        showarrow=False, 
                        yref='paper', xref='paper',
                        x=0.99, y=0.95))

# Create x and y buttons
x_buttons = []
y_buttons = []

for column in data.columns:
    x_buttons.append(dict(method='update',
                        label=column,
                        args=[{'x': [data[column]]},
                              {'annotations': [dict(text=corr_annotation(fig['data'][0]['x'], fig['data'][0]['y']),
                                                    showarrow=False, 
                                                    yref='paper', xref='paper',
                                                    x=0.99, y=0.95)]}]
                        )
                )
    
    y_buttons.append(dict(method='update',
                        label=column,
                        args=[{'y': [data[column]]},
                              {'annotations': [dict(text=corr_annotation(fig['data'][0]['x'], fig['data'][0]['y']),
                                                    showarrow=False, 
                                                    yref='paper', xref='paper',
                                                    x=0.99, y=0.95)]}]
                        )
                )

# Pass buttons to the updatemenus argument
fig.update_layout(updatemenus=[dict(buttons=x_buttons, direction='up', x=0.5, y=-0.1),
                               dict(buttons=y_buttons, direction='right', x=-0.01, y=0.5)])

And the final result

由于我们需要为它们中的每一个创建注释,因此我们将按 ABCD 顺序和 DCBA 顺序为 x,y 组合创建 x 轴和 y 轴的注释。我们有相同的R值,但我们没有验证过,所以请自行处理。

from scipy import stats

def corr_annotation(x, y):
    pearsonr = stats.pearsonr(x, y)
    return 'r = {:.2f} (p = {:.3f})'.format(pearsonr[0], pearsonr[1])

import pandas as pd
import numpy as np
import plotly.graph_objects as go

# Prep random data
data = pd.DataFrame(dict(
    A=np.random.randint(11, size=10),
    B=np.random.randint(11, size=10),
    C=np.random.randint(11, size=10),
    D=np.random.randint(11, size=10) 
))

# Create figure and add one scatter trace
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=data['A'], 
    y=data['A'],
    visible=True,
    mode='markers',
    )
              )

fig.add_annotation(dict(text=corr_annotation(fig['data'][0]['x'], fig['data'][0]['y']),
                        showarrow=False, 
                        yref='paper', xref='paper',
                        x=0.99, y=0.95))

# Create x and y buttons
x_buttons = []
y_buttons = []

for ncol,rcol in zip(data.columns, data.columns[::-1]):
    x_buttons.append(dict(method='update',
                        label=ncol,
                        args=[{'x': [data[ncol]]},
                              {'annotations': [dict(text=corr_annotation(data[ncol], data[rcol]),
                                                    showarrow=False, 
                                                    yref='paper', xref='paper',
                                                    x=0.99, y=0.95)]}]
                        )
                )
    
    y_buttons.append(dict(method='update',
                        label=ncol,
                        args=[{'y': [data[ncol]]},
                              {'annotations': [dict(text=corr_annotation(data[rcol], data[ncol]),
                                                    showarrow=False, 
                                                    yref='paper', xref='paper',
                                                    x=0.99, y=0.95)]}]
                        )
                )

# Pass buttons to the updatemenus argument
fig.update_layout(updatemenus=[dict(buttons=x_buttons, direction='up', x=0.5, y=-0.1),
                               dict(buttons=y_buttons, direction='right', x=-0.01, y=0.5)])

fig.show()

我的解决方案是更改为 select 对变量(即同时更改 x 和 y)的单个下拉按钮。对此的一个警告是在处理大型数据集时,因为组合的数量可能会变得非常大,但对于我的情况(~20 列)它很好。

from scipy import stats

def corr_annotation(x, y):
    pearsonr = stats.pearsonr(x, y)
    return 'r = {:.2f} (p = {:.3f})'.format(pearsonr[0], pearsonr[1])

# Prep random data
import pandas as pd
import numpy as np

np.random.seed(12)

data = pd.DataFrame(dict(
    A=np.random.randint(11, size=10),
    B=np.random.randint(11, size=10),
    C=np.random.randint(11, size=10),
    D=np.random.randint(11, size=10) 
))

# Create base figure
import plotly.express as px

fig = px.scatter(data, x='A', y='B')

fig.add_annotation(dict(text=corr_annotation(data['A'], data['B']),
                        showarrow=False, 
                        yref='paper', xref='paper',
                        x=0.99, y=0.95))

# Create buttons
import itertools

buttons = []

for x, y in itertools.combinations(data.columns, 2):
    buttons.append(dict(method='update',
                        label='{} x {}'.format(x, y),
                        args=[{'x': [data[x]],
                               'y': [data[y]]},
                              {'xaxis': {'title': x},
                               'yaxis': {'title': y},
                               'annotations': [dict(text=corr_annotation(data[x], data[y]),
                                                    showarrow=False, 
                                                    yref='paper', xref='paper',
                                                    x=0.99, y=0.95)]}]
                        )
                   )

# Update and show figure
fig.update_layout(updatemenus=[dict(buttons=buttons, direction='down', x=0.1, y=1.15)])

fig.show()