Source code for dtale.dash_application.layout.layout
import json
import dash_colorscales as dcs
import dash_core_components as dcc
import dash_daq as daq
import dash_html_components as html
import plotly
from pkg_resources import parse_version
import dtale.dash_application.custom_geojson as custom_geojson
from dtale.charts.utils import YAXIS_CHARTS, ZAXIS_CHARTS, find_group_vals
from dtale.dash_application.layout.utils import build_input, build_option
from dtale.utils import (
ChartBuildingError,
classify_type,
dict_merge,
flatten_lists,
get_dtypes,
inner_build_query,
is_app_root_defined,
make_list,
)
[docs]def test_plotly_version(version_num):
if "unknown" in plotly.__version__:
return True
return parse_version(plotly.__version__) >= parse_version(version_num)
[docs]def base_layout(github_fork, app_root, **kwargs):
"""
Base layout to be returned by :meth:`dtale.dash_application.views.DtaleDash.interpolate_index`
:param github_fork: `True` if "Fork me on Github" banner should be displayed, `False` otherwise
:type github_fork: bool
:param kwargs: Optional keyword arguments to be passed to 'dash.Dash.interplolate_index'
:type kwargs: dict
:return: HTML
:rtype: str
"""
back_to_data_padding, github_fork_html, webroot_html = ("", "", "")
if github_fork:
back_to_data_padding = "padding-right: 125px"
github_fork_html = """
<span id="forkongithub">
<a href="https://github.com/man-group/dtale">Fork me on GitHub</a>
</span>
"""
favicon_path = "../../images/favicon.png"
if is_app_root_defined(app_root):
webroot_html = """
<script type="text/javascript">
window.resourceBaseUrl = '{app_root}';
</script>
""".format(
app_root=app_root
)
favicon_path = "{}/images/favicon.png".format(app_root)
return """
<!DOCTYPE html>
<html>
<head>
{webroot_html}
{metas}
<title>D-Tale Charts</title>
<link rel="shortcut icon" href="{favicon_path}">
{css}
</head>
<body>
{github_fork_html}
<div class="container-fluid charts">
<div class="row" style="margin: 0">
<div class="col-auto">
<header>
<span class="title-font">D-TALE</span>
<span style="font-size: 16px" class="pl-4">Charts</span>
</header>
</div>
<div class="col"></div>
<div class="col-auto mt-4" style="{back_to_data_padding}">
<a href="#" onclick="javascript:backToData()">
<i class="fas fa-th mr-4"></i>
<span>Back To Data</span>
</a>
</div>
</div>
{app_entry}
</div>
<footer>
{config}
{scripts}
<script type="text/javascript">
const pathSegs = window.location.pathname.split('/');
const dataId = pathSegs[pathSegs.length - 1];
const backToData = () => window.open('{app_root}/dtale/main/' + dataId);
const goToLegacy = () => location.replace('{app_root}/dtale/popup/charts/' + dataId);
</script>
{renderer}
{css}
</footer>
</body>
</html>
""".format(
metas=kwargs["metas"],
css=kwargs["css"],
app_entry=kwargs["app_entry"],
config=kwargs["config"],
scripts=kwargs["scripts"],
renderer=kwargs["renderer"],
back_to_data_padding=back_to_data_padding,
webroot_html=webroot_html,
github_fork_html=github_fork_html,
app_root=app_root if is_app_root_defined(app_root) else "",
favicon_path=favicon_path,
)
[docs]def build_tab(label, value, additional_style=None, **kwargs):
"""
Builds a :dash:`dash_core_components.Tab <dash-core-components/tab>` with standard styling settings.
"""
base_style = {"borderBottom": "1px solid #d6d6d6", "padding": "6px"}
return dcc.Tab(
label=label,
value=value,
style=dict_merge(base_style, {"fontWeight": "bold"}, additional_style or {}),
disabled_style=dict_merge(
base_style,
{
"fontWeight": "bold",
"backgroundColor": "LightGray",
"color": "black",
"cursor": "not-allowed",
},
additional_style or {},
),
selected_style=dict_merge(
base_style,
{
"borderTop": "1px solid #d6d6d6",
"backgroundColor": "#2a91d1",
"color": "white",
},
additional_style or {},
),
**kwargs
)
CHARTS = [
dict(value="line"),
dict(value="bar"),
dict(value="scatter"),
dict(value="pie"),
dict(value="wordcloud"),
dict(value="heatmap"),
dict(value="3d_scatter", label="3D Scatter"),
dict(value="surface"),
dict(value="maps", label="Maps"),
]
CHART_INPUT_SETTINGS = {
"line": dict(
x=dict(type="single"),
y=dict(type="multi"),
z=dict(display=False),
group=dict(display=True, type="single"),
),
"bar": dict(
x=dict(type="single"),
y=dict(type="multi"),
z=dict(display=False),
group=dict(display=True, type="single"),
),
"scatter": dict(
x=dict(type="single"),
y=dict(type="multi"),
z=dict(display=False),
group=dict(display=True, type="single"),
),
"pie": dict(
x=dict(type="single"),
y=dict(type="multi"),
z=dict(display=False),
group=dict(display=True, type="single"),
),
"wordcloud": dict(
x=dict(type="single"),
y=dict(type="multi"),
z=dict(display=False),
group=dict(display=True, type="single"),
),
"heatmap": dict(
x=dict(type="single"),
y=dict(type="single"),
z=dict(display=True, type="single"),
group=dict(display=False),
),
"3d_scatter": dict(
x=dict(type="single"),
y=dict(type="single"),
z=dict(display=True, type="single"),
group=dict(display=True),
),
"surface": dict(
x=dict(type="single"),
y=dict(type="single"),
z=dict(display=True, type="single"),
group=dict(display=False),
),
"maps": dict(
x=dict(display=False),
y=dict(display=False),
z=dict(display=False),
group=dict(display=False),
map_group=dict(display=True),
),
}
AGGS = dict(
raw="No Aggregation",
count="Count",
nunique="Unique Count",
sum="Sum",
mean="Mean",
rolling="Rolling",
corr="Correlation",
first="First",
last="Last",
median="Median",
min="Minimum",
max="Maximum",
std="Standard Deviation",
var="Variance",
mad="Mean Absolute Deviation",
prod="Product of All Items",
pctct="Percentage Count",
pctsum="Percentage Sum",
)
FREQS = ["H", "H2", "WD", "D", "W", "M", "Q", "Y"]
FREQ_LABELS = dict(
H="Hourly",
H2="Hour",
WD="Weekday",
W="Weekly",
M="Monthly",
Q="Quarterly",
Y="Yearly",
)
MAP_TYPES = [
dict(value="choropleth", image=True),
dict(value="scattergeo", label="ScatterGeo", image=True),
dict(value="mapbox"),
]
SCOPES = ["world", "usa", "europe", "asia", "africa", "north america", "south america"]
PROJECTIONS = [
"equirectangular",
"mercator",
"orthographic",
"natural earth",
"kavrayskiy7",
"miller",
"robinson",
"eckert4",
"azimuthal equal area",
"azimuthal equidistant",
"conic equal area",
"conic conformal",
"conic equidistant",
"gnomonic",
"stereographic",
"mollweide",
"hammer",
"transverse mercator",
"albers usa",
"winkel tripel",
"aitoff",
"sinusoidal",
]
[docs]def build_img_src(proj, img_type="projections"):
return "../images/{}/{}.png".format(img_type, "_".join(proj.split(" ")))
[docs]def build_proj_hover_children(proj):
if proj is None:
return None
return [
html.I(className="ico-help-outline", style=dict(color="white")),
html.Div(
[html.Div(proj), html.Img(src=build_img_src(proj))],
className="hoverable__content",
style=dict(width="auto"),
),
]
[docs]def build_proj_hover(proj):
return html.Span(
[
"Projection",
html.Div(
build_proj_hover_children(proj),
className="ml-3 hoverable",
style=dict(display="none")
if proj is None
else dict(borderBottom="none"),
id="proj-hover",
),
],
className="input-group-addon",
)
[docs]def build_mapbox_token_children():
from dtale.charts.utils import get_mapbox_token
msg = "To access additional styles enter a token here..."
if get_mapbox_token() is None:
msg = "Change your token here..."
return [
html.I(className="ico-help-outline", style=dict(color="white")),
html.Div(
[
html.Span("Mapbox Access Token:"),
dcc.Input(
id="mapbox-token-input",
type="text",
placeholder=msg,
className="form-control",
value="",
style={"lineHeight": "inherit"},
),
],
className="hoverable__content",
style=dict(width="20em", right="-1.45em"),
),
]
[docs]def build_mapbox_token_hover():
return html.Span(
[
"Style",
html.Div(
build_mapbox_token_children(),
className="ml-3 hoverable",
style=dict(borderBottom="none"),
id="token-hover",
),
],
className="input-group-addon",
)
LOC_MODE_INFO = {
"ISO-3": dict(
url=html.A(
"ISO-3",
href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3",
target="_blank",
),
examples=["USA (United States)", "CAN (Canada)", "GBR (United Kingdom)"],
),
"USA-states": dict(
url=html.A(
"USA-states (use ISO)",
href="https://en.wikipedia.org/wiki/List_of_U.S._state_abbreviations",
target="_blank",
),
examples=["NY (New York)", "CA (California)", "MA (Massachusetts)"],
),
"country names": dict(
url=html.A(
"country names (case-insensitive)",
href="https://simple.wikipedia.org/wiki/List_of_countries",
target="_blank",
),
examples=["United States", "United Kingdom", "Germany"],
),
"geojson-id": dict(label="Custom GeoJSON", desc="Load custom geojson into D-Tale"),
}
[docs]def build_loc_mode_hover_children(loc_mode):
if loc_mode is None:
return None
loc_mode_cfg = LOC_MODE_INFO[loc_mode]
url, examples, desc = (loc_mode_cfg.get(p) for p in ["url", "examples", "desc"])
body = []
if url is not None:
body.append(
html.Div([html.Span("View", className="mr-3"), loc_mode_cfg["url"]])
)
if examples is not None:
body.append(
html.Ul(
[
html.Li(e, style={"listStyleType": "disc"}, className="mb-3")
for e in loc_mode_cfg["examples"]
],
className="pt-3 mb-0",
)
)
if desc is not None:
body.append(html.Span(desc))
return [
html.I(className="ico-help-outline", style=dict(color="white")),
html.Div(
body,
className="hoverable__content build-code",
style=dict(width="auto", whiteSpace="nowrap", left="-2em", top="auto"),
),
]
[docs]def build_loc_mode_hover(loc_mode):
return html.Span(
[
html.Span("Location Mode", style=dict(whiteSpace="pre-line")),
html.Div(
build_loc_mode_hover_children(loc_mode),
className="ml-3 hoverable",
style=dict(display="none")
if loc_mode is None
else dict(borderBottom="none"),
id="loc-mode-hover",
),
],
className="input-group-addon pt-1 pb-0",
)
JET = ["#000083", "#003CAA", "#05FFFF", "#FFFF00", "#FA0000", "#800000"]
REDS = ["#fff5f0", "#fdcab4", "#fc8a6a", "#f24632", "#bc141a", "#67000d"]
ANIMATION_CHARTS = ["line"]
ANIMATE_BY_CHARTS = ["bar", "3d_scatter", "maps"]
[docs]def show_input_handler(chart_type):
settings = CHART_INPUT_SETTINGS.get(chart_type or "line") or {}
def _show_input(input_id, input_type="single"):
cfg = settings.get(input_id, {})
return cfg.get("display", True) and cfg.get("type", "single") == input_type
return _show_input
[docs]def show_group_input(inputs, group_cols=None):
chart_type = inputs.get("chart_type")
if show_input_handler(chart_type)("group"):
return len(group_cols or make_list(inputs.get("group")))
elif show_input_handler(chart_type)("map_group"):
return len(group_cols or make_list(inputs.get("map_group")))
return False
[docs]def update_label_for_freq(val):
"""
Formats sub-values contained within 'val' to display date frequencies if included.
- (val=['a', 'b', 'c']) => 'a, b, c'
- (val=['a|H', 'b', 'c']) => 'a (Hour), b, c'
"""
def _freq_handler(sub_val):
for freq in FREQS:
if sub_val.endswith("|{}".format(freq)):
col, freq = sub_val.split("|")
if freq in FREQ_LABELS:
return "{} ({})".format(col, FREQ_LABELS[freq])
return col
return sub_val
return ", ".join([_freq_handler(sub_val) for sub_val in make_list(val)])
[docs]def build_error(error, tb):
"""
Returns error/traceback information in standard component with styling
:param error: execption message
:type error: str
:param tb: tracebackF
:type tb: str
:return: error component
:rtype: :dash:`dash_html_components.Div <dash-html-components/div>`
"""
if isinstance(error, ChartBuildingError):
if error.details:
tb = error.details
error = error.error
return html.Div(
[
html.I(className="ico-error"),
html.Span(str(error)),
html.Div(html.Pre(str(tb)), className="traceback"),
],
className="dtale-alert alert alert-danger",
)
[docs]def build_cols(cols, dtypes):
"""
Helper function to add additional column entries for columns of type datetime so that users can make use of
different frequencies of dates. For example, hour, weekday, month, quarter, year
:param cols: columns in dataframe
:type cols: list of strings
:param dtypes: datatypes of columns in dataframe
:type dtypes: dict
:return: generator or columns + any additional (datetime column + frequency) options
"""
for c in cols:
if classify_type(dtypes[c]) == "D":
for freq in FREQS:
if freq in FREQ_LABELS:
yield "{}|{}".format(c, freq), "{} ({})".format(
c, FREQ_LABELS[freq]
)
else:
yield c, c
else:
yield c, c
[docs]def build_selections(*args):
"""
simple helper function to build a single level list of values based on variable number of inputs which could be
equal to None.
"""
return flatten_lists([[] if a is None else make_list(a) for a in args])
[docs]def build_input_options(df, **inputs):
"""
Builds dropdown options for (X, Y, Z, Group, Barsort & Y-Axis Ranges) with filtering based on currently selected
values for the following inputs: x, y, z, group.
"""
chart_type, x, y, z, group = (
inputs.get(p) for p in ["chart_type", "x", "y", "z", "group"]
)
col_opts = list(build_cols(df.columns, get_dtypes(df)))
group_val, z_val = (None, z) if chart_type in ZAXIS_CHARTS else (group, None)
x_options = [
build_option(c, l)
for c, l in col_opts
if c not in build_selections(y, z_val, group_val)
]
y_filter = build_selections(x, group_val, z_val)
y_multi_options = [build_option(c, l) for c, l in col_opts if c not in y_filter]
y_single_options = [build_option(c, l) for c, l in col_opts if c not in y_filter]
z_options = [
build_option(c)
for c in df.columns
if c not in build_selections(x, y, group_val)
]
group_options = [
build_option(c, l)
for c, l in col_opts
if c not in build_selections(x, y, z_val)
]
barsort_options = [build_option(o) for o in build_selections(x, y)]
yaxis_options = [build_option(y2) for y2 in y or []]
return (
x_options,
y_multi_options,
y_single_options,
z_options,
group_options,
barsort_options,
yaxis_options,
)
[docs]def build_map_options(
df, type="choropleth", loc=None, lat=None, lon=None, map_val=None
):
dtypes = get_dtypes(df)
cols = sorted(dtypes.keys())
float_cols, str_cols, num_cols = [], [], []
for c in cols:
dtype = dtypes[c]
classification = classify_type(dtype)
if classification == "S":
str_cols.append(c)
continue
if classification in ["F", "I"]:
num_cols.append(c)
if classification == "F":
float_cols.append(c)
lat_options = [
build_option(c) for c in float_cols if c not in build_selections(lon, map_val)
]
lon_options = [
build_option(c) for c in float_cols if c not in build_selections(lat, map_val)
]
loc_options = [
build_option(c) for c in str_cols if c not in build_selections(map_val)
]
if type == "choropleth":
val_options = [
build_option(c) for c in num_cols if c not in build_selections(loc)
]
else:
val_options = [
build_option(c) for c in num_cols if c not in build_selections(lon, lat)
]
return loc_options, lat_options, lon_options, val_options
[docs]def build_mapbox_style_options():
from dtale.charts.utils import get_mapbox_token
free_styles = [
"open-street-map",
"carto-positron",
"carto-darkmatter",
"stamen-terrain",
"stamen-toner",
"stamen-watercolor",
]
token_styles = [
"basic",
"streets",
"outdoors",
"light",
"dark",
"satellite",
"satellite-streets",
]
styles = free_styles
if get_mapbox_token() is not None:
styles += token_styles
return [build_option(v) for v in styles]
[docs]def bar_input_style(**inputs):
"""
Sets display CSS property for bar chart inputs
"""
chart_type, group_col = (inputs.get(p) for p in ["chart_type", "group"])
show_bar = chart_type == "bar"
show_barsort = show_bar and group_col is None
return (
dict(display="block" if show_bar else "none"),
dict(display="block" if show_barsort else "none"),
)
[docs]def colorscale_input_style(**inputs):
return dict(
display="block" if inputs.get("chart_type") in ["heatmap", "maps"] else "none"
)
[docs]def animate_styles(df, **inputs):
chart_type, agg, cpg = (inputs.get(p) for p in ["chart_type", "agg", "cpg"])
opts = []
if cpg or agg in ["pctsum", "pctct"]:
return dict(display="none"), dict(display="none"), opts
if chart_type in ANIMATION_CHARTS:
return dict(display="block"), dict(display="none"), opts
if chart_type in ANIMATE_BY_CHARTS:
opts = [build_option(v, l) for v, l in build_cols(df.columns, get_dtypes(df))]
if len(opts):
return dict(display="none"), dict(display="block"), opts
return dict(display="none"), dict(display="none"), []
[docs]def show_chart_per_group(**inputs):
"""
Boolean function to determine whether "Chart Per Group" toggle should be displayed or not
"""
[chart_type, group] = [inputs.get(p) for p in ["chart_type", "group"]]
invalid_type = chart_type in ["pie", "wordcloud", "maps"]
return (
show_input_handler(chart_type)("group")
and len(group or [])
and not invalid_type
)
[docs]def show_yaxis_ranges(**inputs):
"""
Boolean function to determine whether "Y-Axis Range" inputs should be displayed or not
"""
chart_type, y = (inputs.get(p) for p in ["chart_type", "y"])
return chart_type in YAXIS_CHARTS and len(y or [])
[docs]def get_yaxis_type_tabs(y):
tabs = [
build_tab("Default", "default", {"padding": "2px", "minWidth": "4em"}),
build_tab("Single", "single", {"padding": "2px", "minWidth": "4em"}),
]
if len(y) <= 1:
return tabs
return tabs + [build_tab("Multi", "multi", {"padding": "2px", "minWidth": "4em"})]
[docs]def build_group_val_options(df, group_cols):
group_vals = find_group_vals(df, group_cols)
return [
build_option(
json.dumps(gv), "|".join([str(gv.get(p, "NaN")) for p in group_cols])
)
for gv in group_vals
]
[docs]def build_map_type_tabs(map_type):
def _build_hoverable():
for t in MAP_TYPES:
if t.get("image", False):
yield html.Div(
[
html.Span(t.get("label", t["value"].capitalize())),
html.Img(src=build_img_src(t["value"], img_type="map_type")),
],
className="col-md-6",
)
return html.Div(
[
dcc.Tabs(
id="map-type-tabs",
value=map_type or "choropleth",
children=[
build_tab(t.get("label", t["value"].capitalize()), t["value"])
for t in MAP_TYPES
],
style=dict(height="36px"),
),
html.Div(
html.Div(list(_build_hoverable()), className="row"),
className="hoverable__content map-types",
),
],
style=dict(paddingLeft=15, borderBottom="none", width="20em"),
className="hoverable",
)
[docs]def main_inputs_and_group_val_display(inputs):
if show_group_input(inputs):
return dict(display="block"), "col-md-8"
return dict(display="none"), "col-md-12"
[docs]def charts_layout(df, settings, **inputs):
"""
Builds main dash inputs with dropdown options populated with the columns of the dataframe associated with the
page. Inputs included are: chart tabs, query, x, y, z, group, aggregation, rolling window/computation,
chart per group toggle, bar sort, bar mode, y-axis range editors
:param df: dataframe to drive the charts built on page
:type df: :class:`pandas:pandas.DataFrame`
:param settings: global settings associated with this dataframe (contains properties like "query")
:type param: dict
:return: dash markup
"""
chart_type, x, y, z, group, agg = (
inputs.get(p) for p in ["chart_type", "x", "y", "z", "group", "agg"]
)
y = y or []
show_input = show_input_handler(chart_type)
show_cpg = show_chart_per_group(**inputs)
show_yaxis = show_yaxis_ranges(**inputs)
scatter_input = dict(display="block" if chart_type == "scatter" else "none")
bar_style, barsort_input_style = bar_input_style(**inputs)
animate_style, animate_by_style, animate_opts = animate_styles(df, **inputs)
options = build_input_options(df, **inputs)
(
x_options,
y_multi_options,
y_single_options,
z_options,
group_options,
barsort_options,
yaxis_options,
) = options
query_placeholder = "Enter pandas query (ex: col1 == 1)"
query_value = inputs.get("query") or inner_build_query(
settings, settings.get("query")
)
query_label = html.Div(
[
html.Span("Query"),
html.A(
html.I(className="fa fa-info-circle ml-4"),
href="https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#indexing-query",
target="_blank",
style={"color": "white"},
),
],
className="input-group-addon",
style={"minWidth": "7em"},
)
yaxis_type = (inputs.get("yaxis") or {}).get("type") or "default"
yaxis_type_style = (
{"borderRadius": "0 0.25rem 0.25rem 0"} if yaxis_type == "default" else None
)
show_map = chart_type == "maps"
map_props = ["map_type", "loc_mode", "loc", "lat", "lon", "map_val"]
map_type, loc_mode, loc, lat, lon, map_val = (inputs.get(p) for p in map_props)
map_scope, proj, mapbox_style = (
inputs.get(p) for p in ["scope", "proj", "mapbox_style"]
)
loc_options, lat_options, lon_options, map_val_options = build_map_options(
df, type=map_type, loc=loc, lat=lat, lon=lon, map_val=map_val
)
cscale_style = colorscale_input_style(**inputs)
default_cscale = JET if chart_type == "heatmap" else REDS
group_val_style, main_input_class = main_inputs_and_group_val_display(inputs)
group_val = [json.dumps(gv) for gv in inputs.get("group_val") or []]
def show_style(show):
return {"display": "block" if show else "none"}
def show_map_style(show):
return {} if show else {"display": "none"}
return html.Div(
[
dcc.Store(id="query-data", data=inputs.get("query")),
dcc.Store(
id="input-data",
data={
k: v
for k, v in inputs.items()
if k not in ["cpg", "barmode", "barsort"]
},
),
dcc.Store(
id="chart-input-data",
data={
k: v
for k, v in inputs.items()
if k in ["cpg", "barmode", "barsort"]
},
),
dcc.Store(
id="map-input-data",
data={
k: v
for k, v in inputs.items()
if k
in [
"map_type",
"map_code",
"loc_mode",
"lat",
"lon",
"map_val",
"scope",
"proj",
]
},
),
dcc.Store(id="range-data"),
dcc.Store(id="yaxis-data", data=inputs.get("yaxis")),
dcc.Store(id="last-chart-input-data", data=inputs),
dcc.Input(id="chart-code", type="hidden"),
html.Div(
html.Div(
dcc.Tabs(
id="chart-tabs",
value=chart_type or "line",
children=[
build_tab(
t.get("label", t["value"].capitalize()), t["value"]
)
for t in CHARTS
],
style=dict(height="36px"),
),
className="col-md-12",
),
className="row pt-3 pb-3 charts-filters",
),
html.Div(
html.Div(
[
html.Div(
[
query_label,
dcc.Input(
id="query-input",
type="text",
placeholder=query_placeholder,
className="form-control",
value=query_value,
style={"lineHeight": "inherit"},
),
],
className="input-group mr-3",
)
],
className="col",
),
className="row pt-3 pb-3 charts-filters",
),
html.Div(
[
html.Div(
[
html.Div(
[
build_input(
[html.Div("X"), html.Small("(Agg By)")],
dcc.Dropdown(
id="x-dropdown",
options=x_options,
placeholder="Select a column",
value=x,
style=dict(width="inherit"),
),
label_class="input-group-addon d-block pt-1 pb-0",
),
build_input(
"Y",
dcc.Dropdown(
id="y-multi-dropdown",
options=y_multi_options,
multi=True,
placeholder="Select a column(s)",
style=dict(width="inherit"),
value=y
if show_input("y", "multi")
else None,
),
className="col",
id="y-multi-input",
style=show_style(show_input("y", "multi")),
),
build_input(
[html.Div("Y"), html.Small("(Agg By)")],
dcc.Dropdown(
id="y-single-dropdown",
options=y_single_options,
placeholder="Select a column",
style=dict(width="inherit"),
value=y[0]
if show_input("y") and len(y)
else None,
),
className="col",
label_class="input-group-addon d-block pt-1 pb-0",
id="y-single-input",
style=show_style(show_input("y")),
),
build_input(
"Z",
dcc.Dropdown(
id="z-dropdown",
options=z_options,
placeholder="Select a column",
style=dict(width="inherit"),
value=z,
),
className="col",
id="z-input",
style=show_style(show_input("z")),
),
build_input(
"Group",
dcc.Dropdown(
id="group-dropdown",
options=group_options,
multi=True,
placeholder="Select a group(s)",
value=group,
style=dict(width="inherit"),
),
className="col",
id="group-input",
style=show_style(show_input("group")),
),
],
id="non-map-inputs",
style={} if not show_map else {"display": "none"},
className="row p-0 charts-filters",
),
html.Div(
[
build_map_type_tabs(map_type),
html.Div(
[
html.Div(
[
build_loc_mode_hover(loc_mode),
dcc.Dropdown(
id="map-loc-mode-dropdown",
options=[
build_option(
v,
LOC_MODE_INFO[v].get(
"label"
),
)
for v in [
"ISO-3",
"USA-states",
"country names",
"geojson-id",
]
],
style=dict(width="inherit"),
value=loc_mode,
),
],
className="input-group mr-3",
)
],
id="map-loc-mode-input",
style=show_map_style(map_type == "choropleth"),
className="col-auto",
),
custom_geojson.build_modal(map_type, loc_mode),
build_input(
[html.Div("Locations"), html.Small("(Agg By)")],
dcc.Dropdown(
id="map-loc-dropdown",
options=loc_options,
placeholder="Select a column",
value=loc,
style=dict(width="inherit"),
),
id="map-loc-input",
label_class="input-group-addon d-block pt-1 pb-0",
style=show_map_style(map_type == "choropleth"),
),
build_input(
[html.Div("Lat"), html.Small("(Agg By)")],
dcc.Dropdown(
id="map-lat-dropdown",
options=lat_options,
placeholder="Select a column",
value=lat,
style=dict(width="inherit"),
),
id="map-lat-input",
label_class="input-group-addon d-block pt-1 pb-0",
style=show_map_style(
map_type in ["scattergeo", "mapbox"]
),
),
build_input(
[html.Div("Lon"), html.Small("(Agg By)")],
dcc.Dropdown(
id="map-lon-dropdown",
options=lon_options,
placeholder="Select a column",
style=dict(width="inherit"),
value=lon,
),
id="map-lon-input",
label_class="input-group-addon d-block pt-1 pb-0",
style=show_map_style(
map_type in ["scattergeo", "mapbox"]
),
),
build_input(
"Scope",
dcc.Dropdown(
id="map-scope-dropdown",
options=[build_option(v) for v in SCOPES],
style=dict(width="inherit"),
value=map_scope or "world",
),
id="map-scope-input",
style=show_map_style(map_type == "scattergeo"),
),
html.Div(
[
html.Div(
[
build_mapbox_token_hover(),
dcc.Dropdown(
id="map-mapbox-style-dropdown",
options=build_mapbox_style_options(),
style=dict(width="inherit"),
value=mapbox_style
or "open-street-map",
),
],
className="input-group mr-3",
)
],
id="map-mapbox-style-input",
className="col-auto",
style=show_map_style(map_type == "mapbox"),
),
html.Div(
[
html.Div(
[
build_proj_hover(proj),
dcc.Dropdown(
id="map-proj-dropdown",
options=[
build_option(v)
for v in PROJECTIONS
],
style=dict(width="inherit"),
value=proj,
),
],
className="input-group mr-3",
)
],
id="map-proj-input",
style=show_map_style(map_type == "scattergeo"),
className="col-auto",
),
build_input(
"Value",
dcc.Dropdown(
id="map-val-dropdown",
options=map_val_options,
placeholder="Select a column",
style=dict(width="inherit"),
value=map_val,
),
),
build_input(
"Group",
dcc.Dropdown(
id="map-group-dropdown",
options=group_options,
multi=True,
placeholder="Select a group(s)",
value=inputs.get("map_group"),
style=dict(width="inherit"),
),
className="col",
id="map-group-input",
),
],
id="map-inputs",
className="row charts-filters",
style={} if show_map else {"display": "none"},
),
html.Div(
[
build_input(
"Aggregation",
dcc.Dropdown(
id="agg-dropdown",
options=[
build_option(v, AGGS[v])
for v in [
"raw",
"count",
"nunique",
"sum",
"mean",
"rolling",
"corr",
"first",
"last",
"median",
"min",
"max",
"std",
"var",
"mad",
"prod",
"pctsum",
"pctct",
]
],
placeholder="Select an aggregation",
style=dict(width="inherit"),
value=agg or "raw",
),
),
html.Div(
[
build_input(
"Window",
dcc.Input(
id="window-input",
type="number",
placeholder="Enter days",
className="form-control text-center",
style={"lineHeight": "inherit"},
value=inputs.get("window"),
),
),
build_input(
"Computation",
dcc.Dropdown(
id="rolling-comp-dropdown",
options=[
build_option(
"corr", "Correlation"
),
build_option("count", "Count"),
build_option(
"cov", "Covariance"
),
build_option(
"kurt", "Kurtosis"
),
build_option("max", "Maximum"),
build_option("mean", "Mean"),
build_option(
"median", "Median"
),
build_option("min", "Minimum"),
build_option("skew", "Skew"),
build_option(
"std", "Standard Deviation"
),
build_option("sum", "Sum"),
build_option("var", "Variance"),
],
placeholder="Select an computation",
style=dict(width="inherit"),
value=inputs.get("rolling_comp"),
),
),
],
id="rolling-inputs",
style=show_style(agg == "rolling"),
),
],
className="row pt-3 pb-3 charts-filters",
),
html.Div(
[
build_input(
"Chart Per\nGroup",
html.Div(
daq.BooleanSwitch(
id="cpg-toggle",
on=inputs.get("cpg") or False,
),
className="toggle-wrapper",
),
id="cpg-input",
style=show_style(show_cpg),
className="col-auto",
),
build_input(
"Trendline",
dcc.Dropdown(
id="trendline-dropdown",
options=[
build_option("ols"),
build_option("lowess"),
],
value=inputs.get("trendline"),
),
className="col-auto addon-min-width",
style=scatter_input,
id="trendline-input",
),
build_input(
"Barmode",
dcc.Dropdown(
id="barmode-dropdown",
options=[
build_option("group", "Group"),
build_option("stack", "Stack"),
build_option("relative", "Relative"),
],
value=inputs.get("barmode") or "group",
placeholder="Select a mode",
),
className="col-auto addon-min-width",
style=bar_style,
id="barmode-input",
),
build_input(
"Barsort",
dcc.Dropdown(
id="barsort-dropdown",
options=barsort_options,
value=inputs.get("barsort"),
),
className="col-auto addon-min-width",
style=barsort_input_style,
id="barsort-input",
),
html.Div(
html.Div(
[
html.Span(
"Y-Axis",
className="input-group-addon",
),
html.Div(
dcc.Tabs(
id="yaxis-type",
value=yaxis_type,
children=get_yaxis_type_tabs(y),
),
id="yaxis-type-div",
className="form-control col-auto pt-3",
style=yaxis_type_style,
),
dcc.Dropdown(
id="yaxis-dropdown",
options=yaxis_options,
),
html.Span(
"Min:",
className="input-group-addon col-auto",
id="yaxis-min-label",
),
dcc.Input(
id="yaxis-min-input",
type="number",
className="form-control col-auto",
style={"lineHeight": "inherit"},
),
html.Span(
"Max:",
className="input-group-addon col-auto",
id="yaxis-max-label",
),
dcc.Input(
id="yaxis-max-input",
type="number",
className="form-control col-auto",
style={"lineHeight": "inherit"},
),
],
className="input-group",
id="yaxis-min-max-options",
),
className="col-auto addon-min-width",
id="yaxis-input",
style=show_style(show_yaxis),
),
build_input(
"Colorscale",
dcs.DashColorscales(
id="colorscale-picker",
colorscale=inputs.get("colorscale")
or default_cscale,
),
className="col-auto addon-min-width",
style=cscale_style,
id="colorscale-input",
),
build_input(
"Animate",
html.Div(
daq.BooleanSwitch(
id="animate-toggle",
on=inputs.get("animate") or False,
),
className="toggle-wrapper",
),
id="animate-input",
style=animate_style,
className="col-auto",
),
build_input(
"Animate By",
dcc.Dropdown(
id="animate-by-dropdown",
options=animate_opts,
value=inputs.get("animate_by"),
),
className="col-auto addon-min-width",
style=animate_by_style,
id="animate-by-input",
),
],
className="row pt-3 pb-5 charts-filters",
id="chart-inputs",
),
],
id="main-inputs",
className=main_input_class,
),
build_input(
"Group(s)",
dcc.Dropdown(
id="group-val-dropdown",
multi=True,
placeholder="Select a group value(s)",
value=group_val,
style=dict(width="inherit"),
),
className="col-md-4 pt-3 pb-5",
id="group-val-input",
style=group_val_style,
),
],
className="row",
),
dcc.Loading(
html.Div(id="chart-content", style={"height": "69vh"}), type="circle"
),
dcc.Textarea(id="copy-text", style=dict(position="absolute", left="-110%")),
],
className="charts-body",
)