plotly / plotly/plotly.py

Pandas import error

未关闭
#2,433 10 条评论 2 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

bug P3
主要语言
Python
星标
18.8k
派生
2.8k
平均合并
16 小时 26 分钟
30 天内合并 PR
21

描述

A Dash user is seeing an error from pandas without ever directly importing pandas, just dash, plotly, and numpy. https://community.plotly.com/t/callback-error-when-plotting-multiple-graph-objects/38756

The error occurs inside plotly when the Dash app tries to render one of the plots in a callback:

Traceback (most recent call last):
  File "/Users/alex/plotly/fiddle/f.py", line 74, in update_dist_plot
    "data": [go.Bar(x=bins, y=counts)],
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/plotly/graph_objs/__init__.py", line 93149, in __init__
    self["x"] = x if x is not None else _v
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/plotly/basedatatypes.py", line 3490, in __setitem__
    self._set_prop(prop, value)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/plotly/basedatatypes.py", line 3772, in _set_prop
    val = validator.validate_coerce(val)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_plotly_utils/basevalidators.py", line 385, in validate_coerce
    v = copy_to_readonly_numpy_array(v)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_plotly_utils/basevalidators.py", line 93, in copy_to_readonly_numpy_array
    if pd and isinstance(v, (pd.Series, pd.Index)):
AttributeError: module 'pandas' has no attribute 'Series'

That's the error I see - the OP's error message is a little more extensive, which is a little funny because we both report pandas v1.0.3

AttributeError: partially initialized module ‘pandas’ has no attribute ‘Series’ (most likely due to a circular import)

I can reproduce locally with this app:

import dash_core_components as dcc
import dash_html_components as html
from dash import Dash
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import numpy as np

app = Dash(__name__)

app.layout = html.Div(
    [
        html.Div(
            [
                html.Br(),
                html.Label("Plotting Options"),
                dcc.RadioItems(
                    id="trunk-angle-radio",
                    options=[
                        {"label": "Sagittal", "value": "Sagittal"},
                        {"label": "Lateral", "value": "Lateral"},
                        {"label": "Twist", "value": "Twist"},
                    ],
                    value="Sagittal",
                ),
            ]
        ),
        html.Div(
            [
                html.Div(
                    [dcc.Graph(id="trunk-angle-plot")],
                    style={"width": "48%", "display": "inline-block"},
                ),
                html.Div(
                    [dcc.Graph(id="trunk-angle-dist")],
                    style={"width": "48%", "display": "inline-block", "float": "right"},
                ),
            ]
        ),
        html.Div(
            [
                html.Label("Data Statistics"),
                html.Div(id="data-stats-div", style={"padding": 10}),
            ]
        ),
    ]
)


@app.callback(
    Output("trunk-angle-plot", "figure"), [Input("trunk-angle-radio", "value")]
)
def update_angle_plot(radio_option):
    (x, y) = get_trunk_angles(radio_option)
    fig = {
        "data": [go.Scatter(x=x, y=y, mode="lines+markers")],
        "layout": go.Layout(
            title="Trunk Angle Time Series Plot",
            xaxis={"title": "Time (sec)"},
            yaxis={"title": "Degrees"},
        ),
    }
    return fig


@app.callback(
    Output("trunk-angle-dist", "figure"), [Input("trunk-angle-radio", "value")]
)
def update_dist_plot(radio_option):
    (x, y) = get_trunk_angles(radio_option)
    counts, bins = np.histogram(y, bins=range(-90, 91, 30))
    bins = bins + (bins[1] - bins[0]) / 2
    # print(counts, bins)
    fig = {
        "data": [go.Bar(x=bins, y=counts)],
        "layout": go.Layout(
            title="Trunk Angle Distributions",
            xaxis={
                "title": "Bin midpoint (degrees)",
                "tickmode": "array",
                "tickvals": bins,
                "ticktext": [str(int(bin)) for bin in bins],
            },
            yaxis={"title": "Percentage of time"},
        ),
    }
    return fig


@app.callback(
    Output("data-stats-div", "children"), [Input("trunk-angle-radio", "value")]
)
def update_stats(radio_option):
    (x, y) = get_trunk_angles(radio_option)
    stats_div = [
        html.Div("Minimum: {}".format(np.min(y)), id="trunk-angle-dist-min"),
        html.Div("Maximum: {}".format(np.max(y)), id="trunk-angle-dist-max"),
        html.Div("Mean: {:.2f}".format(np.mean(y)), id="trunk-angle-dist-mean"),
        html.Div(
            "Standard Deviation: {:.2f}".format(np.std(y)), id="trunk-angle-dist-std"
        ),
        html.Div(
            "Range: {}".format(np.max(y) - np.min(y)), id="trunk-angle-dist-range"
        ),
    ]
    return stats_div


def get_trunk_angles(radio_option):

    dummy_x = np.linspace(0, 50, 101)

    if radio_option == "Sagittal":
        dummy_y = np.random.randint(-90, 90, 101)
    elif radio_option == "Lateral":
        dummy_y = np.random.randint(-90, 90, 101)
    elif radio_option == "Twist":
        dummy_y = np.random.randint(-90, 90, 101)

    return (dummy_x, dummy_y)


if __name__ == "__main__":
    app.run_server(debug=True)

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

复现提供的 Dash 应用,并从 plotly/basedatatypes.py 和 _plotly_utils/basevalidators.py 中的 traceback 位置开始,尤其关注 update_dist_plot 和 copy_to_readonly_numpy_array。追踪在构造 go.Bar 时 pandas 缺少 Series 的原因,然后验证 callback 在没有报告的 AttributeError 的情况下能够渲染。

由索引模型根据 Issue 内容生成。

评估

技术栈
numpy, pandas, python
领域
data-visualization
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
需要澄清
新手友好度
25/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。