Example #1
0
 def osi_download_button_pressed(self):
     return (
         Output(self.dashboard_home.download_excel, "data"),
         Input(self.dashboard_home.download_excel_button, "n_clicks"),
     )
Example #2
0
import dash_bootstrap_components as dbc
from dash import Input, Output, html

list_group = html.Div([
    dbc.ListGroup([
        dbc.ListGroupItem("Internal link", href="/l/components/list_group"),
        dbc.ListGroupItem("External link", href="https://google.com"),
        dbc.ListGroupItem("Disabled link",
                          href="https://google.com",
                          disabled=True),
        dbc.ListGroupItem("Button", id="button-item", n_clicks=0, action=True),
    ]),
    html.P(id="counter"),
])


@app.callback(Output("counter", "children"),
              [Input("button-item", "n_clicks")])
def count_clicks(n):
    return f"Button clicked {n} times"
def distribution_controllers(get_uuid: Callable,
                             volumemodel: InplaceVolumesModel) -> None:
    @callback(
        Output({
            "id": get_uuid("main-voldist"),
            "page": "custom"
        }, "children"),
        Input(get_uuid("selections"), "data"),
        State(get_uuid("page-selected"), "data"),
    )
    def _update_page_custom(selections: dict, page_selected: str) -> tuple:

        if page_selected != "custom":
            raise PreventUpdate

        selections = selections[page_selected]
        if not selections["update"]:
            raise PreventUpdate

        selected_data = [
            selections[x]
            for x in ["Subplots", "Color by", "X Response", "Y Response"]
            if selections[x] is not None
        ]
        groups = ["REAL"]
        parameters = []
        for item in selected_data:
            if item in volumemodel.selectors and item not in groups:
                groups.append(item)
            if item in volumemodel.parameters and item not in parameters:
                parameters.append(item)

        # for bo/bg the data should be grouped on fluid zone
        if any(x in selected_data
               for x in ["BO", "BG"]) and "FLUID_ZONE" not in groups:
            if "BO" in selected_data and "BG" in selected_data:
                return html.Div("Can't plot BO against BG",
                                style={"margin-top": "40px"})
            selections["filters"]["FLUID_ZONE"] = [
                "oil" if "BO" in selected_data else "gas"
            ]

        dframe = volumemodel.get_df(filters=selections["filters"],
                                    groups=groups,
                                    parameters=parameters)

        if dframe.empty:
            return html.Div("No data left after filtering",
                            style={"margin-top": "40px"})

        df_for_figure = (dframe if not (selections["Plot type"] == "bar"
                                        and not "REAL" in selected_data) else
                         dframe.groupby([x for x in groups
                                         if x != "REAL"]).mean().reset_index())
        figure = (
            create_figure(
                plot_type=selections["Plot type"],
                data_frame=df_for_figure,
                x=selections["X Response"],
                y=selections["Y Response"],
                nbins=selections["hist_bins"],
                facet_col=selections["Subplots"],
                color=selections["Color by"],
                color_discrete_sequence=selections["Colorscale"],
                color_continuous_scale=selections["Colorscale"],
                barmode=selections["barmode"],
                boxmode=selections["barmode"],
                layout=dict(title=dict(
                    text=(f"{volume_description(selections['X Response'])}" +
                          (f" [{volume_unit(selections['X Response'])}]"
                           if selections["X Response"]
                           in volumemodel.volume_columns else "")),
                    x=0.5,
                    xref="paper",
                    font=dict(size=18),
                ), ),
                yaxis=dict(showticklabels=True),
            ).add_annotation(
                fluid_annotation(selections)).update_xaxes({
                    "matches": None
                } if not selections["X axis matches"] else {}).update_yaxes({
                    "matches":
                    None
                } if not selections["Y axis matches"] else {}).update_xaxes(
                    {
                        "type": "category",
                        "tickangle": 45,
                        "tickfont_size": 12
                    } if selections["X Response"] in
                    volumemodel.selectors else {}))

        return custom_plotting_layout(
            figure=figure,
            tables=make_tables(
                dframe=dframe,
                responses=list(
                    {selections["X Response"], selections["Y Response"]}),
                groups=groups,
                volumemodel=volumemodel,
                page_selected=page_selected,
                selections=selections,
                table_type="Statistics table",
                view_height=37,
            ) if selections["bottom_viz"] == "table" else None,
        )

    @callback(
        Output({
            "id": get_uuid("main-table"),
            "page": "table"
        }, "children"),
        Input(get_uuid("selections"), "data"),
        State(get_uuid("page-selected"), "data"),
    )
    def _update_page_tables(
        selections: dict,
        page_selected: str,
    ) -> list:

        if page_selected != "table":
            raise PreventUpdate

        selections = selections[page_selected]
        if not selections["update"]:
            raise PreventUpdate

        table_groups = (["ENSEMBLE", "REAL"] if selections["Table type"]
                        == "Statistics table" else ["ENSEMBLE"])
        if selections["Group by"] is not None:
            table_groups.extend(
                [x for x in selections["Group by"] if x not in table_groups])
        dframe = volumemodel.get_df(filters=selections["filters"],
                                    groups=table_groups)

        return make_tables(
            dframe=dframe,
            responses=selections["table_responses"],
            groups=selections["Group by"],
            view_height=85,
            table_type=selections["Table type"],
            volumemodel=volumemodel,
            page_selected=page_selected,
            selections=selections,
        )

    @callback(
        Output({
            "id": get_uuid("main-voldist"),
            "page": "per_zr"
        }, "children"),
        Input(get_uuid("selections"), "data"),
        State(get_uuid("page-selected"), "data"),
    )
    def _update_page_per_zr(selections: dict, page_selected: str) -> list:
        if page_selected != "per_zr":
            raise PreventUpdate

        selections = selections[page_selected]
        if not selections["update"]:
            raise PreventUpdate

        figs = []
        selectors = [
            x for x in ["ZONE", "REGION", "FACIES", "FIPNUM", "SET"]
            if x in volumemodel.selectors
        ]
        color = selections["Color by"] is not None
        for selector in selectors:
            groups = list({selector, selections["Color by"]
                           }) if color else [selector]
            dframe = volumemodel.get_df(filters=selections["filters"],
                                        groups=groups)
            piefig = ((create_figure(
                plot_type="pie",
                data_frame=dframe,
                values=selections["X Response"],
                names=selector,
                color_discrete_sequence=selections["Colorscale"],
                color=selector,
            ).update_traces(
                marker_line=dict(color="#000000", width=1)).update_layout(
                    margin=dict(l=10, b=10))) if not color else [])
            barfig = create_figure(
                plot_type="bar",
                data_frame=dframe,
                x=selector,
                y=selections["X Response"],
                title=f"{selections['X Response']} per {selector}",
                barmode="overlay"
                if selector == selections["Color by"] else "group",
                layout={
                    "bargap": 0.05
                },
                color_discrete_sequence=selections["Colorscale"],
                color=selections["Color by"],
                text=selections["X Response"],
                xaxis=dict(type="category",
                           tickangle=45,
                           tickfont_size=17,
                           title=None),
            ).update_traces(
                texttemplate=("%{text:.3s}" if selections["X Response"]
                              in volumemodel.volume_columns else
                              "%{text:.3g}"),
                textposition="auto",
            )

            if selections["X Response"] not in volumemodel.hc_responses:
                barfig.add_annotation(fluid_annotation(selections))
            figs.append([piefig, barfig])
        return plots_per_zone_region_layout(figs)

    @callback(
        Output({
            "id": get_uuid("main-voldist"),
            "page": "conv"
        }, "children"),
        Input(get_uuid("selections"), "data"),
        State(get_uuid("page-selected"), "data"),
    )
    def _update_page_conv(selections: dict, page_selected: str) -> go.Figure:
        if page_selected != "conv":
            raise PreventUpdate

        selections = selections[page_selected]
        if not selections["update"]:
            raise PreventUpdate

        subplots = selections["Subplots"] if selections[
            "Subplots"] is not None else []
        groups = ["REAL"]
        if subplots and subplots not in groups:
            groups.append(subplots)

        dframe = volumemodel.get_df(filters=selections["filters"],
                                    groups=groups)
        dframe = dframe.sort_values(by=["REAL"])

        if dframe.empty:
            return html.Div("No data left after filtering",
                            style={"margin-top": "40px"})

        dfs = []
        df_groups = dframe.groupby(subplots) if subplots else [(None, dframe)]
        for _, df in df_groups:
            for calculation in ["mean", "p10", "p90"]:
                df_stat = df.reset_index(drop=True).copy()
                df_stat[selections["X Response"]] = (
                    (df_stat[selections["X Response"]].expanding().mean())
                    if calculation == "mean" else
                    df_stat[selections["X Response"]].expanding().quantile(
                        0.1 if calculation == "p90" else 0.9))
                df_stat["calculation"] = calculation
                df_stat["index"] = df_stat.index + 1
                dfs.append(df_stat)
        if dfs:
            dframe = pd.concat(dfs)

        title = (
            f"<b>Convergence plot of mean/p10/p90 for {selections['X Response']} </b>"
            "  -  shaded areas indicates failed/filtered out realizations")

        figure = (create_figure(
            plot_type="line",
            data_frame=dframe,
            x="REAL",
            y=selections["X Response"],
            facet_col=selections["Subplots"],
            color="calculation",
            custom_data=["calculation", "index"],
            title=title,
            yaxis=dict(showticklabels=True),
        ).update_traces(
            hovertemplate=
            (f"{selections['X Response']} %{{y}} <br>"
             f"%{{customdata[0]}} for realizations {dframe['REAL'].min()}-%{{x}}<br>"
             "Realization count: %{customdata[1]} <extra></extra>"),
            line_width=3.5,
        ).update_traces(line_color="black", selector={
            "name": "mean"
        }).update_traces(
            line=dict(color="firebrick", dash="dash"),
            selector={
                "name": "p10"
            }).update_traces(
                line=dict(color="royalblue", dash="dash"),
                selector={
                    "name": "p90"
                }
            ).update_xaxes({
                "matches": None
            } if not selections["X axis matches"] else {}).update_yaxes(
                {"matches": None} if not selections["Y axis matches"] else {}))
        if selections["X Response"] not in volumemodel.hc_responses:
            figure.add_annotation(fluid_annotation(selections))

        missing_reals = [
            x for x in range(dframe["REAL"].min(), dframe["REAL"].max())
            if x not in dframe["REAL"].unique()
        ]
        if missing_reals:
            for real_range in to_ranges(missing_reals):
                figure.add_vrect(
                    x0=real_range[0] - 0.5,
                    x1=real_range[1] + 0.5,
                    fillcolor="gainsboro",
                    layer="below",
                    opacity=0.4,
                    line_width=0,
                )

        return convergence_plot_layout(figure=figure)
Example #4
0
def test_dvcv004_duplicate_outputs_across_callbacks(dash_duo):
    app = Dash(__name__)
    app.layout = html.Div(
        [html.Div(id="a"),
         html.Div(id="b"),
         html.Div(id="c")])

    @app.callback([Output("a", "children"),
                   Output("a", "style")], [Input("b", "children")])
    def x(b):
        return b, b

    @app.callback(Output("b", "children"), [Input("b", "style")])
    def y(b):
        return b

    @app.callback(Output("a", "children"), [Input("b", "children")])
    def x2(b):
        return b

    @app.callback([Output("b", "children"),
                   Output("b", "style")], [Input("c", "children")])
    def y2(c):
        return c

    @app.callback(
        [Output({"a": 1}, "children"),
         Output({
             "b": ALL,
             "c": 1
         }, "children")],
        [Input("b", "children")],
    )
    def z(b):
        return b, b

    @app.callback(
        [
            Output({"a": ALL}, "children"),
            Output({
                "b": 1,
                "c": ALL
            }, "children")
        ],
        [Input("b", "children")],
    )
    def z2(b):
        return b, b

    dash_duo.start_server(app, **debugging)

    specs = [
        [
            "Overlapping wildcard callback outputs",
            [
                # depending on the order callbacks get reported to the
                # front end, either of these could have been registered first.
                # so we use this oder-independent form that just checks for
                # both prop_id's and the string "overlaps another output"
                '({"b":1,"c":ALL}.children)',
                "overlaps another output",
                '({"b":ALL,"c":1}.children)',
                "used in a different callback.",
            ],
        ],
        [
            "Overlapping wildcard callback outputs",
            [
                '({"a":ALL}.children)',
                "overlaps another output",
                '({"a":1}.children)',
                "used in a different callback.",
            ],
        ],
        [
            "Duplicate callback outputs",
            ["Output 0 (b.children) is already in use."]
        ],
        [
            "Duplicate callback outputs",
            ["Output 0 (a.children) is already in use."]
        ],
    ]
    check_errors(dash_duo, specs)
Example #5
0
def test_dvcv010_bad_props(dash_duo):
    app = Dash(__name__)
    app.layout = html.Div(
        [
            html.Div([html.Div(id="inner-div"),
                      dcc.Input(id="inner-input")],
                     id="outer-div"),
            dcc.Input(id={"a": 1}),
        ],
        id="main",
    )

    @app.callback(
        Output("inner-div", "xyz"),
        # "data-xyz" is OK, does not give an error
        [Input("inner-input", "pdq"),
         Input("inner-div", "data-xyz")],
        [State("inner-div", "value")],
    )
    def xyz(a, b, c):
        a if b else c

    @app.callback(
        Output({"a": MATCH}, "no"),
        [Input({"a": MATCH}, "never")],
        # "boo" will not error because we don't check State MATCH/ALLSMALLER
        [State({"a": MATCH}, "boo"),
         State({"a": ALL}, "nope")],
    )
    def f(a, b, c):
        return a if b else c

    dash_duo.start_server(app, **debugging)

    specs = [
        [
            "Invalid prop for this component",
            [
                'Property "never" was used with component ID:',
                '{"a":1}',
                "in one of the Input items of a callback.",
                "This ID is assigned to a dash_core_components.Input component",
                "in the layout, which does not support this property.",
                "This ID was used in the callback(s) for Output(s):",
                '{"a":MATCH}.no',
            ],
        ],
        [
            "Invalid prop for this component",
            [
                'Property "nope" was used with component ID:',
                '{"a":1}',
                "in one of the State items of a callback.",
                "This ID is assigned to a dash_core_components.Input component",
                '{"a":MATCH}.no',
            ],
        ],
        [
            "Invalid prop for this component",
            [
                'Property "no" was used with component ID:',
                '{"a":1}',
                "in one of the Output items of a callback.",
                "This ID is assigned to a dash_core_components.Input component",
                '{"a":MATCH}.no',
            ],
        ],
        [
            "Invalid prop for this component",
            [
                'Property "pdq" was used with component ID:',
                '"inner-input"',
                "in one of the Input items of a callback.",
                "This ID is assigned to a dash_core_components.Input component",
                "inner-div.xyz",
            ],
        ],
        [
            "Invalid prop for this component",
            [
                'Property "value" was used with component ID:',
                '"inner-div"',
                "in one of the State items of a callback.",
                "This ID is assigned to a dash_html_components.Div component",
                "inner-div.xyz",
            ],
        ],
        [
            "Invalid prop for this component",
            [
                'Property "xyz" was used with component ID:',
                '"inner-div"',
                "in one of the Output items of a callback.",
                "This ID is assigned to a dash_html_components.Div component",
                "inner-div.xyz",
            ],
        ],
    ]
    check_errors(dash_duo, specs)
Example #6
0
    def set_callbacks(self, app: Dash) -> None:
        @app.callback(
            Output(self.uuid("graph"), "figure"),
            Input(self.uuid("ensemble"), "value"),
            Input(self.uuid("plot_type"), "value"),
            Input(self.uuid("n_wells"), "value"),
            Input(self.uuid("wells"), "value"),
            Input(self.uuid("sort_by"), "value"),
            Input(self.uuid("stat_bars"), "value"),
            Input(self.uuid("ascending"), "value"),
        )
        def _update_graph(
            ensemble: str,
            plot_type: str,
            n_wells: int,
            wells: Union[str, List[str]],
            sort_by: str,
            stat_bars: Union[str, List[str]],
            ascending: bool,
        ) -> dict:
            wells = wells if isinstance(wells, list) else [wells]
            stat_bars = stat_bars if isinstance(stat_bars,
                                                list) else [stat_bars]
            df = filter_df(df=self.smry, ensemble=ensemble, wells=wells)
            stat_df = (calc_statistics(df).sort_values(
                sort_by, ascending=ascending).iloc[0:n_wells, :])
            traces = []
            if plot_type == "Fan chart":
                traces.extend(
                    _get_fanchart_traces(
                        ens_stat_df=stat_df,
                        color=self.ens_colors[ensemble],
                        legend_group=ensemble,
                    ))
            elif plot_type in ["Bar chart", "Line chart"]:
                for stat in stat_bars:
                    yaxis = "y2" if stat == "count" else "y"

                    if plot_type == "Bar chart":

                        traces.append({
                            "x":
                            [vec[5:] for vec in stat_df.index],  # strip WBHP:
                            "y":
                            stat_df[stat],
                            "name": [
                                key for key, value in self.label_map.items()
                                if value == stat
                            ][0],
                            "yaxis":
                            yaxis,
                            "type":
                            "bar",
                            "offsetgroup":
                            stat,
                            "showlegend":
                            True,
                        })
                    elif plot_type == "Line chart":
                        traces.append({
                            "x":
                            [vec[5:] for vec in stat_df.index],  # strip WBHP:
                            "y":
                            stat_df[stat],
                            "name": [
                                key for key, value in self.label_map.items()
                                if value == stat
                            ][0],
                            "yaxis":
                            yaxis,
                            "type":
                            "line",
                            "offsetgroup":
                            stat,
                            "showlegend":
                            True,
                        })
                    else:
                        raise ValueError("Invalid plot type.")

            layout = self.theme.create_themed_layout({
                "yaxis": {
                    "side": "left",
                    "title": "Bottom hole pressure",
                    "showgrid": False,
                },
                "yaxis2": {
                    "side": "right",
                    "overlaying": "y",
                    "title": "Count (data points)",
                    "showgrid": False,
                },
                "xaxis": {
                    "showgrid": False
                },
                "barmode": "group",
                "legend": {
                    "x": 1.05
                },
            })
            return {"data": traces, "layout": layout}

        @app.callback(
            Output(self.uuid("select_stat"), "style"),
            Input(self.uuid("plot_type"), "value"),
        )
        def _update_stat_selector(plot_type: str) -> dict:
            return ({
                "display": "none"
            } if plot_type == "Fan chart" else {
                "display": "block"
            })
Example #7
0
def well_overview_callbacks(
    app: Dash,
    get_uuid: Callable,
    data_models: Dict[str, EnsembleWellAnalysisData],
    theme: WebvizConfigTheme,
) -> None:
    @app.callback(
        Output(get_uuid(ClientsideStoreElements.WELL_OVERVIEW_CHART_SELECTED),
               "data"),
        Input(
            {
                "id": get_uuid(WellOverviewLayoutElements.CHARTTYPE_BUTTON),
                "button": ALL,
            },
            "n_clicks",
        ),
        State(
            {
                "id": get_uuid(WellOverviewLayoutElements.CHARTTYPE_BUTTON),
                "button": ALL,
            },
            "id",
        ),
    )
    def _update_chart_selected(_apply_click: int, button_ids: list) -> str:
        """Stores the selected chart type in ClientsideStoreElements.WELL_OVERVIEW_CHART_SELECTED"""
        ctx = callback_context.triggered[0]

        # handle initial callback
        if ctx["prop_id"] == ".":
            return "bar"

        for button_id in button_ids:
            if button_id["button"] in ctx["prop_id"]:
                return button_id["button"]
        raise ValueError("Id not found")

    @callback(
        Output(
            {
                "id": get_uuid(WellOverviewLayoutElements.CHARTTYPE_BUTTON),
                "button": ALL,
            },
            "style",
        ),
        Input(get_uuid(ClientsideStoreElements.WELL_OVERVIEW_CHART_SELECTED),
              "data"),
        State(
            {
                "id": get_uuid(WellOverviewLayoutElements.CHARTTYPE_BUTTON),
                "button": ALL,
            },
            "id",
        ),
    )
    def _update_button_style(chart_selected: str, button_ids: list) -> list:
        """Updates the styling of the chart type buttons, showing which chart type
        is currently selected.
        """
        button_styles = {
            button["button"]: {
                "background-color": "#E8E8E8"
            }
            for button in button_ids
        }
        button_styles[chart_selected] = {
            "background-color": "#7393B3",
            "color": "#fff"
        }

        return update_relevant_components(
            id_list=button_ids,
            update_info=[{
                "new_value": style,
                "conditions": {
                    "button": button
                },
            } for button, style in button_styles.items()],
        )

    @callback(
        Output(
            {
                "id": get_uuid(WellOverviewLayoutElements.CHARTTYPE_SETTINGS),
                "charttype": ALL,
            },
            "style",
        ),
        Input(get_uuid(ClientsideStoreElements.WELL_OVERVIEW_CHART_SELECTED),
              "data"),
        State(
            {
                "id": get_uuid(WellOverviewLayoutElements.CHARTTYPE_SETTINGS),
                "charttype": ALL,
            },
            "id",
        ),
    )
    def _display_charttype_settings(chart_selected: str,
                                    charttype_settings_ids: list) -> list:
        """Display only the settings relevant for the currently selected chart type."""
        return [{
            "display": "block"
        } if settings_id["charttype"] == chart_selected else {
            "display": "none"
        } for settings_id in charttype_settings_ids]

    @app.callback(
        Output(get_uuid(WellOverviewLayoutElements.GRAPH_FRAME), "children"),
        Input(get_uuid(WellOverviewLayoutElements.ENSEMBLES), "value"),
        Input(
            {
                "id": get_uuid(WellOverviewLayoutElements.CHARTTYPE_CHECKLIST),
                "charttype": ALL,
            },
            "value",
        ),
        Input(get_uuid(WellOverviewLayoutElements.SUMVEC), "value"),
        Input(get_uuid(ClientsideStoreElements.WELL_OVERVIEW_CHART_SELECTED),
              "data"),
        Input(get_uuid(WellOverviewLayoutElements.WELL_FILTER), "value"),
        State(
            {
                "id": get_uuid(WellOverviewLayoutElements.CHARTTYPE_CHECKLIST),
                "charttype": ALL,
            },
            "id",
        ),
        State(get_uuid(WellOverviewLayoutElements.GRAPH), "figure"),
    )
    def _update_graph(
        ensembles: List[str],
        checklist_values: List[List[str]],
        sumvec: str,
        chart_selected: str,
        wells_selected: List[str],
        checklist_ids: List[Dict[str, str]],
        current_fig_dict: dict,
    ) -> List[wcc.Graph]:
        """Updates the well overview graph with selected input (f.ex chart type)"""
        ctx = callback_context.triggered[0]["prop_id"].split(".")[0]

        settings = {
            checklist_id["charttype"]: checklist_values[i]
            for i, checklist_id in enumerate(checklist_ids)
        }

        # If the event is a plot settings event, then we only update the formatting
        # and not the figure data
        if current_fig_dict is not None and is_plot_settings_event(
                ctx, get_uuid):
            fig_dict = format_well_overview_figure(
                go.Figure(current_fig_dict),
                chart_selected,
                settings[chart_selected],
                sumvec,
            )
        else:
            figure = WellOverviewFigure(
                ensembles,
                data_models,
                sumvec,
                chart_selected,
                wells_selected,
                theme,
            )

            fig_dict = format_well_overview_figure(figure.figure,
                                                   chart_selected,
                                                   settings[chart_selected],
                                                   sumvec)

        return [
            wcc.Graph(
                id=get_uuid(WellOverviewLayoutElements.GRAPH),
                style={"height": "87vh"},
                figure=fig_dict,
            )
        ]
def layout_controllers(get_uuid: Callable) -> None:
    @callback(
        Output(get_uuid("page-selected"), "data"),
        Output(get_uuid("voldist-page-selected"), "data"),
        Input({
            "id": get_uuid("selections"),
            "button": ALL
        }, "n_clicks"),
        Input(get_uuid("tabs"), "value"),
        State({
            "id": get_uuid("selections"),
            "button": ALL
        }, "id"),
        State(get_uuid("voldist-page-selected"), "data"),
    )
    def _selected_page_controllers(
        _apply_click: int,
        tab_selected: str,
        button_ids: list,
        previous_page: dict,
    ) -> tuple:

        ctx = callback_context.triggered[0]
        initial_pages = {"voldist": "custom", "tornado": "torn_multi"}

        # handle initial callback
        if ctx["prop_id"] == ".":
            page_selected = (tab_selected if not tab_selected in initial_pages
                             else initial_pages[tab_selected])
            previous_page = initial_pages

        elif "tabs" in ctx["prop_id"]:
            page_selected = (tab_selected if not tab_selected in initial_pages
                             else previous_page[tab_selected])
            previous_page = no_update

        else:
            for button_id in button_ids:
                if button_id["button"] in ctx["prop_id"]:
                    page_selected = previous_page[tab_selected] = button_id[
                        "button"]

        return page_selected, previous_page

    @callback(
        Output({
            "id": get_uuid("selections"),
            "button": ALL
        }, "style"),
        Input(get_uuid("page-selected"), "data"),
        State(get_uuid("tabs"), "value"),
        State({
            "id": get_uuid("selections"),
            "button": ALL
        }, "id"),
    )
    def _update_button_style(page_selected: str, tab_selected: str,
                             button_ids: list) -> list:

        if tab_selected not in ["voldist", "tornado"]:
            raise PreventUpdate

        button_styles = {
            button["button"]: {
                "background-color": "#E8E8E8"
            }
            for button in button_ids
        }
        button_styles[page_selected] = {
            "background-color": "#7393B3",
            "color": "#fff"
        }

        return update_relevant_components(
            id_list=button_ids,
            update_info=[{
                "new_value": style,
                "conditions": {
                    "button": button
                },
            } for button, style in button_styles.items()],
        )

    @callback(
        Output({
            "id": get_uuid("main-voldist"),
            "page": ALL
        }, "style"),
        Input(get_uuid("page-selected"), "data"),
        State({
            "id": get_uuid("main-voldist"),
            "page": ALL
        }, "id"),
        State(get_uuid("tabs"), "value"),
    )
    def _main_voldist_display(
        page_selected: str,
        main_layout_ids: list,
        tab_selected: str,
    ) -> list:

        if tab_selected != "voldist":
            raise PreventUpdate

        voldist_layout = []
        for page_id in main_layout_ids:
            if page_id["page"] == page_selected:
                voldist_layout.append({"display": "block"})
            else:
                voldist_layout.append({"display": "none"})
        return voldist_layout

    @callback(
        Output({
            "id": get_uuid("main-tornado"),
            "page": ALL
        }, "style"),
        Input(get_uuid("page-selected"), "data"),
        State({
            "id": get_uuid("main-tornado"),
            "page": ALL
        }, "id"),
        State(get_uuid("tabs"), "value"),
    )
    def _main_tornado_display(
        page_selected: str,
        main_layout_ids: list,
        tab_selected: str,
    ) -> list:

        if tab_selected != "tornado":
            raise PreventUpdate

        main_layout = []
        for page_id in main_layout_ids:
            if page_id["page"] == page_selected:
                main_layout.append({"display": "block"})
            else:
                main_layout.append({"display": "none"})
        return main_layout
Example #9
0
def fipfile_qc_controller(get_uuid: Callable,
                          disjoint_set_df: pd.DataFrame) -> None:
    @callback(
        Output(get_uuid("main-fipqc"), "children"),
        Input(get_uuid("selections"), "data"),
        Input({
            "id": get_uuid("main-fipqc"),
            "element": "display-option"
        }, "value"),
        State(get_uuid("page-selected"), "data"),
    )
    def _update_page_fipfileqc(selections: dict, display_option: str,
                               page_selected: str) -> html.Div:
        ctx = callback_context.triggered[0]

        if page_selected != "fipqc":
            raise PreventUpdate

        df = disjoint_set_df[["SET", "FIPNUM", "REGION", "ZONE", "REGZONE"]]

        selections = selections[page_selected]
        if not "display-option" in ctx["prop_id"]:
            if not selections["update"]:
                raise PreventUpdate

        for filt, values in selections["filters"].items():
            df = df.loc[df[filt].isin(values)]

        if selections["Group table"] and display_option == "table":
            df["FIPNUM"] = df["FIPNUM"].astype(str)
            df = df.groupby(["SET"
                             ]).agg(lambda x: ", ".join(set(x))).reset_index()

        df = df.sort_values(by=["SET"])

        if display_option == "table":
            return html.Div(children=create_data_table(
                columns=create_table_columns(df.columns),
                data=df.to_dict("records"),
                height="82vh",
                table_id={"table_id": "disjointset-info"},
                style_cell_conditional=[
                    {
                        "if": {
                            "column_id": ["SET", "FIPNUM"]
                        },
                        "width": "10%"
                    },
                    {
                        "if": {
                            "column_id": ["ZONE", "REGION"]
                        },
                        "width": "20%"
                    },
                ],
                style_cell={
                    "whiteSpace": "normal",
                    "textAlign": "left",
                    "height": "auto",
                },
            ), )

        df["FIPNUM"] = df["FIPNUM"].astype(str)
        return html.Div([
            create_heatmap(df=df, y="ZONE", x="REGION"),
            create_heatmap(df=df, y="ZONE", x="FIPNUM"),
            create_heatmap(df=df, y="REGION", x="FIPNUM"),
        ])
Example #10
0
import dash_bootstrap_components as dbc
from dash import Input, Output

input_group = dbc.InputGroup([
    dbc.Button("Random name", id="input-group-button", n_clicks=0),
    dbc.Input(id="input-group-button-input", placeholder="name"),
])


@app.callback(
    Output("input-group-button-input", "value"),
    [Input("input-group-button", "n_clicks")],
)
def on_button_click(n_clicks):
    if n_clicks:
        names = ["Arthur Dent", "Ford Prefect", "Trillian Astra"]
        which = n_clicks % len(names)
        return names[which]
    else:
        return ""
        html.Div(
            id="toast-container",
            style={
                "position": "fixed",
                "top": 10,
                "right": 10,
                "width": 350
            },
        ),
    ],
    className="p-5",
)


@app.callback(
    Output("message-store", "data"),
    [
        Input("button", "n_clicks"),
        Input({
            "type": "toast",
            "id": ALL
        }, "n_dismiss"),
    ],
    [State("message-store", "data")],
)
def manage_store(n, dismissed_toast, store):
    """
    This callback manages the message store. If the "generate" button is
    clicked we add an item to the store. If one of the toasts is dismissed we
    remove the corresponding item from the store. To figure out which of these
    happened, we use callback context.
Example #12
0
        html.Br(),
    ],
             className='one columns'),
    html.Div(children=[
        html.H3('NETWORK DIAGRAM'),
        dcc.Graph(id='Graph', figure=network_graph(df)),
        html.Br(),
    ],
             className='ten columns'),
],
                      className='row')


# Callback for adding the all check
@app.callback(
    Output('port-checklist', 'value'),
    Output('all-checklist', 'value'),
    Input('port-checklist', 'value'),
    Input('all-checklist', 'value'),
)
def sync_checklists(ports_selected, all_selected):
    ctx = callback_context
    input_id = ctx.triggered[0]['prop_id'].split('.')[0]
    if input_id == 'port-checklist':
        all_selected = ['All'] if set(ports_selected) == set(all_ports) else []
    else:
        ports_selected = all_ports if all_selected else []
    return ports_selected, all_selected


# Callback to update the graph according to the checklist
                ),
            ],
            id="modal-body-scroll",
            scrollable=True,
            is_open=False,
        ),
    ]
)


def toggle_modal(n1, n2, is_open):
    if n1 or n2:
        return not is_open
    return is_open


app.callback(
    Output("modal-scroll", "is_open"),
    [Input("open-scroll", "n_clicks"), Input("close-scroll", "n_clicks")],
    [State("modal-scroll", "is_open")],
)(toggle_modal)

app.callback(
    Output("modal-body-scroll", "is_open"),
    [
        Input("open-body-scroll", "n_clicks"),
        Input("close-body-scroll", "n_clicks"),
    ],
    [State("modal-body-scroll", "is_open")],
)(toggle_modal)
Example #14
0
 def osi_reset_button_pressed(self):
     return (
         Output(self.dashboard_home.confirm_reset_dialogue, "displayed"),
         Input(self.dashboard_home.reset_button, "n_clicks"),
     )
Example #15
0
    ),
    ctl.H2("Boolean input"),
    bool_input,
    ctl.H2("Matrix input"),
    matrix_input,
    ctl.H2("Slider input"),
    slider_input,
    ctl.H2("Dynamic inputs"),
    ctl.Button("Generate inputs", id="generate-inputs"),
    html.Div(id="dynamic-inputs"),
    ctl.H1("Output"),
    html.Span(id="output"),
])


@app.callback(Output("output", "children"),
              Input(your_component.get_all_kwargs_id(), "value"))
def show_outputs(*args):

    kwargs = your_component.reconstruct_kwargs_from_state()

    return str(kwargs)


@app.callback(Output("dynamic-inputs", "children"),
              Input("generate-inputs", "n_clicks"))
def add_inputs(n_clicks):

    if not n_clicks:
        raise PreventUpdate
Example #16
0
            ),
            md={
                "size": 12,
                "offset": 0
            },
            lg={
                "size": 10,
                "offset": 1
            },
        )),
])


@callback(
    [
        Output("btn-add-schedule", "hidden"),
        Output("btn-remove-schedule", "hidden"),
        Output("btn-add-schedule", "n_clicks"),
        Output("btn-remove-schedule", "n_clicks"),
    ],
    [
        Input("btn-add-schedule", "n_clicks"),
        Input("btn-remove-schedule", "n_clicks"),
        Input("btn-start-scanning", "n_clicks"),
    ],
)
def btn_schedule_click(add_click, remove_click, open_click):
    """Add scanner/screen schedule"""
    if add_click > 0:
        tg_wrapper._handler._check_scheduled_job()
        return True, False, 0, 0
Example #17
0
    def set_callbacks(self, app):
        @app.callback(
            Output(self.uuid("parcoords"), "figure"),
            self.parcoord_inputs,
        )
        def _update_parcoord(ens, exc_inc, parameter_list, *opt_args):
            """Updates parallel coordinates plot
            Filter dataframe for chosen ensembles and parameters
            Call render_parcoord to render new figure
            """
            # Ensure selected ensembles is a list
            ens = ens if isinstance(ens, list) else [ens]
            # Ensure selected parameters is a list
            parameter_list = (parameter_list if isinstance(
                parameter_list, list) else [parameter_list])
            special_columns = ["ENSEMBLE", "REAL"]
            if exc_inc == "exc":
                parameterdf = self.parameterdf.drop(parameter_list, axis=1)
            elif exc_inc == "inc":
                parameterdf = self.parameterdf[special_columns +
                                               parameter_list]
            params = [
                param for param in parameterdf.columns
                if param not in special_columns
                and param in self.parameter_columns
            ]

            mode = opt_args[0] if opt_args else "ensemble"
            # Need a default response
            response = ""

            if mode == "response":
                if len(ens) != 1:
                    # Need to wait for update of ensemble selector to multi=False
                    raise PreventUpdate
                df = parameterdf.loc[self.parameterdf["ENSEMBLE"] == ens[0]]
                response = opt_args[1]
                response_filter_values = opt_args[2:] if len(
                    opt_args) > 2 else {}
                filteroptions = parresp.make_response_filters(
                    response_filters=self.response_filters,
                    response_filter_values=response_filter_values,
                )
                responsedf = parresp.filter_and_sum_responses(
                    self.responsedf,
                    ens[0],
                    response,
                    filteroptions=filteroptions,
                    aggregation=self.aggregation,
                )

                # Renaming to make it clear in plot.
                responsedf.rename(columns={response: f"Response: {response}"},
                                  inplace=True)
                df = pd.merge(responsedf, df,
                              on=["REAL"]).drop(columns=special_columns)
                df[self.uuid("COLOR")] = df.apply(
                    lambda row: self.ensembles.index(ens[0]), axis=1)
            else:
                # Filter on ensembles (ens) and active parameters (params),
                # adding the COLOR column to the columns to keep
                df = self.parameterdf[self.parameterdf["ENSEMBLE"].isin(ens)][
                    params + ["ENSEMBLE"]]
                df[self.uuid("COLOR")] = df.apply(
                    lambda row: self.ensembles.index(row["ENSEMBLE"]), axis=1)
            return render_parcoord(
                df,
                self.theme,
                self.ens_colormap,
                self.uuid("COLOR"),
                self.ensembles,
                mode,
                params,
                response,
            )

        @app.callback(
            [
                Output(self.uuid("ensembles"), "multi"),
                Output(self.uuid("ensembles"), "value"),
                Output(self.uuid("view_response"), "style"),
            ],
            [Input(self.uuid("mode"), "value")],
        )
        def _update_mode(mode: str):
            if mode == "ensemble":
                return True, self.ensembles, {"display": "none"}
            if mode == "response":
                return False, self.ensembles[0], {"display": "block"}
            # The error should never occur
            raise ValueError("ensemble and response are the only valid modes.")
Example #18
0
from dash import Dash, dcc, html, Input, Output

import dash_bootstrap_components as dbc

app = Dash(__name__)# external_stylesheets=[dbc.themes.BOOTSTRAP]

app.layout = html.Div([
    html.H6("Change the value in the text box to see callbacks in action!"),
    html.Div([
        "Input: ",
        dcc.Dropdown(['New York City', 'Montréal', 'San Francisco'], 'Montréal',id='my-input')
    ]),
    #html.Br(),
    html.Div(id='my-output'),

])


@app.callback(
    Output(component_id='my-output', component_property='children'),
    Input(component_id='my-input', component_property='value')
)
def update_output_div(input_value):
    return f'Output: {input_value}'


if __name__ == '__main__':
    app.run_server(debug=True)
Example #19
0
def plugin_callbacks(
    get_uuid: Callable,
    ensemble_surface_providers: Dict[str, EnsembleSurfaceProvider],
    surface_server: SurfaceServer,
    ensemble_fault_polygons_providers: Dict[str,
                                            EnsembleFaultPolygonsProvider],
    fault_polygons_server: FaultPolygonsServer,
    map_surface_names_to_fault_polygons: Dict[str, str],
    well_picks_provider: Optional[WellPickProvider],
    fault_polygon_attribute: Optional[str],
) -> None:
    def selections(tab: str, colorselector: bool = False) -> Dict[str, str]:
        uuid = get_uuid(LayoutElements.SELECTIONS if not colorselector else
                        LayoutElements.COLORSELECTIONS)
        return {"view": ALL, "id": uuid, "tab": tab, "selector": ALL}

    def selector_wrapper(tab: str,
                         colorselector: bool = False) -> Dict[str, str]:
        uuid = get_uuid(LayoutElements.WRAPPER
                        if not colorselector else LayoutElements.COLORWRAPPER)
        return {"id": uuid, "tab": tab, "selector": ALL}

    def links(tab: str, colorselector: bool = False) -> Dict[str, str]:
        uuid = get_uuid(LayoutElements.LINK
                        if not colorselector else LayoutElements.COLORLINK)
        return {"id": uuid, "tab": tab, "selector": ALL}

    @callback(
        Output(get_uuid(LayoutElements.OPTIONS_DIALOG), "open"),
        Input({
            "id": get_uuid("Button"),
            "tab": ALL
        }, "n_clicks"),
        State(get_uuid(LayoutElements.OPTIONS_DIALOG), "open"),
    )
    def open_close_options_dialog(_n_click: list, is_open: bool) -> bool:
        if any(click is not None for click in _n_click):
            return not is_open
        raise PreventUpdate

    # 2nd callback
    @callback(
        Output({
            "id": get_uuid(LayoutElements.LINKED_VIEW_DATA),
            "tab": MATCH
        }, "data"),
        Output(selector_wrapper(MATCH), "children"),
        Input(selections(MATCH), "value"),
        Input({
            "id": get_uuid(LayoutElements.VIEWS),
            "tab": MATCH
        }, "value"),
        Input({
            "id": get_uuid(LayoutElements.MULTI),
            "tab": MATCH
        }, "value"),
        Input(links(MATCH), "value"),
        Input(get_uuid(LayoutElements.REALIZATIONS_FILTER), "value"),
        Input(get_uuid("tabs"), "value"),
        State(selections(MATCH), "id"),
        State(selector_wrapper(MATCH), "id"),
    )
    def _update_components_and_selected_data(
        mapselector_values: List[Dict[str, Any]],
        number_of_views: int,
        multi_selector: str,
        selectorlinks: List[List[str]],
        filtered_reals: List[int],
        tab_name: str,
        selector_ids: List[dict],
        wrapper_ids: List[dict],
    ) -> Tuple[List[dict], list]:
        """Reads stored raw selections, stores valid selections as a dcc.Store
        and updates visible and valid selections in layout"""

        # Prevent update if the pattern matched components does not match the current tab
        datatab = wrapper_ids[0]["tab"]
        if datatab != tab_name or number_of_views is None:
            raise PreventUpdate

        ctx = callback_context.triggered[0]["prop_id"]

        selector_values = []
        for idx in range(number_of_views):
            view_selections = combine_selector_values_and_name(
                mapselector_values, selector_ids, view=idx)
            view_selections["multi"] = multi_selector
            if tab_name == Tabs.STATS:
                view_selections[
                    "mode"] = DefaultSettings.VIEW_LAYOUT_STATISTICS_TAB[idx]
            selector_values.append(view_selections)

        linked_selector_names = [l[0] for l in selectorlinks if l]

        component_properties = _update_selector_component_properties_from_provider(
            selector_values=selector_values,
            linked_selectors=linked_selector_names,
            multi=multi_selector,
            multi_in_ctx=get_uuid(LayoutElements.MULTI) in ctx,
            filtered_realizations=filtered_reals,
        )
        # retrive the updated selector values from the component properties
        selector_values = [{key: val["value"]
                            for key, val in data.items()}
                           for idx, data in enumerate(component_properties)]

        if multi_selector is not None:
            selector_values = update_selections_with_multi(
                selector_values, multi_selector)
        selector_values = remove_data_if_not_valid(selector_values)
        if tab_name == Tabs.DIFF and len(selector_values) == 2:
            selector_values = add_diff_surface_to_values(selector_values)

        return (
            selector_values,
            [
                SideBySideSelectorFlex(
                    tab_name,
                    get_uuid,
                    selector=id_val["selector"],
                    view_data=[
                        data[id_val["selector"]]
                        for data in component_properties
                    ],
                    link=id_val["selector"] in linked_selector_names,
                    dropdown=id_val["selector"] in ["ensemble", "mode"],
                ) for id_val in wrapper_ids
            ],
        )

    # 3rd callback
    @callback(
        Output(
            {
                "id": get_uuid(LayoutElements.VERIFIED_VIEW_DATA),
                "tab": MATCH
            }, "data"),
        Output(selector_wrapper(MATCH, colorselector=True), "children"),
        Input({
            "id": get_uuid(LayoutElements.LINKED_VIEW_DATA),
            "tab": MATCH
        }, "data"),
        Input(selections(MATCH, colorselector=True), "value"),
        Input(
            {
                "view": ALL,
                "id": get_uuid(LayoutElements.RANGE_RESET),
                "tab": MATCH
            },
            "n_clicks",
        ),
        Input(links(MATCH, colorselector=True), "value"),
        State({
            "id": get_uuid(LayoutElements.MULTI),
            "tab": MATCH
        }, "value"),
        State(selector_wrapper(MATCH, colorselector=True), "id"),
        State(get_uuid(LayoutElements.STORED_COLOR_SETTINGS), "data"),
        State(get_uuid("tabs"), "value"),
        State(selections(MATCH, colorselector=True), "id"),
    )
    def _update_color_components_and_value(
        selector_values: List[dict],
        colorvalues: List[Dict[str, Any]],
        _n_click: int,
        colorlinks: List[List[str]],
        multi: str,
        color_wrapper_ids: List[dict],
        stored_color_settings: Dict,
        tab: str,
        colorval_ids: List[dict],
    ) -> Tuple[List[dict], list]:
        """Adds color settings to validated stored selections, updates color component in layout
        and writes validated selectors with colors to a dcc.Store"""
        ctx = callback_context.triggered[0]["prop_id"]

        if selector_values is None:
            raise PreventUpdate

        reset_color_index = (json.loads(ctx.split(".")[0])["view"] if get_uuid(
            LayoutElements.RANGE_RESET) in ctx else None)
        color_update_index = (json.loads(ctx.split(".")[0]).get("view") if
                              LayoutElements.COLORSELECTIONS in ctx else None)

        # if a selector is set as multi in the "Maps per Selector" tab
        # color_range should be linked and the min and max surface ranges
        # from all the views should be used as range
        use_range_from_all = tab == Tabs.SPLIT and multi != "attribute"

        links = [l[0] for l in colorlinks if l]
        links = links if not use_range_from_all else links + ["color_range"]

        # update selector_values with current values from the color components
        for idx, data in enumerate(selector_values):
            data.update(
                combine_selector_values_and_name(colorvalues,
                                                 colorval_ids,
                                                 view=idx))
        color_component_properties = _update_color_component_properties(
            values=selector_values,
            links=links if not use_range_from_all else links + ["color_range"],
            stored_color_settings=stored_color_settings,
            reset_color_index=reset_color_index,
            color_update_index=color_update_index,
        )

        if use_range_from_all:
            ranges = [data["surface_range"] for data in selector_values]
            min_max_for_all = [
                min(r[0] for r in ranges),
                max(r[1] for r in ranges)
            ]
            for data in color_component_properties:
                data["color_range"]["range"] = min_max_for_all
                if reset_color_index is not None:
                    data["color_range"]["value"] = min_max_for_all

        for idx, data in enumerate(color_component_properties):
            for key, val in data.items():
                selector_values[idx][key] = val["value"]

        return (
            selector_values,
            [
                SideBySideSelectorFlex(
                    tab,
                    get_uuid,
                    selector=id_val["selector"],
                    view_data=[
                        data[id_val["selector"]]
                        for data in color_component_properties
                    ],
                    link=id_val["selector"] in links,
                    dropdown=id_val["selector"] in ["colormap"],
                ) for id_val in color_wrapper_ids
            ],
        )

    # 4th callback
    @callback(
        Output(get_uuid(LayoutElements.STORED_COLOR_SETTINGS), "data"),
        Input({
            "id": get_uuid(LayoutElements.VERIFIED_VIEW_DATA),
            "tab": ALL
        }, "data"),
        State(get_uuid("tabs"), "value"),
        State(get_uuid(LayoutElements.STORED_COLOR_SETTINGS), "data"),
        State({
            "id": get_uuid(LayoutElements.VERIFIED_VIEW_DATA),
            "tab": ALL
        }, "id"),
    )
    def _update_color_store(
        selector_values: List[List[dict]],
        tab: str,
        stored_color_settings: Dict[str, dict],
        data_id: List[dict],
    ) -> Dict[str, dict]:
        """Update the color store with chosen color range and colormap for surfaces"""
        if selector_values is None:
            raise PreventUpdate
        index = [x["tab"] for x in data_id].index(tab)

        stored_color_settings = (stored_color_settings
                                 if stored_color_settings is not None else {})
        for data in selector_values[index]:
            surfaceid = (get_surface_id_for_diff_surf(selector_values[index])
                         if data.get("surf_type") == "diff" else
                         get_surface_id_from_data(data))
            stored_color_settings[surfaceid] = {
                "colormap": data["colormap"],
                "color_range": data["color_range"],
            }

        return stored_color_settings

    # 5th callback
    @callback(
        Output({
            "id": get_uuid(LayoutElements.DECKGLMAP),
            "tab": MATCH
        }, "layers"),
        Output({
            "id": get_uuid(LayoutElements.DECKGLMAP),
            "tab": MATCH
        }, "bounds"),
        Output({
            "id": get_uuid(LayoutElements.DECKGLMAP),
            "tab": MATCH
        }, "views"),
        Input({
            "id": get_uuid(LayoutElements.VERIFIED_VIEW_DATA),
            "tab": MATCH
        }, "data"),
        Input(get_uuid(LayoutElements.WELLS), "value"),
        Input(get_uuid(LayoutElements.VIEW_COLUMNS), "value"),
        Input(get_uuid(LayoutElements.OPTIONS), "value"),
        State(get_uuid("tabs"), "value"),
        State({
            "id": get_uuid(LayoutElements.MULTI),
            "tab": MATCH
        }, "value"),
    )
    def _update_map(
        surface_elements: List[dict],
        selected_wells: List[str],
        view_columns: Optional[int],
        options: List[str],
        tab_name: str,
        multi: str,
    ) -> tuple:
        """Updates the map component with the stored, validated selections"""

        # Prevent update if the pattern matched components does not match the current tab
        state_list = callback_context.states_list
        if state_list[1]["id"]["tab"] != tab_name or surface_elements is None:
            raise PreventUpdate

        if tab_name == Tabs.DIFF:
            view_columns = 3 if view_columns is None else view_columns

        layers = update_map_layers(
            views=len(surface_elements),
            include_well_layer=well_picks_provider is not None,
            visible_well_layer=LayoutLabels.SHOW_WELLS in options,
            visible_fault_polygons_layer=LayoutLabels.SHOW_FAULTPOLYGONS
            in options,
            visible_hillshading_layer=LayoutLabels.SHOW_HILLSHADING in options,
        )
        layer_model = DeckGLMapLayersModel(layers)

        for idx, data in enumerate(surface_elements):
            diff_surf = data.get("surf_type") == "diff"
            surf_meta, img_url = (
                get_surface_metadata_and_image(data) if not diff_surf else
                get_surface_metadata_and_image_for_diff_surface(
                    surface_elements))
            viewport_bounds = [
                surf_meta.x_min,
                surf_meta.y_min,
                surf_meta.x_max,
                surf_meta.y_max,
            ]

            # Map3DLayer currently not implemented. Will replace
            # ColormapLayer and HillshadingLayer
            # layer_data = {
            #     "mesh": img_url,
            #     "propertyTexture": img_url,
            #     "bounds": surf_meta.deckgl_bounds,
            #     "rotDeg": surf_meta.deckgl_rot_deg,
            #     "meshValueRange": [surf_meta.val_min, surf_meta.val_max],
            #     "propertyValueRange": [surf_meta.val_min, surf_meta.val_max],
            #     "colorMapName": data["colormap"],
            #     "colorMapRange": data["color_range"],
            # }

            # layer_model.update_layer_by_id(
            #     layer_id=f"{LayoutElements.MAP3D_LAYER}-{idx}",
            #     layer_data=layer_data,
            # )
            layer_data = {
                "image": img_url,
                "bounds": surf_meta.deckgl_bounds,
                "rotDeg": surf_meta.deckgl_rot_deg,
                "valueRange": [surf_meta.val_min, surf_meta.val_max],
            }
            layer_model.update_layer_by_id(
                layer_id=f"{LayoutElements.COLORMAP_LAYER}-{idx}",
                layer_data=layer_data,
            )

            layer_model.update_layer_by_id(
                layer_id=f"{LayoutElements.HILLSHADING_LAYER}-{idx}",
                layer_data=layer_data,
            )
            layer_model.update_layer_by_id(
                layer_id=f"{LayoutElements.COLORMAP_LAYER}-{idx}",
                layer_data={
                    "colorMapName": data["colormap"],
                    "colorMapRange": data["color_range"],
                },
            )
            if (LayoutLabels.SHOW_FAULTPOLYGONS in options
                    and fault_polygon_attribute is not None):
                # if diff surface use polygons from first view
                data_for_faultpolygons = data if not diff_surf else surface_elements[
                    0]
                fault_polygons_provider = ensemble_fault_polygons_providers[
                    data_for_faultpolygons["ensemble"][0]]
                horizon_name = data_for_faultpolygons["name"][0]
                fault_polygons_address = SimulatedFaultPolygonsAddress(
                    attribute=fault_polygon_attribute,
                    name=map_surface_names_to_fault_polygons.get(
                        horizon_name, horizon_name),
                    realization=int(data_for_faultpolygons["realizations"][0]),
                )
                layer_model.update_layer_by_id(
                    layer_id=f"{LayoutElements.FAULTPOLYGONS_LAYER}-{idx}",
                    layer_data={
                        "data":
                        fault_polygons_server.encode_partial_url(
                            provider_id=fault_polygons_provider.provider_id(),
                            fault_polygons_address=fault_polygons_address,
                        ),
                    },
                )
            if LayoutLabels.SHOW_WELLS in options and well_picks_provider is not None:
                horizon_name = (data["name"][0] if not diff_surf else
                                surface_elements[0]["name"][0])
                layer_model.update_layer_by_id(
                    layer_id=f"{LayoutElements.WELLS_LAYER}-{idx}",
                    layer_data={
                        "data":
                        well_picks_provider.get_geojson(
                            selected_wells, horizon_name)
                    },
                )
        return (
            layer_model.layers,
            viewport_bounds if surface_elements else no_update,
            {
                "layout":
                view_layout(len(surface_elements), view_columns),
                "showLabel":
                True,
                "viewports": [
                    {
                        "id":
                        f"{view}_view",
                        "show3D":
                        False,
                        "layerIds": [
                            # f"{LayoutElements.MAP3D_LAYER}-{view}",
                            f"{LayoutElements.COLORMAP_LAYER}-{view}",
                            f"{LayoutElements.HILLSHADING_LAYER}-{view}",
                            f"{LayoutElements.FAULTPOLYGONS_LAYER}-{view}",
                            f"{LayoutElements.WELLS_LAYER}-{view}",
                        ],
                        "name":
                        make_viewport_label(surface_elements[view], tab_name,
                                            multi),
                    } for view in range(len(surface_elements))
                ],
            },
        )

    def make_viewport_label(data: dict, tab: str, multi: Optional[str]) -> str:
        """Return text-label for each viewport based on which tab is selected"""
        # For the difference view
        if tab == Tabs.DIFF and data.get("surf_type") == "diff":
            return "Difference Map (View1 - View2)"

        # For the statistics view 'mode' is used as label
        if tab == Tabs.STATS:
            if data["mode"] == SurfaceMode.REALIZATION:
                return f"REAL {data['realizations'][0]}"
            return data["mode"]

        # For the "map per selector" the chosen multi selector is used as label
        if tab == Tabs.SPLIT:
            if multi == "realizations":
                return f"REAL {data['realizations'][0]}"
            return data[multi][0] if multi == "mode" else data[multi]

        return general_label(data)

    def general_label(data: dict) -> str:
        """Create a general map label with all available information"""
        surfaceid = [
            data["ensemble"][0], data["attribute"][0], data["name"][0]
        ]
        if data["date"]:
            surfaceid.append(data["date"][0])
        if data["mode"] != SurfaceMode.REALIZATION:
            surfaceid.append(data["mode"])
        else:
            surfaceid.append(f"REAL {data['realizations'][0]}")
        return " ".join(surfaceid)

    # pylint: disable=too-many-branches
    def _update_selector_component_properties_from_provider(
        selector_values: List[dict],
        linked_selectors: List[str],
        multi: str,
        multi_in_ctx: bool,
        filtered_realizations: List[int],
    ) -> List[Dict[str, dict]]:
        """Return updated options and values for the different selector components using
        the provider. If current selected value for a selector is in the options it will
        be used as the new value"""
        view_data = []
        for idx, data in enumerate(selector_values):

            if not ("ensemble" in linked_selectors and idx > 0):
                ensembles = list(ensemble_surface_providers.keys())
                ensemble = data.get("ensemble", [])
                ensemble = [ensemble] if isinstance(ensemble,
                                                    str) else ensemble
                if not ensemble or multi_in_ctx:
                    ensemble = ensembles if multi == "ensemble" else ensembles[:
                                                                               1]

            if not ("attribute" in linked_selectors and idx > 0):
                attributes = []
                for ens in ensemble:
                    provider = ensemble_surface_providers[ens]
                    attributes.extend([
                        x for x in provider.attributes() if x not in attributes
                    ])
                    # only show attributes with date when multi is set to date
                    if multi == "date":
                        attributes = [
                            x for x in attributes
                            if attribute_has_date(x, provider)
                        ]

                attribute = [
                    x for x in data.get("attribute", []) if x in attributes
                ]
                if not attribute or multi_in_ctx:
                    attribute = attributes if multi == "attribute" else attributes[:
                                                                                   1]

            if not ("name" in linked_selectors and idx > 0):
                names = []
                for ens in ensemble:
                    provider = ensemble_surface_providers[ens]
                    for attr in attribute:
                        attr_names = provider.surface_names_for_attribute(attr)
                        names.extend([x for x in attr_names if x not in names])

                name = [x for x in data.get("name", []) if x in names]
                if not name or multi_in_ctx:
                    name = names if multi == "name" else names[:1]

            if not ("date" in linked_selectors and idx > 0):
                dates = []
                for ens in ensemble:
                    provider = ensemble_surface_providers[ens]
                    for attr in attribute:
                        attr_dates = provider.surface_dates_for_attribute(attr)

                        if attr_dates is not None:
                            dates.extend(
                                [x for x in attr_dates if x not in dates])

                interval_dates = [x for x in dates if "_" in x]
                dates = [x for x in dates if x not in interval_dates
                         ] + interval_dates

                date = [x for x in data.get("date", []) if x in dates]
                if not date or multi_in_ctx:
                    date = dates if multi == "date" else dates[:1]

            if not ("mode" in linked_selectors and idx > 0):
                modes = list(SurfaceMode)
                mode = data.get("mode", SurfaceMode.REALIZATION)

            if not ("realizations" in linked_selectors and idx > 0):
                if mode == SurfaceMode.REALIZATION:
                    real = data.get("realizations", [])
                    if not real or real[0] not in filtered_realizations:
                        real = filtered_realizations[:1]
                else:
                    real = filtered_realizations

            view_data.append({
                "ensemble": {
                    "value": ensemble,
                    "options": ensembles,
                    "multi": multi == "ensemble",
                },
                "attribute": {
                    "value": attribute,
                    "options": attributes,
                    "multi": multi == "attribute",
                },
                "name": {
                    "value": name,
                    "options": names,
                    "multi": multi == "name"
                },
                "date": {
                    "value": date,
                    "options": dates,
                    "multi": multi == "date"
                },
                "mode": {
                    "value": mode,
                    "options": modes
                },
                "realizations": {
                    "value":
                    real,
                    "disabled":
                    mode != SurfaceMode.REALIZATION,
                    "options":
                    filtered_realizations,
                    "multi":
                    mode != SurfaceMode.REALIZATION or multi == "realizations",
                },
            })

        return view_data

    def _update_color_component_properties(
        values: List[dict],
        links: List[str],
        stored_color_settings: dict,
        reset_color_index: Optional[int],
        color_update_index: Optional[int],
    ) -> List[dict]:
        """Return updated options and values for the different color selector components.
        If previous color settings are found it will be used, or set value to min and max
        surface range unless the user has updated the component through interaction."""
        stored_color_settings = (stored_color_settings
                                 if stored_color_settings is not None else {})
        colormaps = DefaultSettings.COLORMAP_OPTIONS

        surfids: List[str] = []
        color_data: List[dict] = []
        for idx, data in enumerate(values):
            surfaceid = (get_surface_id_for_diff_surf(values)
                         if data.get("surf_type") == "diff" else
                         get_surface_id_from_data(data))
            # if surfaceid exist in another view use the color settings
            # from that view and disable the color component
            if surfaceid in surfids:
                index_of_first = surfids.index(surfaceid)
                surfids.append(surfaceid)
                view_data = deepcopy(color_data[index_of_first])
                view_data["colormap"].update(disabled=True)
                view_data["color_range"].update(disabled=True)
                color_data.append(view_data)
                continue

            surfids.append(surfaceid)

            use_stored_color = (surfaceid in stored_color_settings
                                and not color_update_index == idx)
            if not ("colormap" in links and idx > 0):
                colormap = (stored_color_settings[surfaceid]["colormap"]
                            if use_stored_color else data.get(
                                "colormap", colormaps[0]))

            if not ("color_range" in links and idx > 0):
                value_range = data["surface_range"]
                if data.get("colormap_keep_range", False):
                    color_range = data["color_range"]
                elif reset_color_index == idx or surfaceid not in stored_color_settings:
                    color_range = value_range
                else:
                    color_range = (
                        stored_color_settings[surfaceid]["color_range"]
                        if use_stored_color else data.get(
                            "color_range", value_range))

            color_data.append({
                "colormap": {
                    "value": colormap,
                    "options": colormaps
                },
                "color_range": {
                    "value":
                    color_range,
                    "step":
                    calculate_slider_step(
                        min_value=value_range[0],
                        max_value=value_range[1],
                        steps=100,
                    ) if value_range[0] != value_range[1] else 0,
                    "range":
                    value_range,
                },
            })

        return color_data

    def get_surface_address_from_data(
        data: dict,
    ) -> Union[SimulatedSurfaceAddress, ObservedSurfaceAddress,
               StatisticalSurfaceAddress]:
        """Return the SurfaceAddress based on view selection"""
        has_date = (ensemble_surface_providers[
            data["ensemble"][0]].surface_dates_for_attribute(
                data["attribute"][0]) is not None)

        if data["mode"] == SurfaceMode.REALIZATION:
            return SimulatedSurfaceAddress(
                attribute=data["attribute"][0],
                name=data["name"][0],
                datestr=data["date"][0] if has_date else None,
                realization=int(data["realizations"][0]),
            )
        if data["mode"] == SurfaceMode.OBSERVED:
            return ObservedSurfaceAddress(
                attribute=data["attribute"][0],
                name=data["name"][0],
                datestr=data["date"][0] if has_date else None,
            )
        return StatisticalSurfaceAddress(
            attribute=data["attribute"][0],
            name=data["name"][0],
            datestr=data["date"][0] if has_date else None,
            realizations=[int(real) for real in data["realizations"]],
            statistic=data["mode"],
        )

    def publish_and_get_surface_metadata(
            surface_provider: EnsembleSurfaceProvider,
            surface_address: SurfaceAddress) -> Tuple:
        provider_id: str = surface_provider.provider_id()
        qualified_address = QualifiedSurfaceAddress(provider_id,
                                                    surface_address)
        surf_meta = surface_server.get_surface_metadata(qualified_address)
        if not surf_meta:
            # This means we need to compute the surface
            surface = surface_provider.get_surface(address=surface_address)
            if not surface:
                raise ValueError(
                    f"Could not get surface for address: {surface_address}")
            surface_server.publish_surface(qualified_address, surface)
            surf_meta = surface_server.get_surface_metadata(qualified_address)
        return surf_meta, surface_server.encode_partial_url(qualified_address)

    def publish_and_get_diff_surface_metadata(
        surface_provider: EnsembleSurfaceProvider,
        surface_address: SurfaceAddress,
        sub_surface_provider: EnsembleSurfaceProvider,
        sub_surface_address: SurfaceAddress,
    ) -> Tuple:
        provider_id: str = surface_provider.provider_id()
        subprovider_id = sub_surface_provider.provider_id()
        qualified_address: Union[QualifiedSurfaceAddress,
                                 QualifiedDiffSurfaceAddress]
        qualified_address = QualifiedDiffSurfaceAddress(
            provider_id, surface_address, subprovider_id, sub_surface_address)

        surf_meta = surface_server.get_surface_metadata(qualified_address)
        if not surf_meta:
            surface_a = surface_provider.get_surface(address=surface_address)
            surface_b = sub_surface_provider.get_surface(
                address=sub_surface_address)
            if surface_a is not None and surface_b is not None:
                surface = surface_a - surface_b
            surface_server.publish_surface(qualified_address, surface)
            surf_meta = surface_server.get_surface_metadata(qualified_address)
        return surf_meta, surface_server.encode_partial_url(qualified_address)

    def get_surface_id_from_data(data: dict) -> str:
        """Retrieve surfaceid used for the colorstore"""
        surfaceid = data["attribute"][0] + data["name"][0]
        if data["date"]:
            surfaceid += data["date"][0]
        if data["mode"] == SurfaceMode.STDDEV:
            surfaceid += data["mode"]
        return surfaceid

    def get_surface_id_for_diff_surf(values: List[dict]) -> str:
        """Retrieve surfaceid used for the colorstore, for the diff surface
        this needs to be a combination of the two surfaces subtracted"""
        return get_surface_id_from_data(values[0]) + get_surface_id_from_data(
            values[1])

    def update_selections_with_multi(values: List[dict],
                                     multi: str) -> List[dict]:
        """If a selector has been set as multi, the values selected in that component needs
        to be divided between the views so that there is only one unique value in each"""
        multi_values = values[0][multi]
        new_values = []
        for val in multi_values:
            updated_values = deepcopy(values[0])
            updated_values[multi] = [val]
            new_values.append(updated_values)
        return new_values

    def attribute_has_date(attribute: str,
                           provider: EnsembleSurfaceProvider) -> bool:
        """Check if an attribute has any dates"""
        return provider.surface_dates_for_attribute(attribute) is not None

    def remove_data_if_not_valid(values: List[dict]) -> List[dict]:
        """Checks if surfaces can be provided from the selections.
        Any invalid selections are removed."""
        updated_values = []
        for data in values:
            surface_address = get_surface_address_from_data(data)
            try:
                provider = ensemble_surface_providers[data["ensemble"][0]]
                surf_meta, _ = publish_and_get_surface_metadata(
                    surface_address=surface_address,
                    surface_provider=provider,
                )
            except ValueError:
                continue
            if not isinstance(surf_meta.val_min,
                              np.ma.core.MaskedConstant) and not isinstance(
                                  surf_meta.val_max,
                                  np.ma.core.MaskedConstant):
                data["surface_range"] = [surf_meta.val_min, surf_meta.val_max]
                updated_values.append(data)

        return updated_values

    def get_surface_metadata_and_image(data: dict) -> Tuple:
        surface_address = get_surface_address_from_data(data)
        provider = ensemble_surface_providers[data["ensemble"][0]]
        return publish_and_get_surface_metadata(
            surface_address=surface_address, surface_provider=provider)

    def get_surface_metadata_and_image_for_diff_surface(
        selector_values: List[dict], ) -> Tuple:
        surface_address = get_surface_address_from_data(selector_values[0])
        sub_surface_address = get_surface_address_from_data(selector_values[1])
        provider = ensemble_surface_providers[selector_values[0]["ensemble"]
                                              [0]]
        sub_provider = ensemble_surface_providers[selector_values[1]
                                                  ["ensemble"][0]]
        return publish_and_get_diff_surface_metadata(
            surface_address=surface_address,
            surface_provider=provider,
            sub_surface_address=sub_surface_address,
            sub_surface_provider=sub_provider,
        )

    def add_diff_surface_to_values(selector_values: List[dict]) -> List[dict]:
        surf_meta, _ = get_surface_metadata_and_image_for_diff_surface(
            selector_values)
        selector_values.append({
            "surface_range": [surf_meta.val_min, surf_meta.val_max],
            "surf_type":
            "diff",
        })
        return selector_values

    def combine_selector_values_and_name(values: list, id_list: list,
                                         view: int) -> dict:
        """Combine selector values with selector name for given view"""
        return {
            id_values["selector"]: values
            for values, id_values in zip(values, id_list)
            if id_values["view"] == view
        }
Example #20
0
toast = html.Div(
    [
        dbc.Button(
            "Open toast",
            id="positioned-toast-toggle",
            color="primary",
            n_clicks=0,
        ),
        dbc.Toast(
            "This toast is placed in the top right",
            id="positioned-toast",
            header="Positioned toast",
            is_open=False,
            dismissable=True,
            icon="danger",
            # top: 66 positions the toast below the navbar
            style={"position": "fixed", "top": 66, "right": 10, "width": 350},
        ),
    ]
)


@app.callback(
    Output("positioned-toast", "is_open"),
    [Input("positioned-toast-toggle", "n_clicks")],
)
def open_toast(n):
    if n:
        return True
    return False
def update_intersection_source(app: Dash, get_uuid: Callable,
                               surface_geometry: Dict) -> None:
    @app.callback(
        Output({
            "id": get_uuid("intersection-data"),
            "element": "well-wrapper"
        }, "style"),
        Output(
            {
                "id": get_uuid("intersection-data"),
                "element": "xline-wrapper"
            }, "style"),
        Output(
            {
                "id": get_uuid("intersection-data"),
                "element": "yline-wrapper"
            }, "style"),
        Input({
            "id": get_uuid("intersection-data"),
            "element": "source"
        }, "value"),
    )
    def _show_source_details(source: str) -> Tuple[Dict, Dict, Dict]:
        hide = {"display": "none"}
        show = {"display": "inline"}
        if source == "well":
            return show, hide, hide
        if source == "xline":
            return hide, show, hide
        if source == "yline":
            return hide, hide, show
        return hide, hide, hide

    @app.callback(
        Output(
            {
                "id": get_uuid("map"),
                "element": "stored_xline"
            },
            "data",
        ),
        Input(
            {
                "id": get_uuid("intersection-data"),
                "cross-section": "xline",
                "element": "value",
            },
            "value",
        ),
    )
    def _store_xline(x_value: Union[float, int]) -> List:

        return [
            [x_value, surface_geometry["ymin"]],
            [x_value, surface_geometry["ymax"]],
        ]

    @app.callback(
        Output(
            {
                "id": get_uuid("map"),
                "element": "stored_yline"
            },
            "data",
        ),
        Input(
            {
                "id": get_uuid("intersection-data"),
                "cross-section": "yline",
                "element": "value",
            },
            "value",
        ),
    )
    def _store_yline(y_value: Union[float, int]) -> List:

        return [
            [surface_geometry["xmin"], y_value],
            [surface_geometry["xmax"], y_value],
        ]

    @app.callback(
        Output(
            {
                "id": get_uuid("intersection-data"),
                "cross-section": MATCH,
                "element": "value",
            },
            "step",
        ),
        Input(
            {
                "id": get_uuid("intersection-data"),
                "cross-section": MATCH,
                "element": "step",
            },
            "value",
        ),
    )
    def _set_cross_section_step(step: Union[float, int]) -> Union[float, int]:
        return step
Example #22
0
        [
            dbc.AccordionItem(
                "This is the content of the first section. It has a "
                "default ID of item-0.",
                title="Item 1: item-0",
            ),
            dbc.AccordionItem(
                "This is the content of the second section. It has a "
                "default ID of item-1.",
                title="Item 2: item-1",
            ),
            dbc.AccordionItem(
                "This is the content of the third section. It has a "
                "default ID of item-2.",
                title="Item 3: item-2",
            ),
        ],
        id="accordion-always-open",
        always_open=True,
    ),
    html.Div(id="accordion-contents-open-ids", className="mt-3"),
])


@app.callback(
    Output("accordion-contents-open-ids", "children"),
    [Input("accordion-always-open", "active_item")],
)
def change_item(item):
    return f"Item(s) selected: {item}"
Example #23
0
def test_dvcv006_inconsistent_wildcards(dash_duo):
    app = Dash(__name__)
    app.layout = html.Div()

    @app.callback(
        [
            Output({"b": MATCH}, "children"),
            Output({
                "b": ALL,
                "c": 1
            }, "children")
        ],
        [Input({
            "b": MATCH,
            "c": 2
        }, "children")],
    )
    def x(c):
        return c, [c]

    @app.callback(
        [Output({"a": MATCH}, "children")],
        [
            Input({"b": MATCH}, "children"),
            Input({"c": ALLSMALLER}, "children")
        ],
        [
            State({
                "d": MATCH,
                "dd": MATCH
            }, "children"),
            State({"e": ALL}, "children")
        ],
    )
    def y(b, c, d, e):
        return b + c + d + e

    dash_duo.start_server(app, **debugging)

    specs = [
        [
            "`Input` / `State` wildcards not in `Output`s",
            [
                'State 0 ({"d":MATCH,"dd":MATCH}.children)',
                "has MATCH or ALLSMALLER on key(s) d, dd",
                'where Output 0 ({"a":MATCH}.children)',
            ],
        ],
        [
            "`Input` / `State` wildcards not in `Output`s",
            [
                'Input 1 ({"c":ALLSMALLER}.children)',
                "has MATCH or ALLSMALLER on key(s) c",
                'where Output 0 ({"a":MATCH}.children)',
            ],
        ],
        [
            "`Input` / `State` wildcards not in `Output`s",
            [
                'Input 0 ({"b":MATCH}.children)',
                "has MATCH or ALLSMALLER on key(s) b",
                'where Output 0 ({"a":MATCH}.children)',
            ],
        ],
        [
            "Mismatched `MATCH` wildcards across `Output`s",
            [
                'Output 1 ({"b":ALL,"c":1}.children)',
                "does not have MATCH wildcards on the same keys as",
                'Output 0 ({"b":MATCH}.children).',
            ],
        ],
    ]
    check_errors(dash_duo, specs)
Example #24
0
def test_cbva002_callback_return_validation():
    app = Dash(__name__)
    app.layout = html.Div([
        html.Div(id="a"),
        html.Div(id="b"),
        html.Div(id="c"),
        html.Div(id="d"),
        html.Div(id="e"),
        html.Div(id="f"),
    ])

    @app.callback(Output("b", "children"), [Input("a", "children")])
    def single(a):
        return set([1])

    single_wrapped = app.callback_map["b.children"]["callback"]

    with pytest.raises(InvalidCallbackReturnValue):
        # outputs_list (normally callback_context.outputs_list) is provided
        # by the dispatcher from the request.
        single_wrapped("aaa", outputs_list={"id": "b", "property": "children"})
        pytest.fail("not serializable")

    @app.callback([Output("c", "children"),
                   Output("d", "children")], [Input("a", "children")])
    def multi(a):
        return [1, set([2])]

    multi_wrapped = app.callback_map["..c.children...d.children.."]["callback"]

    with pytest.raises(InvalidCallbackReturnValue):
        outputs_list = [
            {
                "id": "c",
                "property": "children"
            },
            {
                "id": "d",
                "property": "children"
            },
        ]
        multi_wrapped("aaa", outputs_list=outputs_list)
        pytest.fail("nested non-serializable")

    @app.callback([Output("e", "children"),
                   Output("f", "children")], [Input("a", "children")])
    def multi2(a):
        return ["abc"]

    multi2_wrapped = app.callback_map["..e.children...f.children.."][
        "callback"]

    with pytest.raises(InvalidCallbackReturnValue):
        outputs_list = [
            {
                "id": "e",
                "property": "children"
            },
            {
                "id": "f",
                "property": "children"
            },
        ]
        multi2_wrapped("aaa", outputs_list=outputs_list)
        pytest.fail("wrong-length list")
Example #25
0
def multipage_app(validation=False):
    app = Dash(__name__,
               suppress_callback_exceptions=(validation == "suppress"))

    skeleton = html.Div(
        [dcc.Location(id="url", refresh=False),
         html.Div(id="page-content")])

    layout_index = html.Div([
        dcc.Link('Navigate to "/page-1"', id="index_p1", href="/page-1"),
        dcc.Link('Navigate to "/page-2"', id="index_p2", href="/page-2"),
    ])

    layout_page_1 = html.Div([
        html.H2("Page 1"),
        dcc.Input(id="input-1-state", type="text", value="Montreal"),
        dcc.Input(id="input-2-state", type="text", value="Canada"),
        html.Button(id="submit-button", n_clicks=0, children="Submit"),
        html.Div(id="output-state"),
        html.Br(),
        dcc.Link('Navigate to "/"', id="p1_index", href="/"),
        dcc.Link('Navigate to "/page-2"', id="p1_p2", href="/page-2"),
    ])

    layout_page_2 = html.Div([
        html.H2("Page 2"),
        dcc.Input(id="page-2-input", value="LA"),
        html.Div(id="page-2-display-value"),
        html.Br(),
        dcc.Link('Navigate to "/"', id="p2_index", href="/"),
        dcc.Link('Navigate to "/page-1"', id="p2_p1", href="/page-1"),
    ])

    validation_layout = html.Div(
        [skeleton, layout_index, layout_page_1, layout_page_2])

    def validation_function():
        return skeleton if flask.has_request_context() else validation_layout

    app.layout = validation_function if validation == "function" else skeleton
    if validation == "attribute":
        app.validation_layout = validation_layout

    # Index callbacks
    @app.callback(Output("page-content", "children"),
                  [Input("url", "pathname")])
    def display_page(pathname):
        if pathname == "/page-1":
            return layout_page_1
        elif pathname == "/page-2":
            return layout_page_2
        else:
            return layout_index

    # Page 1 callbacks
    @app.callback(
        Output("output-state", "children"),
        [Input("submit-button", "n_clicks")],
        [State("input-1-state", "value"),
         State("input-2-state", "value")],
    )
    def update_output(n_clicks, input1, input2):
        return ("The Button has been pressed {} times,"
                'Input 1 is "{}",'
                'and Input 2 is "{}"').format(n_clicks, input1, input2)

    # Page 2 callbacks
    @app.callback(Output("page-2-display-value", "children"),
                  [Input("page-2-input", "value")])
    def display_value(value):
        print("display_value")
        return 'You have selected "{}"'.format(value)

    return app
Example #26
0
                ),
            ],
            className="ms-1",
        ),
        dbc.Row(dbc.Col(footer)),
    ],
    fluid=True,
)
"""
==========================================================================
Callbacks
"""


@app.callback(
    Output("allocation_pie_chart", "figure"),
    Input("stock_bond", "value"),
    Input("cash", "value"),
)
def update_pie(stocks, cash):
    bonds = 100 - stocks - cash
    slider_input = [cash, bonds, stocks]

    if stocks >= 70:
        investment_style = "Aggressive"
    elif stocks <= 30:
        investment_style = "Conservative"
    else:
        investment_style = "Moderate"
    figure = make_pie(slider_input, investment_style + " Asset Allocation")
    return figure
Example #27
0
    html.P("Mean:"),
    dcc.Slider(id="histograms-mean",
               min=-3,
               max=3,
               value=0,
               marks={
                   -3: "-3",
                   3: "3"
               }),
    html.P("Standard Deviation:"),
    dcc.Slider(id="histograms-std",
               min=1,
               max=3,
               value=1,
               marks={
                   1: "1",
                   3: "3"
               }),
])


@callback(
    Output("histograms-graph", "figure"),
    Input("histograms-mean", "value"),
    Input("histograms-std", "value"),
)
def display_color(mean, std):
    data = np.random.normal(mean, std, size=500)
    fig = px.histogram(data, nbins=30, range_x=[-10, 10])
    return fig
Example #28
0
 def osi_update_notebook(self):
     return (
         Output(self.notebook_home.notebook_div, "style"),
         Output(self.notebook_home.notebook, "data"),
         Input(self.notebook_home.update_notebook_button, "n_clicks"),
     )
import dash_bootstrap_components as dbc
from dash import Input, Output, html, no_update

toast = html.Div([
    dbc.Button(
        "Open toast",
        id="simple-toast-toggle",
        color="primary",
        className="mb-3",
        n_clicks=0,
    ),
    dbc.Toast(
        [html.P("This is the content of the toast", className="mb-0")],
        id="simple-toast",
        header="This is the header",
        icon="primary",
        dismissable=True,
        is_open=False,
    ),
])


@app.callback(
    Output("simple-toast", "is_open"),
    [Input("simple-toast-toggle", "n_clicks")],
)
def open_toast(n):
    if n == 0:
        return no_update
    return True
import dash_bootstrap_components as dbc
from dash import Input, Output, State, html

fade = html.Div([
    dbc.Button("Toggle fade", id="fade-button", className="mb-3", n_clicks=0),
    dbc.Fade(
        dbc.Card(
            dbc.CardBody(
                html.P("This content fades in and out",
                       className="card-text"))),
        id="fade",
        is_in=False,
        appear=False,
    ),
])


@app.callback(
    Output("fade", "is_in"),
    [Input("fade-button", "n_clicks")],
    [State("fade", "is_in")],
)
def toggle_fade(n, is_in):
    if not n:
        # Button has never been clicked
        return False
    return not is_in