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)
def _update_page_per_zr( selections: dict, page_selected: str, figure_ids: List[dict], ) -> list: if page_selected != "per_zr": raise PreventUpdate selections = selections[page_selected] if not selections["update"]: raise PreventUpdate figs = {} for selector in [x["selector"] for x in figure_ids]: dframe = volumemodel.get_df(filters=selections["filters"], groups=[selector]) texttemplate = ("%{text:.3s}" if selections["X Response"] in volumemodel.volume_columns else "%{text:.3g}") # pylint: disable=no-member figs[selector] = { "pie": create_figure( plot_type="pie", data_frame=dframe, values=selections["X Response"], names=selector, title=f"{selections['X Response']} per {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)), "bar": create_figure( plot_type="bar", data_frame=dframe, x=selector, y=selections["X Response"], color_discrete_sequence=px.colors.diverging.BrBG_r, color=selections["Color by"], text=selections["X Response"], xaxis=dict(type="category", tickangle=45, tickfont_size=17, title=None), ).update_traces(texttemplate=texttemplate, textposition="auto").add_annotation( fluid_annotation(selections)), } output_figs = [] for fig_id in figure_ids: output_figs.append(figs[fig_id["selector"]][fig_id["chart"]]) return output_figs
def create_realplot(df: pd.DataFrame, sensitivity_colors: dict) -> go.Figure: senscasecolors = { senscase: sensitivity_colors[sensname] for senscase, sensname in zip(df["sensname_case"], df["sensname"]) } return (create_figure( plot_type="bar", data_frame=df, x="REAL", y="VALUE", color="sensname_case", color_discrete_map=senscasecolors, barmode="overlay", custom_data=["casetype"], yaxis={ "range": [df["VALUE"].min() * 0.7, df["VALUE"].max() * 1.1] }, opacity=0.85, ).update_layout(legend={ "orientation": "h", "yanchor": "bottom", "y": 1.02 }).update_layout(legend_title_text="").for_each_trace(lambda t: ( t.update(marker_line_color="black") if t["customdata"][0][0] == "high" else t.update(marker_line_color="white", marker_line_width=2)) if t[ "customdata"][0][0] != "mc" else None))
def create_barfig(df: pd.DataFrame, groupby: list, diff_mode: str, colorcol: str) -> Union[None, go.Figure]: if df.empty: return None return (create_figure( plot_type="bar", data_frame=df, x=df[groupby].astype(str).agg(" ".join, axis=1) if groupby else ["Total"], y=diff_mode, color_continuous_scale="teal_r", color=df[colorcol], hover_data={col: True for col in groupby}, opacity=1, ).update_layout( margin={ "l": 20, "r": 20, "t": 5, "b": 5 }, bargap=0.15, paper_bgcolor="rgba(0,0,0,0)", ).update_xaxes(title_text=None, tickangle=45, ticks="outside").update_yaxes(zeroline=True, zerolinecolor="black"))
def create_figure(self) -> go.Figure: return (create_figure( plot_type="scatter", data_frame=self.dframe, x="X", y="Y", color=self.color_by if self.color_by != "PERMX" else np.log10( self.dframe[self.color_by]), color_discrete_map=self.colormap, xaxis={ "constrain": "domain", **self.axis_layout }, yaxis={ "scaleanchor": "x", **self.axis_layout }, hover_data=[self.color_by] + self.hover_data, color_continuous_scale="Viridis", ).update_traces(marker_size=10, unselected={ "marker": { "opacity": 0 } }).update_coloraxes(showscale=False).update_layout( plot_bgcolor="white", margin={ "t": 10, "b": 10, "l": 0, "r": 0 }, showlegend=False, ))
def make_grouped_plot( self, ensembles: list, parameters: List[Any], plot_type: str = "distribution", ) -> go.Figure: """Create subplots for selected parameters""" df = self.dataframe_melted.copy() df = df[df["ENSEMBLE"].isin(ensembles)] df = df[df["PARAMETER"].isin(parameters)] df = self._sort_parameters_col(df, parameters) return (create_figure( plot_type=plot_type, data_frame=df, x="VALUE", facet_col="PARAMETER", color="ENSEMBLE", color_discrete_sequence=self.colorway, ).update_xaxes(matches=None).for_each_trace(lambda t: t.update(text=t[ "text"].replace("VALUE", "") if t["text"] is not None else None)))
def create_scatterfig( df: pd.DataFrame, x: str, y: str, selections: dict, groupby: list, diff_mode: Optional[str] = None, ) -> go.Figure: highlight_colors = {"yes": "#FF1243", "no": "#80B7BC"} colorby = (selections["Color by"] if selections["Color by"] == "highlighted" else groupby[0]) df[colorby] = df[colorby].astype(str) fig = (create_figure( plot_type="scatter", data_frame=df, x=x, y=y, color_discrete_sequence=px.colors.qualitative.Dark2, color_discrete_map=highlight_colors if colorby == "highlighted" else None, color=colorby, hover_data=groupby, ).update_traces(marker_size=10).update_layout(margin={ "l": 20, "r": 20, "t": 20, "b": 20 })) if len(df) == 1: fig.update_xaxes(range=[df[x].mean() * 0.95, df[x].mean() * 1.05]) if diff_mode is not None: fig.update_yaxes(range=find_diff_plot_range(df, diff_mode, selections)) if diff_mode == "diff (%)" and y == diff_mode: fig.add_hline(y=selections["Accept value"], line_dash="dot").add_hline( y=-selections["Accept value"], line_dash="dot") return fig
def make_grouped_plot( self, ensembles: list, prop: str, selector_values: List[Any], statistic: str = "Avg", plot_type: str = "histogram", match_axis: bool = False, ) -> go.Figure: sel_length = 1 for selector in selector_values: sel_length *= len(selector) df = self.dataframe.copy() df = df[df["PROPERTY"] == prop] if selector_values is not None: df = self.filter_dataframe(df, self.selectors, selector_values) df = df[df["ENSEMBLE"].isin(ensembles)] fig = create_figure( plot_type=plot_type if plot_type != "scatter_ensemble" else "scatter", data_frame=df, x="REAL" if plot_type != "distribution" else statistic, y=statistic if plot_type != "distribution" else None, facet_col="label" if plot_type != "scatter_ensemble" else "ENSEMBLE", color="ENSEMBLE" if plot_type != "scatter_ensemble" else "label", color_discrete_sequence=self.colorway, ) if not match_axis: fig.update_xaxes(matches=None).update_yaxes(matches=None) fig = fig.to_dict() fig["layout"] = self.theme.create_themed_layout(fig["layout"]) return fig
def _update_page_1p1t_and_custom( selections: dict, plot_table_select: str, page_selected: str, figure_ids: list, table_wrapper_ids: list, ) -> tuple: if page_selected not in ["1p1t", "custom"]: raise PreventUpdate selections = selections[page_selected] if not selections["update"]: raise PreventUpdate groups = ["REAL"] parameters = [] responses = [] for item in ["Subplots", "Color by", "X Response", "Y Response"]: if selections[item] is not None: if (selections[item] in volumemodel.selectors and selections[item] not in groups): groups.append(selections[item]) if (selections[item] in volumemodel.parameters and selections[item] not in parameters): parameters.append(selections[item]) if (item in ["X Response", "Y Response"] and selections[item] not in responses): responses.append(selections[item]) dframe = volumemodel.get_df(filters=selections["filters"], groups=groups, parameters=parameters) if not (plot_table_select == "table" and page_selected == "custom"): df_for_figure = ( dframe if not (selections["Plot type"] == "bar" and groups != ["REAL"]) 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"], 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)) if selections["X Response"] in volumemodel.selectors: figure.update_xaxes( dict(type="category", tickangle=45, tickfont_size=12)) if selections["Subplots"] is not None: if not selections["X axis matches"]: figure.update_xaxes({"matches": None}) if not selections["Y axis matches"]: figure.update_yaxes({"matches": None}) else: figure = dash.no_update # Make tables if not (plot_table_select == "graph" and page_selected == "custom"): table_wrapper_children = make_table_wrapper_children( dframe=dframe, responses=responses, groups=groups, volumemodel=volumemodel, page_selected=page_selected, selections=selections, table_type="Statistics table", view_height=42 if page_selected == "1p1t" else 86, ) else: table_wrapper_children = dash.no_update return tuple( update_relevant_components( id_list=id_list, update_info=[{ "new_value": val, "conditions": { "page": page_selected }, }], ) for val, id_list in zip([figure, table_wrapper_children], [figure_ids, table_wrapper_ids]))
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"]) 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.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 dfs.append(df_stat) if dfs: dframe = pd.concat(dfs) figure = (create_figure( plot_type="line", data_frame=dframe, x="REAL", y=selections["X Response"], facet_col=selections["Subplots"], color="calculation", title= f"Convergence plot of mean/p10/p90 for {selections['X Response']} ", yaxis=dict(showticklabels=True), ).update_traces(line_width=3.5).update_traces( line=dict(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" }).add_annotation(fluid_annotation(selections))) if selections["Subplots"] is not None: if not selections["X axis matches"]: figure.update_xaxes({"matches": None}) if not selections["Y axis matches"]: figure.update_yaxes(dict(matches=None)) return figure
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) 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, )
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)
def make_distribution_plot(df, parameter, response, theme): """Make plotly traces for scatterplot and histograms for selected response and input parameter""" fig = make_subplots( rows=4, cols=2, specs=[ [{ "colspan": 2, "rowspan": 2 }, None], [None, None], [{ "rowspan": 2 }, { "rowspan": 2 }], [None, None], ], ) scatter_trace, trendline = create_figure( plot_type="scatter", data_frame=df, x=parameter, y=response, trendline="ols", hover_data={ "REAL": True }, color_discrete_sequence=["SteelBlue"], marker={ "size": 20, "opacity": 0.7 }, ).data fig.add_trace(scatter_trace, 1, 1) fig.add_trace(trendline, 1, 1) fig.add_trace( { "type": "histogram", "x": df[parameter], "showlegend": False, }, 3, 1, ) fig.add_trace( { "type": "histogram", "x": df[response], "showlegend": False, }, 3, 2, ) fig["layout"].update( theme_layout( theme.plotly_theme, { "bargap": 0.05, "xaxis": { "title": parameter, }, "yaxis": { "title": response }, "xaxis2": { "title": parameter }, "xaxis3": { "title": response }, "title": f"Distribution of {response} and {parameter}", }, )) return fig