带有 ipywidgets 的交互式 plotly boxplot

Interactive plotly boxplot with ipywidgets

我正在尝试使用 ipywidgets 和 Plotly 创建交互式箱线图。

我从 this example

开始

虽然这很好,但我想根据下拉输入更改箱线图的分组。

有了 interact 我可以做到这一点:

import datetime
import numpy as np
import pandas as pd

import plotly.graph_objects as go
from ipywidgets import widgets

df = pd.read_csv(
 'https://raw.githubusercontent.com/yankev/testing/master/datasets/nycflights.csv')
df = df.drop(df.columns[[0]], axis=1)

from ipywidgets import interact

def view_image(col):
    fig = go.FigureWidget()
    for val in df[col].unique():
        groupData = df.query(f'{col} == "{val}"')
        fig.add_trace(
            go.Box(y = groupData['distance'],
                  name = val)
        )
    fig.show()
    

    
interact(view_image, col = ['origin', 'carrier'])

结果是我可以更改数据分组所依据的列。

但是,我想对小部件有更多的控制,就像在官方示例中那样。

这就是我正在尝试的(但失败了):

# Assign an empty figure widget with two traces
gdata = []
for origin in df.origin.unique():
    groupData = df.query(f'origin == "{origin}"')
    gdata.append(
        go.Box(y = groupData['distance'],
              name = origin)
    )
g = go.FigureWidget(data=gdata,
                    layout=go.Layout(
                        title=dict(
                            text='NYC FlightDatabase'
                        ),
                        barmode='overlay'
                    ))

def response_box(change):
    col = column.value
    with g.batch_update():
        gdata = []
        for val in df[col].unique():
            groupData = df.query(f'{col} == "{val}"')
            gdata.append(
                go.Box(y = groupData['distance'],
                      name = val)
            )
        g.data = gdata

column = widgets.Dropdown(
    options=['origin','carrier']
)
column.observe(response_box, 'value')
container2 = widgets.HBox([column])
widgets.VBox([container2,
              g])

请注意,由于我有新的分组,我不能只进入 g.data[index].y 并更改每个索引,但我必须像在 interact 函数中那样重新生成图形。

这个特定的迭代给我一个“你不能直接更新数据”的错误。我尝试了几种不同的方法,但我似乎没有找到一种有效的方法。

有什么想法吗?

import datetime
import numpy as np
import pandas as pd

import plotly.graph_objects as go
import plotly.express as px
from ipywidgets import widgets
from ipywidgets import interact

df = pd.read_csv(
    "https://raw.githubusercontent.com/yankev/testing/master/datasets/nycflights.csv"
)
df = df.drop(df.columns[[0]], axis=1)

@interact
def view_image(
    col=widgets.Dropdown(
        description="Plot:", value="carrier", options=["origin", "carrier"]
    ),
    filtercol=widgets.Dropdown(
        description="Filter by:", value="carrier", options=["origin", "dest", "carrier"]
    ),

    filter=widgets.Text(
        description="Filter:", value=""
    ),
):
    # check if filter results in any rows... if not all data...
    if df[filtercol].eq(filter).any():
        dfp = df.loc[df[filtercol].eq(filter)]
    else:
        dfp = df
    fig = px.box(dfp, x=col, y="distance", color=col)
    go.FigureWidget(fig.to_dict()).show()