def build_drilldown_title(data_id, all_inputs, click_point, props, val_prop): data = global_state.get_data(data_id) def _build_val(col, val): if classify_type(find_dtype(data[col])) == "D": return json_date(convert_date_val_to_date(val)) return val if "text" in click_point: # Heatmaps strs = [] for dim in click_point["text"].split("<br>"): prop, val = dim.split(": ") strs.append("{} ({})".format(prop, val)) return "{}: {}".format(text("Drilldown for"), ", ".join(strs)) strs = [] frame_col = all_inputs.get("animate_by") if frame_col: strs.append("{} ({})".format(frame_col, click_point.get("customdata"))) for prop in props: prop = make_list(prop) val_key = prop[0] if click_point.get(val_key) is not None: col = make_list(all_inputs.get(prop[-1]))[0] strs.append("{} ({})".format( col, _build_val(col, click_point.get(val_key)))) val_prop = make_list(val_prop) val_key = val_prop[0] val_col = make_list(all_inputs.get(val_prop[-1]))[0] agg = AGGS[all_inputs.get("agg") or "raw"] strs.append("{} {} ({})".format( agg, val_col, _build_val(val_col, click_point.get(val_key)))) return "{}: {}".format(text("Drilldown for"), ", ".join(strs))
def build_modal(map_type, loc_mode): return html.Div( [ html.Div( html.Span( html.Span(text("GeoJSON Options"), style=dict(whiteSpace="pre-line")), className="input-group-addon d-block pt-1 pb-0 pointer", ), className="input-group mr-3", id="open-geojson-modal", ), dbc.Modal( [ dbc.ModalHeader(text("Custom GeoJSON Options")), dbc.ModalBody(build_geojson_upload(loc_mode)), dbc.ModalFooter( dbc.Button(text("Close"), id="close-geojson-modal", className="ml-auto")), ], id="geojson-modal", size="lg", centered=True, ), ], className="col-auto", style={} if map_type == "choropleth" and loc_mode == "geojson-id" else {"display": "none"}, id="custom-geojson-input", )
def build_histogram(data_id, col, query, point_filter): data = run_query( handle_predefined(data_id), query, global_state.get_context_variables(data_id), ) query, _ = build_group_inputs_filter(data, [point_filter]) data = run_query(data, query) s = data[~pd.isnull(data[col])][col] hist_data, hist_labels = np.histogram(s, bins=10) hist_labels = list( map(lambda x: json_float(x, precision=3), hist_labels[1:])) axes_builder = build_axes( dict( data=dict(all=dict(Frequency=hist_data, Bins=hist_labels)), min=dict(Frequency=0), max=dict(Frequency=max(hist_data)), ), "Bins", dict(type="single", data={}), ) hist_data = dict(data={"all": dict(x=hist_labels, Frequency=hist_data)}) bars = bar_builder( hist_data, "Bins", ["Frequency"], axes_builder, chart_builder_passthru, modal=True, ) bars.figure["layout"]["xaxis"]["type"] = "category" bars.figure["layout"]["title"]["text"] = "{} {} ({} {})".format( text("Histogram of"), col, len(s), text("data points")) return bars
def build_modal(ext_aggs, chart_type, y): return [ build_hoverable( html.I( className="ico-settings pointer", id="open-extended-agg-modal", style=show_style(chart_type not in NON_EXT_AGGREGATION and len(y)), ), html.Div(html.Span(text("ext_agg_desc")), id="extended-aggregation-tooltip"), hover_class="saved-chart-config", top="100%", additional_classes="mb-auto mt-auto", ), dcc.Store(id="extended-aggregations", data=ext_aggs), dcc.Store(id="prev-open-extended-agg-modal", data=0), dcc.Store(id="prev-close-extended-agg-modal", data=0), dcc.Store(id="prev-clear-extended-agg-modal", data=0), dcc.Store(id="prev-apply-extended-agg-modal", data=0), dbc.Modal( [ dbc.ModalHeader( html.Div( [ html.Div( text("Extended Aggregations"), className="col mt-auto mb-auto", ), html.Button( html.Span("X"), className="close mr-5", id="close-extended-agg-modal", ), ], className="row", )), dbc.ModalBody(build_body(ext_aggs)), dbc.ModalFooter([ dbc.Button( text("Clear"), id="clear-extended-agg-modal", className="ml-auto", ), dbc.Button( text("Apply"), id="apply-extended-agg-modal", ), ]), ], id="extended-agg-modal", size="lg", centered=True, ), ]
def update_geojson(contents, filename): if filename is None: raise PreventUpdate geojson_options = [ build_option(ct["key"]) for ct in get_custom_geojson() ] try: geojson_key = load_geojson(contents, filename) geojson_options.append(build_option(geojson_key)) return "{} {}!".format(geojson_key, text("uploaded")), geojson_options except BaseException as ex: return str(ex), geojson_options
def update_featureidkey_options(geojson): geojson_data = get_custom_geojson(geojson) placeholder = text("Select Uploaded Data") if geojson_data is None or isinstance(geojson_data, list): return [], False, placeholder disabled = geojson_data["type"] != "FeatureCollection" placeholder = "id" if disabled else placeholder if geojson_data and not disabled: return ( [build_option(p) for p in geojson_data.get("properties", [])], disabled, placeholder, ) return [], disabled, placeholder
def build_layout(): return flatten_lists([[ dcc.Store(id="saved-chart-config-{}".format(i)), dcc.Store(id="prev-saved-chart-config-{}".format(i)), dcc.Store(id="saved-deletes-{}".format(i), data=0), html.Div( [ html.Div( [ html.H3( "{} {}".format(text("Saved Chart"), i), className="col-auto pr-3", ), html.Div( id="saved-chart-header-{}".format(i), className="col pl-0", ), html.Div( dbc.Button( text("Delete"), id="delete-saved-btn-{}".format(i), color="primary", className="delete-chart", ), className="col-auto", ), ], className="row", ), html.Div(id="saved-chart-{}".format(i)), ], id="saved-chart-div-{}".format(i), className="saved-chart-div pt-5", style=dict(display="none"), ), ] for i in SAVED_CHART_IDS])
def load_geojson(contents, filename): if contents is None and filename is None: return None if not filename.endswith(".json"): raise Exception(text("geojson files must be JSON!")) _, content_string = contents.split(",") decoded = base64.b64decode(content_string) geojson = json.loads(decoded.decode("utf-8")) geojson_key = "".join(filename.split(".")[:-1]) # get properties available to use for featureidkey data = dict(data=geojson, filename=filename, time=pd.Timestamp("now"), type=geojson["type"]) if data["type"] == "FeatureCollection": data["properties"] = sorted( geojson["features"][0]["properties"].keys()) geojson_key = add_custom_geojson(geojson_key, data) return geojson_key
def build_drilldown_modal(idx): return dbc.Modal( [ dbc.ModalHeader( html.Div( [ html.Div( text("Chart Drilldown"), className="col mt-auto mb-auto", id="drilldown-modal-header-{}".format(idx), ), html.Button( html.Span("X"), className="close mr-5", id="close-drilldown-modal-header-{}".format(idx), ), ], className="row", )), dbc.ModalBody( dcc.Loading( [ html.Div( [ html.Div( dcc.Tabs( id="drilldown-chart-type-{}".format( idx), value="histogram", children=[ build_tab(t.capitalize(), t) for t in ["histogram", "bar"] ], style=dict(height="36px"), ), className="col-md-4", ), build_input( "X", dcc.Dropdown( id="drilldown-x-dropdown-{}".format( idx), options=[], placeholder="Select a column", value=None, style=dict(width="inherit"), className="drilldown-x-dropdown", ), id="drilldown-x-input-{}".format(idx), style=dict(display="none"), ), ], className="row pt-3 pb-5", ), html.Div(id="drilldown-content-{}".format(idx)), ], type="circle", )), dbc.ModalFooter( dbc.Button( text("Close"), id="close-drilldown-modal-{}".format(idx), className="ml-auto", )), ], id="drilldown-modal-{}".format(idx), size="lg", centered=True, className="drilldown-modal", )
def on_data( _ts1, _ts2, _ts3, _ts4, _ts5, _ts6, _ts7, _ts8, load_clicks, inputs, chart_inputs, yaxis_data, map_data, cs_data, treemap_data, funnel_data, last_chart_inputs, auto_load, prev_load_clicks, ext_aggs, ): """ dash callback controlling the building of dash charts """ all_inputs = dict_merge( inputs, chart_inputs, dict(yaxis=yaxis_data or {}), map_data, cs_data, treemap_data, funnel_data, dict(extended_aggregation=ext_aggs or []) if inputs.get("chart_type") not in NON_EXT_AGGREGATION else {}, ) if not auto_load and load_clicks == prev_load_clicks: raise PreventUpdate if all_inputs == last_chart_inputs: raise PreventUpdate if is_app_root_defined(dash_app.server.config.get("APPLICATION_ROOT")): all_inputs["app_root"] = dash_app.server.config["APPLICATION_ROOT"] charts, range_data, code = build_chart(**all_inputs) agg_disabled = len(ext_aggs) > 0 ext_agg_tt = text("ext_agg_desc") ext_agg_warning = show_style(agg_disabled) if agg_disabled: ext_agg_tt = html.Div([ html.Span(text("ext_agg_desc")), html.Br(), html.Ul([ html.Li( extended_aggregations.build_extended_agg_desc(ext_agg), className="mb-0", ) for ext_agg in ext_aggs ]), ]) final_cols = build_final_cols( make_list(inputs.get("y")), inputs.get("z"), inputs.get("agg"), ext_aggs if inputs.get("chart_type") not in NON_EXT_AGGREGATION else [], ) return ( charts, all_inputs, range_data, "\n".join(make_list(code) + [CHART_EXPORT_CODE]), get_yaxis_type_tabs(final_cols), load_clicks, dict(display="block" if valid_chart(**all_inputs) else "none"), agg_disabled, ext_agg_tt, ext_agg_warning, )
def collapse_cleaners_input(n, is_open): final_is_open = is_open if n: final_is_open = not is_open return final_is_open, collapse_btn_text(final_is_open, text("Cleaners"))
def collapse_data_input(n, is_open): final_is_open = is_open if n: final_is_open = not is_open return final_is_open, collapse_btn_text(final_is_open, text("Data Selection"))
def build_saved_header(config): chart_type = config["chart_type"] final_data = [ ("Data ID", config["data_id"]), ("Query", config.get("query")), ("Chart Type", chart_type), ] if config.get("agg") not in [None, "raw"]: final_data.append(("Aggregation", config["agg"])) if chart_type == "maps": group_by = config["map_group"] map_type = config.get("map_type") if map_type == "scattergeo": map_props = ["map_type", "lat", "lon", "map_val", "scope", "proj"] elif map_type == "mapbox": map_props = ["map_type", "lat", "lon", "map_val", "mapbox_style"] else: map_props = ["map_type", "loc_mode", "loc", "map_val"] if config.get("loc_mode") == "geojson-id": map_props += ["geojson", "featureidkey"] for prop in map_props: final_data.append((prop, config.get(prop))) elif chart_type == "candlestick": group_by = config["cs_group"] for prop in ["cs_x", "cs_open", "cs_close", "cs_high", "cs_low"]: final_data.append((prop.split("_")[-1], config.get(prop))) elif chart_type == "treemap": group_by = config["treemap_group"] for prop in ["treemap_value", "treemap_label"]: final_data.append((prop.split("_")[-1], config.get(prop))) else: group_by = config.get("group") final_data.append(("X-Axis", config["x"])) y = make_list(config["y"]) final_data.append(("Y-Axes" if len(y) > 1 else "Y-Axis", ",".join(y))) if chart_type in ZAXIS_CHARTS: final_data.append(("z", config.get("z"))) if chart_type == "scatter" and config["trendline"]: final_data.append(("Trendline", "\u2714")) if group_by: final_data.append(("Group By", ", ".join(make_list(group_by)))) group_type = config["group_type"] final_data.append(("Group Type", group_type)) if group_type == "bins": final_data.append(("Bin Type", config["bin_type"])) final_data.append(("Bins", config["bin_val"])) else: final_data.append( ("Selected Groups", ", ".join(make_list(config["groups"])))) if config["cpg"]: final_data.append(("Chart Per Group", "\u2714")) if config["cpy"]: final_data.append(("Chart Per Y", "\u2714")) if chart_type in ANIMATION_CHARTS and config["animate"]: final_data.append(("Animate", "\u2714")) if chart_type in ANIMATE_BY_CHARTS and config["animate_by"]: final_data.append( ("Animate By", ", ".join(make_list(config["animate_by"])))) return build_hoverable( html.I(className="ico-help-outline"), [ html.B("Chart Configuration"), html.Ul( [ html.Li( [html.B(text(prop)), html.Span(": {}".format(value))], className="mb-0", ) for prop, value in final_data if value is not None ], className="mb-0", ), ], hover_class="saved-chart-config", top="unset", )
def build_geojson_upload(loc_mode, geojson_key=None, featureidkey=None): curr_geojson = get_custom_geojson(geojson_key) featureidkey_options = [] featureidkey_value = featureidkey featureidkey_placeholder = text("Select Uploaded Data") disabled = False if curr_geojson and not isinstance(curr_geojson, list): if curr_geojson.get("type") == "FeatureCollection": featureidkey_options = [ build_option(fik) for fik in curr_geojson["properties"] ] else: featureidkey_value = None disabled = True featureidkey_placeholder = "id" return [ html.Div( [ html.Div( [ dcc.Upload( html.Div( html.Span( html.Span( text("Upload File"), style=dict(whiteSpace="pre-line"), ), className= "input-group-addon d-block pt-1 pb-0 pointer", ), className="input-group mr-3", id="upload-geojson-btn", ), id="upload-geojson", ), ], className="col-auto", ), html.Div(id="output-geojson-upload", className="col mt-auto mb-auto"), ], className="row pb-5", ), html.Div( [ build_input( text("geojson"), dcc.Dropdown( id="geojson-dropdown", options=[ build_option(ct["key"]) for ct in CUSTOM_GEOJSON ], placeholder=text("Select Uploaded Data"), style=dict(width="inherit"), value=geojson_key if loc_mode == "geojson-id" else None, ), className="col-md-6", id="geojson-input", ), build_input( text("featureidkey"), dcc.Dropdown( id="featureidkey-dropdown", options=featureidkey_options, placeholder=featureidkey_placeholder, style=dict(width="inherit"), disabled=disabled, value=featureidkey_value, ), className="col-md-6", id="featureidkey-input", ), ], className="row", ), ]
def build_body(ext_aggs): col_inputs = [html.Div(id="extended-agg-errors")] for i in INPUT_IDS: ext_agg = ext_aggs[i - 1] if len(ext_aggs) >= i else {} col_inputs.append( html.Div( [ html.Span( "{}.".format(i), className="col-auto pr-0 mt-auto mb-auto ext-agg-id", ), build_input( text("Col"), dcc.Dropdown( id="col-dropdown-{}".format(i), placeholder=text("Select"), style=dict(width="inherit"), value=ext_agg.get("col"), ), className="col-md-3", ), build_input( text("Agg"), dcc.Dropdown( id="agg-dropdown-{}".format(i), options=[ build_option(v, text(AGGS[v])) for v in [ "count", "nunique", "sum", "mean", "rolling", "corr", "first", "last", # "drop_duplicates", "median", "min", "max", "std", "var", "mad", "prod", "pctsum", "pctct", ] ], placeholder=text("Select"), style=dict(width="inherit"), value=ext_agg.get("agg"), ), className="col-md-3", ), html.Div( [ build_input( text("Window"), dcc.Input( id="window-input-{}".format(i), type="number", placeholder=text("Enter Days"), className="form-control text-center", style={"lineHeight": "inherit"}, value=ext_agg.get("window"), ), className="col-md-6", ), build_input( text("Computation"), dcc.Dropdown( id="rolling-comp-dropdown-{}".format(i), options=[ build_option("corr", text("Correlation")), build_option("count", text("Count")), build_option("cov", text("Covariance")), build_option("kurt", text("Kurtosis")), build_option("max", text("Maximum")), build_option("mean", text("Mean")), build_option("median", text("Median")), build_option("min", text("Minimum")), build_option("skew", text("Skew")), build_option( "std", text("Standard Deviation"), ), build_option("sum", text("Sum")), build_option("var", text("Variance")), ], placeholder=text("Select"), style=dict(width="inherit"), value=ext_agg.get("rolling_comp"), ), className="col-md-6 pl-0", ), ], id="rolling-inputs-{}".format(i), style=show_style(ext_agg.get("agg") == "rolling", display_style="inherit"), className="col-md-6 row p-0", ), ], className="row pb-3", )) return html.Div(col_inputs, id="extended-agg-body")