Javascript Plotly/Dash:如何使行索引唯一?

Javascript Plotly/Dash:如何使行索引唯一?,javascript,python,plotly,plotly-dash,Javascript,Python,Plotly,Plotly Dash,目标: 散点图中的选定点(使用套索工具)应在数据表中突出显示。如果可能的话,使用dash JS回调,但是任何其他的解决方案都会非常感激 问题: 行索引不是唯一的,但它们在每个类别(跟踪)中重复。因此,如果突出显示散点图左上角的3个最大点。只有2行而不是3行高亮显示。这两个中只有一个是正确的。请通过将悬停在绘图点上的标签与数据表中的信息进行比较来检查这一点 问题/解决方案: 如何使数据表的行索引唯一?或者选择适当的行以另一种方式高亮显示 要求: 熊猫 冲刺 仪表板\u引导\u组件 阴谋地 代码

目标: 散点图中的选定点(使用套索工具)应在数据表中突出显示。如果可能的话,使用dash JS回调,但是任何其他的解决方案都会非常感激

问题: 行索引不是唯一的,但它们在每个类别(跟踪)中重复。因此,如果突出显示散点图左上角的3个最大点。只有2行而不是3行高亮显示。这两个中只有一个是正确的。请通过将悬停在绘图点上的标签与数据表中的信息进行比较来检查这一点

问题/解决方案: 如何使数据表的行索引唯一?或者选择适当的行以另一种方式高亮显示

要求:

  • 熊猫
  • 冲刺
  • 仪表板\u引导\u组件
  • 阴谋地
代码

import pandas as pd
import dash
from dash.dependencies import Input, Output
import dash_table
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import plotly.express as px

df = pd.DataFrame.from_dict(
    {'term': {0: 'GOCC:0043229', 1: 'GOCC:0098588', 2: 'GOCC:0005730', 3: 'GO:0005730', 4: 'GO:0005783', 5: 'GO:0031410', 6: 'KW-0732', 7: 'KW-0156', 8: 'KW-0010'},
    'description': {0: 'Intracellular organelle', 1: 'Bounding membrane of organelle', 2: 'Nucleolus', 3: 'nucleolus', 4: 'endoplasmic reticulum', 5: 'cytoplasmic vesicle', 6: 'Signal', 7: 'Chromatin regulator', 8: 'Activator'},
     'FG_count': {0: 370, 1: 92, 2: 126, 3: 31, 4: 63, 5: 23, 6: 9, 7: 410, 8: 500},
     'logFDR': {0: 3, 1: 4, 2: 5, 3: 6, 4: 7, 5: 8, 6: 5, 7: 1, 8: 2},
     'effectSize': {0: 0.053, 1: -0.049, 2: 0.046, 3: 0.047, 4: -0.040, 5: -0.027, 6: -0.024, 7: 0.025, 8: 0.025},
     'category': {0: 'TM', 1: 'TM', 2: 'TM', 3: 'GOCC', 4: 'GOCC', 5: 'UPK', 6: 'UPK', 7: 'GOCC', 8: 'UPK'}})

app = dash.Dash(__name__, prevent_initial_callbacks=True, external_stylesheets=[dbc.themes.BOOTSTRAP])

max_marker_size = 40
sizeref = 2.0 * max(df["FG_count"]) / (max_marker_size ** 2)
app.layout = html.Div(id='general_div',
    children=[
        html.Div(id='first_row',
            children=[
                    html.Div(dcc.Graph(id='scatter_plot',
                     figure=px.scatter(data_frame=df, x="logFDR", y="effectSize", color="category", size="FG_count", hover_data={"term": True, "description": True, "FG_count": True, "logFDR": False, "effectSize": False, "category": False }, custom_data=["term", "description", "FG_count"]).update_traces(hovertemplate="<b>%{customdata[0]}</b><br>%{customdata[1]}<br>Size: %{customdata[2]}<extra></extra>", mode='markers', marker={'sizemode': 'area', 'sizeref': sizeref, 'sizemin': 3, }).update_layout(hoverlabel=dict(font_size=12, )))),
                ]
            ),

        html.Br(),

        html.Div(id="second_row",
            children=[html.Div(dash_table.DataTable(id='main_datatable', columns= [{"name": colName, "id": colName} for colName in df.columns], data=df.to_dict('records'), sort_action="native", row_selectable="multi", selected_columns=[], selected_rows=[], style_as_list_view=True,  style_cell={'minWidth': "10px", "width": "50px", "maxWidth": "80px", "fontSize": "12px", "font-family": "sans-serif", "text_align": "center", "border": "1px",}, )),
                      ]
            ),

        html.Br(),

        ]
)


def update_table_style(selectedData):
    """
    in analogy to
    https://stackoverflow.com/questions/62516573/update-dash-table-by-selecting-points-on-scatter-plot?answertab=active#tab-top
    """
    table_style_conditions = [{'if': {'row_index': 'odd'}, 'backgroundColor': "#F5F5F5", }] + [{"if": {"state": "selected"}, "backgroundColor": "inherit !important", "border": "inherit !important", "text_align": "inherit !important", }] + [{"if": {"state": "active"}, "backgroundColor": "inherit !important", "border": "inherit !important", "text_align": "inherit !important", }]

    pointIndex_list = []
    if selectedData is not None:
        for point in selectedData["points"]:
            print(point)
            pointIndex_list.append(point["pointIndex"])
        print("pointIndex_list: {}".format(pointIndex_list))
        print("point indices are not unique: ", len(pointIndex_list), "!=", len(set(pointIndex_list)))

        selected_styles = [{'if': {'row_index': point['pointIndex']},
                            'backgroundColor': 'gold'} for point in selectedData['points']]
        return (selected_styles + table_style_conditions)
    return (table_style_conditions)


@app.callback(Output('main_datatable', 'style_data_conditional'),
              [Input('scatter_plot', 'selectedData')])
def display_selected_data(selectedData):
    table_style_conditions = update_table_style(selectedData)
    return table_style_conditions

if __name__ == '__main__':
    app.run_server(debug=True, host="127.0.0.1", port=8001)
将熊猫作为pd导入
导入破折号
从dash.dependencies导入输入,输出
导入破折号表
将仪表板核心组件作为dcc导入
将dash_html_组件导入为html
将dash_引导程序_组件作为dbc导入
将plotly.express导入为px
df=pd.DataFrame.from_dict(
{'term':{0:'GOCC:0043229',1:'GOCC:0098588',2:'GOCC:0005730',3:'GO:0005730',4:'GO:0005783',5:'GO:0031410',6:'KW-0732',7:'KW-0156',8:'KW-0010'},
'描述':{0:'细胞内细胞器',1:'细胞器的界膜',2:'核仁',3:'核仁',4:'内质网',5:'细胞质小泡',6:'信号',7:'染色质调节器',8:'激活剂',
"FG_count":{0:370,1:92,2:126,3:31,4:63,5:23,6:9,7:410,8:500},
‘logFDR’:{0:3,1:4,2:5,3:6,4:7,5:8,6:5,7:1,8:2},
'effectSize':{0:0.053,1:0.049,2:0.046,3:0.047,4:0.040,5:0.027,6:0.024,7:0.025,8:0.025},
'类别':{0:'TM',1:'TM',2:'TM',3:'GOCC',4:'GOCC',5:'UPK',6:'UPK',7:'GOCC',8:'UPK'})
app=dash.dash(\uuuuuu name\uuuuuu,prevent\u initial\u callbacks=True,external\u样式表=[dbc.themes.BOOTSTRAP])
最大标记大小=40
sizeref=2.0*最大值(df[“FG\U计数])/(最大标记大小**2)
app.layout=html.Div(id='general\u Div',
孩子们=[
html.Div(id='first_row',
孩子们=[
html.Div(dcc.Graph(id='scatter\u plot',
figure=px.scatter(data_frame=df,x=“logFDR”,y=“effectSize”,color=“category”,size=“FG_count”,hover_data={term”:True,“description”:True,“FG_count”:True,“logFDR”:False,“effectSize”:False,“category”:False},自定义_数据=[“term”,“description”,“FG_count”])。更新_跟踪(hovertemplate=“%{customdata[0]}
%{customdata[1]}
大小:%{customdata[2]},mode='markers',marker='sizemode':'area','sizeref':sizeref','sizemin':3,}), ] ), html.Br(), html.Div(id=“第二行”, children=[html.Div(dash_table.DataTable(id='main_DataTable',columns=[{“name”:colName,“id”:colName}用于df.columns中的colName],data=df.to_dict('records'),sort_action=“native”,row_可选=“multi”,selected_columns=[],selected_-as_-list_-view=True,style_-cell={'minWidth':“10px”,“width”:“50px”,“maxWidth”:“80px”,“fontSize size”:“12px”,“字体系列”:“无衬线”,“文本对齐”:“中心”,“边框”:“1px”,},), ] ), html.Br(), ] ) def更新表格样式(选定数据): """ 类似于 https://stackoverflow.com/questions/62516573/update-dash-table-by-selecting-points-on-scatter-plot?answertab=active#tab-顶 """ 表格样式条件=[{'if':{'row_index':'odd'},{'backgroundColor':“{F5F5”,}]+[{“if”:{“state”:“selected”},“backgroundColor”:“inherit!important”,“border”:“inherit!important”,“border”;“text_align:“inherit!important”,}+[{“if”:“state:“active”},“backgroundColor:“inherit!important”,“border:“inherit!important”,“text_align”:“继承!重要”,}] pointIndex_list=[] 如果selectedData不是None: 对于所选数据中的点[“点”]: 打印(点) pointIndex_list.append(点[“pointIndex”]) 打印(“点索引列表:{}”。格式(点索引列表)) 打印(“点索引不唯一:”,len(点索引列表),“!=”,len(设置(点索引列表))) 选定的_样式=[{'if':{'row_index':点['pointIndex']}, 'backgroundColor':'gold'}表示所选数据中的点['points']] 返回(所选样式+表格样式条件) 返回(表格样式条件) @应用程序回调(输出('main\u datatable','style\u data\u conditional'), [输入('scatter_plot','selectedData')) def显示所选数据(所选数据): 表格样式\条件=更新表格样式(选定数据) 返回表\u样式\u条件 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': app.run_服务器(debug=True,host=“127.0.0.1”,端口=8001)
需要替换以下代码块。然后它就可以工作了。 诀窍是不使用冗余的行索引,而是使用“术语”列作为“id”。由于“术语”可以通过“自定义数据”从散点图的“点”中提取,因此可以随后与“过滤器查询”一起使用,以查找数据表中的对应行

df["id"] = df["term"]
df = df.set_index("id", drop=False)

dash_table.DataTable( ...
    style_data={'if': {'row_index': 'odd'}, 'backgroundColor': "#F5F5F5", },
    ...
)


def update_table_style(selectedData):
    """
    in analogy to
    https://stackoverflow.com/questions/62516573/update-dash-table-by-selecting-points-on-scatter-plot?answertab=active#tab-top
    """
    table_style_conditions = [{"if": {"state": "selected"}, "backgroundColor": "inherit !important", "border": "inherit !important", "text_align": "inherit !important", }] + [{"if": {"state": "active"}, "backgroundColor": "inherit !important", "border": "inherit !important", "text_align": "inherit !important", }] # [{'if': {'row_index': 'odd'}, 'backgroundColor': "#F5F5F5", }] +

    selected_term_list = []
    if selectedData is not None:
        for point in selectedData["points"]:
            selected_term_list.append(point["customdata"][0])
        print("selected_term_list: {}".format(selected_term_list))
        selected_styles = [{'if': {'filter_query': '{id}='+"{}".format(term)},
                            'backgroundColor': 'gold'} for term in selected_term_list]
        return (selected_styles + table_style_conditions)
    return (table_style_conditions)

@app.callback(Output('main_datatable', 'style_data_conditional'),
              [Input('scatter_plot', 'selectedData')])
def display_selected_data(selectedData):
    table_style_conditions = update_table_style(selectedData)
    return table_style_conditions

需要替换以下代码块。然后它就可以工作了。 诀窍是不使用冗余的行索引,而是使用“术语”列作为“id”。由于“术语”可以通过“自定义数据”从散点图的“点”中提取,因此可以随后与“过滤器查询”一起使用,以查找数据表中的对应行

df["id"] = df["term"]
df = df.set_index("id", drop=False)

dash_table.DataTable( ...
    style_data={'if': {'row_index': 'odd'}, 'backgroundColor': "#F5F5F5", },
    ...
)


def update_table_style(selectedData):
    """
    in analogy to
    https://stackoverflow.com/questions/62516573/update-dash-table-by-selecting-points-on-scatter-plot?answertab=active#tab-top
    """
    table_style_conditions = [{"if": {"state": "selected"}, "backgroundColor": "inherit !important", "border": "inherit !important", "text_align": "inherit !important", }] + [{"if": {"state": "active"}, "backgroundColor": "inherit !important", "border": "inherit !important", "text_align": "inherit !important", }] # [{'if': {'row_index': 'odd'}, 'backgroundColor': "#F5F5F5", }] +

    selected_term_list = []
    if selectedData is not None:
        for point in selectedData["points"]:
            selected_term_list.append(point["customdata"][0])
        print("selected_term_list: {}".format(selected_term_list))
        selected_styles = [{'if': {'filter_query': '{id}='+"{}".format(term)},
                            'backgroundColor': 'gold'} for term in selected_term_list]
        return (selected_styles + table_style_conditions)
    return (table_style_conditions)

@app.callback(Output('main_datatable', 'style_data_conditional'),
              [Input('scatter_plot', 'selectedData')])
def display_selected_data(selectedData):
    table_style_conditions = update_table_style(selectedData)
    return table_style_conditions