与
plotly
交互时,我面临更新 dropdown
散点图上的中线的问题。下拉列表允许用户选择一列(Y 轴),我希望所选 Y 轴的中位数相应更新。但是,当我从下拉列表中选择一个新变量时,中线不会按预期更新。
我分享一个玩具样本数据:
import pandas as pd
df_input = pd.DataFrame({
'rows': range(1, 101),
'column_a': [i + (i % 10) for i in range(1, 101)],
'column_b': [i * 2 for i in range(1, 101)],
'column_c': [i ** 0.5 for i in range(1, 101)],
'outlier_prob': [0.01 * (i % 10) for i in range(1, 101)]
})
这是我使用的功能
import plotly.graph_objects as go
def plot_dq_scatter_dropdown(df):
# Initialize the figure
fig = go.Figure()
# Function to add median lines (vertical for rows, horizontal for selected Y)
def add_median_lines(y):
fig.data = [] # Clear previous data
# Add a scatter trace for the selected Y variable
fig.add_trace(go.Scatter(
x=df["rows"],
y=df[y],
mode='markers',
marker=dict(color=df['outlier_prob'], colorscale='viridis', showscale=True, colorbar=dict(title='Outlier Probability')),
hoverinfo='text',
text=df.index, # Or use other columns for hover data if needed
name=f'{y} vs rows', # This will still be used for the hover and data display
showlegend=False # Hide the legend for each individual trace
))
# Calculate medians for both X and selected Y
median_x = df["rows"].median() # Median of X (rows)
median_y = df[y].median() # Median of selected Y-variable
# Add vertical median line for 'rows'
fig.add_vline(x=median_x, line=dict(color="orange", dash="dash", width=2),
annotation_text="Median rows", annotation_position="top left")
# Add horizontal median line for selected Y-variable
fig.add_hline(y=median_y, line=dict(color="orange", dash="dash", width=2),
annotation_text=f"Median {y}, {median_y}", annotation_position="top left")
# Update layout after adding the data and median lines
fig.update_layout(
title=f"Scatter Plot: rows vs {y}",
xaxis_title="rows",
yaxis_title=y,
autosize=True
)
# Add a dropdown menu for selecting the Y-axis variable
fig.update_layout(
updatemenus=[dict(
type="dropdown",
x=0.17,
y=1.15,
showactive=True,
buttons=[
dict(
label=f"{y}",
method="update",
args=[{
'y': [df[y]],
'x': [df["rows"]],
'type': 'scatter',
'mode': 'markers',
'marker': dict(color=df['outlier_prob'], colorscale='viridis', showscale=True, colorbar=dict(title='Outlier Probability')),
'hoverinfo': 'text',
'text': df.index,
'name': f'{y} vs rows',
'showlegend': False
}, {
'title': f"Scatter Plot: rows vs {y}",
'yaxis.title': y
}]
) for y in df.columns if y not in ["rows", "outlier_prob"]
]
)]
)
# Display the initial plot (default to the second column for the first plot)
add_median_lines(df.columns[1])
# Show the plot
fig.show()
这里是函数调用的例子:
# Call the function to plot the graph
plot_dq_scatter_dropdown(df_input)
这是我在视觉上面临的错误:
以绿色勾勒出的水平轨迹出乎意料地恒定为
column_a
,因为我在下拉列表中与之交互的轨迹是 column_b
。垂直轨迹是正确固定的,因为它不与该轴相互作用。
我使用
shapes
参数而不是 add_vline
和 add_hline
参数修改了函数plot_dq_scatter_dropdown。这是修改后的功能:
def plot_dq_scatter_dropdown(df):
# Initialize the figure
fig = go.Figure()
# Get columns for Y-axis options (excluding 'rows' and 'outlier_prob')
y_columns = [col for col in df.columns if col not in ["rows", "outlier_prob"]]
# Calculate median of rows (constant)
median_x = df["rows"].median()
# Create dropdown buttons with updated configuration
buttons = []
for y_col in y_columns:
median_y = df[y_col].median()
button = dict(
label=y_col,
method="update",
args=[
# Trace updates
{
"y": [df[y_col]], # Update scatter plot Y values
"x": [df["rows"]],
"marker.color": [df["outlier_prob"]],
},
# Layout updates
{
"title": f"Scatter Plot: rows vs {y_col}",
"yaxis.title": y_col,
"shapes": [
# Vertical median line for rows
{
"type": "line",
"x0": median_x,
"x1": median_x,
"y0": 0,
"y1": 1,
"yref": "paper",
"line": {"color": "orange", "dash": "dash", "width": 2}
},
# Horizontal median line for selected Y variable
{
"type": "line",
"x0": 0,
"x1": 1,
"xref": "paper",
"y0": median_y,
"y1": median_y,
"line": {"color": "orange", "dash": "dash", "width": 2}
}
],
"annotations": [
# Annotation for vertical median line
{
"x": median_x,
"y": 1,
"xref": "x",
"yref": "paper",
"text": "Median rows",
"showarrow": False,
"xanchor": "left",
"yanchor": "bottom"
},
# Annotation for horizontal median line
{
"x": 0,
"y": median_y,
"xref": "paper",
"yref": "y",
"text": f"Median {y_col}: {median_y:.2f}",
"showarrow": False,
"xanchor": "left",
"yanchor": "bottom"
}
]
}
]
)
buttons.append(button)
# Add initial scatter plot
initial_y = y_columns[0]
initial_median_y = df[initial_y].median()
fig.add_trace(go.Scatter(
x=df["rows"],
y=df[initial_y],
mode='markers',
marker=dict(
color=df['outlier_prob'],
colorscale='viridis',
showscale=True,
colorbar=dict(title='Outlier Probability')
),
hoverinfo='text',
text=df.index,
showlegend=False
))
# Update layout with dropdown menu and initial median lines
fig.update_layout(
title=f"Scatter Plot: rows vs {initial_y}",
xaxis_title="rows",
yaxis_title=initial_y,
updatemenus=[{
"buttons": buttons,
"direction": "down",
"showactive": True,
"x": 0.17,
"y": 1.15,
"type": "dropdown"
}],
shapes=[
# Initial vertical median line
{
"type": "line",
"x0": median_x,
"x1": median_x,
"y0": 0,
"y1": 1,
"yref": "paper",
"line": {"color": "orange", "dash": "dash", "width": 2}
},
# Initial horizontal median line
{
"type": "line",
"x0": 0,
"x1": 1,
"xref": "paper",
"y0": initial_median_y,
"y1": initial_median_y,
"line": {"color": "orange", "dash": "dash", "width": 2}
}
],
annotations=[
# Initial annotation for vertical median line
{
"x": median_x,
"y": 1,
"xref": "x",
"yref": "paper",
"text": "Median rows",
"showarrow": False,
"xanchor": "left",
"yanchor": "bottom"
},
# Initial annotation for horizontal median line
{
"x": 0,
"y": initial_median_y,
"xref": "paper",
"yref": "y",
"text": f"Median {initial_y}: {initial_median_y:.2f}",
"showarrow": False,
"xanchor": "left",
"yanchor": "bottom"
}
]
)
# Show the plot
fig.show()