我尝试通过简单地根据复选框显示图表来使用小部件。
它显示了 2 个城市(格勒诺布尔和维齐尔)多年来的出生人数。
我想根据复选框显示 0、1 或 2 个城市的进化线。
一开始没问题:它显示 0 行,然后当我们选中这些框时显示 1 或 2 行。
但是如果我取消选中一个框,它不会删除一行。
我的代码中忘记了什么?
这是一个可重现的例子:
import os
import pandas as pd
import plotly.graph_objects as go
from ipywidgets import widgets
# CSV from URL
url = "https://entrepot.metropolegrenoble.fr/opendata/200040715-MET/insee/etat_civil_200040715.csv"
data_pop = pd.read_csv(url)
# Data prep
noms_col = data_pop.columns
data_pop.reset_index(inplace=True)
data_pop.drop(["code_postal"],axis=1,inplace=True)
data_pop.columns = noms_col
# Using widgets
use_Gre = widgets.Checkbox(
description='Grenoble',
value=False,
)
use_Viz = widgets.Checkbox(
description='Vizille',
value=False,
)
container_1 = widgets.HBox(children=[use_Gre, use_Viz])
g = go.FigureWidget(data=[{'type': 'scatter'}])
def validate1():
if use_Gre.value is True:
return True
else:
return False
def validate2():
if use_Viz.value is True:
return True
else:
return False
def response1(change):
if validate1():
if use_Gre.value:
trace01 = data_pop[data_pop['commune']=="Grenoble"].nombre_naissances
x1=data_pop[data_pop['commune']=="Grenoble"].annee
with g.batch_update():
g.add_scatter(y=trace01,name="Grenoble", x= x1)
def response2(change):
if validate2():
if use_Viz.value:
trace02 = data_pop[data_pop['commune']=="Vizille"].nombre_naissances
x2=data_pop[data_pop['commune']=="Vizille"].annee
with g.batch_update():
g.add_scatter(y=trace02,name="Vizille", x= x2)
use_Gre.observe(response1, names="value")
use_Viz.observe(response2, names="value")
widgets.VBox([container_1, g])
我可以建议使用 plotly.express 吗?它将显着减少您的代码,并且已经具有显示/隐藏图例中的图的功能:
import pandas as pd
import plotly.express as px
# CSV from URL
url = "https://entrepot.metropolegrenoble.fr/opendata/200040715-MET/insee/etat_civil_200040715.csv"
data_pop = pd.read_csv(url)
# Data prep
noms_col = data_pop.columns
data_pop.reset_index(inplace=True)
data_pop.drop(["code_postal"],axis=1,inplace=True)
data_pop.columns = noms_col
# keeping only the two cities of interest
data_pop = data_pop[data_pop['commune'].isin(['Grenoble', 'Vizille'])]
fig = px.line(x=data_pop['annee'],
y=data_pop['nombre_naissances'],
color=data_pop['commune'])
# the option legendonly can be set to hide plot by default
for scat in fig.data:
if scat.legendgroup == "Vizille":
scat.visible = "legendonly"
fig.show()
输出:
关于您的代码,问题是每次您选中该框时您的响应函数都会重新绘制数据,但是当您取消选中该框时您不会删除它(您应该在 else 块中执行此操作)
编辑:更正了有关
legendonly
的代码部分
visible
属性,而不是绘制一个空图形并向其添加轨迹。
正如@Tranbi 所建议的那样,使用图例切换可以解决问题,您不一定需要复选框小部件。
不过,假设您更喜欢隐藏图例并仅使用小部件(即计划添加城市和/或更多小部件),并坚持使用 plotly.graph_objects,您可以重构代码如下:
# Data prep
noms_col = data_pop.columns
data_pop.reset_index(inplace=True)
data_pop.drop(["code_postal"],axis=1,inplace=True)
data_pop.columns = noms_col
cities = ['Grenoble', 'Vizille']
# Named lists
checkboxes = dict()
traces = dict()
for city in cities:
# Widget
checkboxes[city] = widgets.Checkbox(description=city, value=False)
# Trace
x = data_pop[data_pop['commune']==city].annee
y = data_pop[data_pop['commune']==city].nombre_naissances
traces[city] = go.Scatter(name=city, x=x, y=y, visible=False)
container_1 = widgets.HBox(children=list(checkboxes.values()))
fig = go.FigureWidget(data=list(traces.values()), layout=dict(showlegend=False))
def response(change):
city = change.owner.description
fig.update_traces(selector=dict(name=city), visible=checkboxes[city].value)
for checkbox in list(checkboxes.values()):
checkbox.observe(response, names='value')
widgets.VBox([container_1, fig])