英文:
Plotly update_menus hiding traces problem
问题
以下是您要翻译的内容:
Newbie in Plotly with Python and StackOverflow here. I have created a figure that includes a number of box plots, a scatter plot and a few more elements that can be relayed out.
My data have gaps that I want to optionally toggle on and off from appearing in the graph using a dropdown list (see Image 1).
In one case, I can hide the gaps successfully but the scatter plot loses its X axis values and is graphed after the end of the labeled data (see Image 2). This is produced by this line of code: dict(label="Exclude missing data", method="update", args=[{"x":df.Run[x_some],"visible": x_some}])
In the other case I can hide the gaps in the data, the scatter plot works but the labels of the X axis that were "hidden" move to the end of the graph (see Image 3). This is produced by this line of code: dict(label="Exclude missing data", method="update", args=[{"visible": x_some}])
Are there any hints on what I'm doing wrong and how to fix this?
Please find some sample code below:
import pandas as pd
import numpy as np
import plotly.io as pio
import datetime as dt
import plotly.graph_objects as go
pio.renderers.default = 'browser'
pd.options.plotting.backend = "plotly"
fig = go.Figure()
N = 100
ydata = np.random.randint(600, 1200, size=(100, 5))
x = ["R"+str(i) for i in range(len(ydata))]
df = pd.DataFrame(ydata, columns=["M1", "M2", "M3", "M4", "M5"])
df["X"] = x
gaps = np.r_[20:40, 60:70]
df.iloc[gaps, 0:5] = np.nan
df["Mean"] = df.iloc[:, 0:5].mean(axis=1).round(0)
cols = df.columns.str.contains("M")
# %% figure setup
layout = dict(
height=700, width=1500,
xaxis_title="Run",
xaxis=dict(autorange=False, range=[0, N], type="category"),
yaxis=dict(autorange=True),
font=dict(family="Courier New, monospace", size=12, color="RebeccaPurple"),
showlegend=False
)
fig.layout = layout
mean_line = go.Scatter(x=df.X, y=df.Mean, connectgaps=True, mode='lines+markers', name='Mean line', showlegend=False)
boxes = , y=df.iloc[i, cols], boxpoints=False, boxmean=True, notched=True, showlegend=False) for i in range(N)]
fig.add_traces(boxes)
x_all = df.index == df.index
x_some = (df.Mean > 0).values
fig.add_trace(mean_line)
fig.update_layout(updatemenus=[
dict(type="dropdown", direction="down", buttons=list([
dict(label="Include missing data", method="update", args=[{"visible": x_all}]),
dict(label="Exclude missing data", method="update", args=[{"visible": x_some}])
]), pad={"l": 10, "t": 10}, showactive=True, x=0.23, xanchor="left", y=1.1, yanchor="top")])
z = fig.to_dict()
fig.show()
英文:
Newbie in Plotly with Python and StackOverflow here. I have created a figure that includes a number of box plots, a scatter plot and a few more elements that can be relayed out.
My data have gaps that I want to optionally toggle on and off from appearing in the graph using a dropdown list (see Image 1).
In one case, I can hide the gaps successfully but the scatter plot loses its X axis values and is graphed after the end of the labeled data (see Image 2). This is produced by this line of code: dict(label="Exclude missing data", method="update", args=[{"x":df.Run[x_some],"visible": x_some}])
In the other case I can hide the gaps in the data, the scatter plot works but the labels of the X axis that were "hidden" move to the end of the graph (see Image 3). This is produced by this line of code: dict(label="Exclude missing data", method="update", args=[{"visible": x_some}])
Are there any hints on what I'm doing wrong and how to fix this?
Please find some sample code below:
import pandas as pd
import numpy as np
import plotly.io as pio
import datetime as dt
import plotly.graph_objects as go
pio.renderers.default = 'browser'
pd.options.plotting.backend = "plotly"
fig = go.Figure()
N = 100
ydata = np.random.randint(600, 1200, size=(100, 5))
x = ["R"+str(i) for i in range(len(ydata))]
df = pd.DataFrame(ydata, columns=["M1", "M2", "M3", "M4", "M5"])
df["X"] = x
gaps = np.r_[20:40, 60:70]
df.iloc[gaps, 0:5] = np.nan
df["Mean"] = df.iloc[:, 0:5].mean(axis=1).round(0)
cols = df.columns.str.contains("M")
# %% figure setup
layout = dict(
height=700, width=1500,
xaxis_title="Run",
xaxis=dict(autorange=False, range=[0, N], type="category"),
yaxis=dict(autorange=True),
font=dict(family="Courier New, monospace", size=12, color="RebeccaPurple"),
showlegend=False
)
fig.layout = layout
mean_line = go.Scatter(x=df.X, y=df.Mean, connectgaps=True, mode='lines+markers', name='Mean line', showlegend=False)
boxes = , y=df.iloc[i, cols], boxpoints=False, boxmean=True, notched=True, showlegend=False) for i in range(N)]
fig.add_traces(boxes)
x_all = df.index == df.index
x_some = (df.Mean > 0).values
fig.add_trace(mean_line)
fig.update_layout(updatemenus=[
dict(type="dropdown", direction="down", buttons=list([
dict(label="Include missing data", method="update", args=[{"visible": x_all}]),
dict(label="Exclude missing data", method="update", args=[{"visible": x_some}])
]), pad={"l": 10, "t": 10}, showactive=True, x=0.23, xanchor="left", y=1.1, yanchor="top")])
z = fig.to_dict()
fig.show()
答案1
得分: 0
发生这种情况的原因是因为你忘记考虑最后一个散点图,它仍然包含NaN
的x值。(这里有100个箱线图和1个散点图,所以x_all
和x_some
实际上应该有长度101 - 在你的原始代码中,这两个布尔数组的长度是100,但是Plotly假设你想要显示最后一个散点图)
为了解决这个问题,我们可以添加另一个散点图,其中包含缺失值 - 我们可以将其默认设置为不可见,并且只有在你从下拉菜单中选择“排除缺失数据”时才显示这个散点图。
注意:x_all
和x_some
现在将有长度102。x_all
应该看起来像[True,... True, True, False]
,因为我们显示了前100个箱线图,然后显示了第一个散点图,没有删除null值,然后不显示第二个散点图,它已经删除了null值。x_some
应该看起来像[True...False... False... True, False, True]
,因为一些空的箱线图不会被显示,然后我们不显示第一个散点图,但是显示了删除了null值的第二个散点图。
import pandas as pd
import numpy as np
import plotly.io as pio
import datetime as dt
import plotly.graph_objects as go
pio.renderers.default = 'browser'
pd.options.plotting.backend = "plotly"
fig = go.Figure()
N = 100
ydata = np.random.randint(600, 1200, size=(100, 5))
x = ["R"+str(i) for i in range(len(ydata))]
df = pd.DataFrame(ydata, columns=["M1", "M2", "M3", "M4", "M5"])
df["X"] = x
gaps = np.r_[20:40, 60:70]
df.iloc[gaps, 0:5] = np.nan
df["Mean"] = df.iloc[:, 0:5].mean(axis=1).round(0)
cols = df.columns.str.contains("M")
# figure setup
layout = dict(
height=700, width=1500,
xaxis_title="Run",
xaxis=dict(autorange=False, range=[0, N], type="category"),
yaxis=dict(autorange=True),
font=dict(family="Courier New, monospace", size=12, color="RebeccaPurple"),
showlegend=False
)
fig.layout = layout
mean_line = go.Scatter(x=df.X, y=df.Mean, connectgaps=True, mode='lines+markers', name='Mean line', showlegend=False)
## create mean line with excluded values missing (not visible by default)
df_non_null = df.dropna()
mean_line_exclude_missing = go.Scatter(x=df_non_null.X, y=df_non_null.Mean, connectgaps=False, mode='lines+markers', name='Mean line', showlegend=False, visible=False)
boxes = , y=df.iloc[i, cols], boxpoints=False, boxmean=True, notched=True, showlegend=False) for i in range(N)]
fig.add_traces(boxes)
x_all = df.index == df.index
x_all = np.append(x_all, [True, False])
x_some = (df.Mean > 0).values
x_some = np.append(x_some, [False, True])
## the last two traces will be the mean line, and the mean line (with nulls excluded)
fig.add_trace(mean_line)
fig.add_trace(mean_line_exclude_missing)
fig.update_layout(updatemenus=[
dict(type="dropdown", direction="down", buttons=list([
dict(label="Include missing data", method="update", args=[{"visible": x_all}]),
dict(label="Exclude missing data", method="update", args=[{"visible": x_some}])
]), pad={"l": 10, "t": 10}, showactive=True, x=0.23, xanchor="left", y=1.1, yanchor="top")])
z = fig.to_dict()
fig.show()
英文:
The reason this is occurring is because you forgot to account for the last trace which is the scatter, and it still includes x-values that are NaN
. (there are 100 box traces and 1 scatter trace, so x_all
and x_some
should actually have length 101 – in your original code, these two boolean arrays have length 100, but plotly assumes that you mean to show the last scatter trace)
To fix this, we can add another scatter trace with missing values dropped – we can make this not visible by default, and only show this scatter when you select the "Exclude missing data"
from the dropdown.
Note: x_all
and x_some
will now have length 102. x_all
should look like [True,... True, True, False]
because we show the first 100 boxplots, and then show the first scatter without nulls dropped, but then don't show the second scatter which has nulls dropped. And x_some
should look like [True...False... False... True, False, True]
because some of the box plots traces that are empty won't be shown, and then we don't show the first scatter without nulls dropped, but show the second scatter which has nulls dropped.
import pandas as pd
import numpy as np
import plotly.io as pio
import datetime as dt
import plotly.graph_objects as go
pio.renderers.default = 'browser'
pd.options.plotting.backend = "plotly"
fig = go.Figure()
N = 100
ydata = np.random.randint(600, 1200, size=(100, 5))
x = ["R"+str(i) for i in range(len(ydata))]
df = pd.DataFrame(ydata, columns=["M1", "M2", "M3", "M4", "M5"])
df["X"] = x
gaps = np.r_[20:40, 60:70]
df.iloc[gaps, 0:5] = np.nan
df["Mean"] = df.iloc[:, 0:5].mean(axis=1).round(0)
cols = df.columns.str.contains("M")
# figure setup
layout = dict(
height=700, width=1500,
xaxis_title="Run",
xaxis=dict(autorange=False, range=[0, N], type="category"),
yaxis=dict(autorange=True),
font=dict(family="Courier New, monospace", size=12, color="RebeccaPurple"),
showlegend=False
)
fig.layout = layout
mean_line = go.Scatter(x=df.X, y=df.Mean, connectgaps=True, mode='lines+markers', name='Mean line', showlegend=False)
## create mean line with excluded values missing (not visible by default)
df_non_null = df.dropna()
mean_line_exclude_missing = go.Scatter(x=df_non_null.X, y=df_non_null.Mean, connectgaps=False, mode='lines+markers', name='Mean line', showlegend=False, visible=False)
boxes = , y=df.iloc[i, cols], boxpoints=False, boxmean=True, notched=True, showlegend=False) for i in range(N)]
fig.add_traces(boxes)
x_all = df.index == df.index
x_all = np.append(x_all, [True, False])
x_some = (df.Mean > 0).values
x_some = np.append(x_some, [False, True])
## the last two traces will be the mean line, and the mean line (with nulls excluded)
fig.add_trace(mean_line)
fig.add_trace(mean_line_exclude_missing)
fig.update_layout(updatemenus=[
dict(type="dropdown", direction="down", buttons=list([
dict(label="Include missing data", method="update", args=[{"visible": x_all}]),
dict(label="Exclude missing data", method="update", args=[{"visible": x_some}])
]), pad={"l": 10, "t": 10}, showactive=True, x=0.23, xanchor="left", y=1.1, yanchor="top")])
z = fig.to_dict()
fig.show()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论