def make_buttons( cls, *, label: str, values: Iterable[str], selectors: dict[str, str], defaults: Iterable[bool] = None, ) -> list[dbc.Button]: values = list(values) defaults = list(defaults) if defaults else ([True] * len(values)) return [ dbc.Button( label, id=dict(_btn_type=TOGGLE_BUTTON_DUMMY, **selectors), className=f"{TOGGLE_BUTTON} {TOGGLE_BUTTON_DUMMY}", color="primary", disabled=True, ), *[ dbc.Button( key, className=TOGGLE_BUTTON, id=dict(_btn_type=TOGGLE_BUTTON, key=key, **selectors), outline=True, active=default, color="info", ) for key, default in zip(values, defaults) ], Store( id=dict(_btn_type=TOGGLE_BUTTON_STATE, **selectors), storage_type="session", ), Store( id=dict(_btn_type=TOGGLE_BUTTON_DEFAULT_STATE, **selectors), storage_type="session", data=defaults, ), Store( id=dict(_btn_type=TOGGLE_BUTTON_STATE_IX, **selectors), data={value: ix for ix, value in enumerate(values)}, ), html.Br(), ]
def get_html(self): """Glues individual setup components together """ return Div( className="app", children=self.components["navbar"].html + [ Div( className="app-content", children=self.components["sidebar"].html + self.components["index"].html ), Store(id="root-store"), Location(id='location') ] )
def get_html(self) -> List[ComponentMeta]: """Initializes the view """ elements = [ Store(id="sidebar-store") ] for idx, data in _SIDEBAR_ELEMENTS.items(): if data["type"] == "number": element = create_number_input(idx, data, self.content, self.defaults) elif data["type"] == "switch": element = create_switch_input(idx, data, self.content) elif data["type"] == "date": element = create_date_input(idx, data, self.content, self.defaults) elif data["type"] == "header": element = create_header(idx, self.content) elif data["type"] == "linebreak": element = create_line_break(idx) else: raise ValueError( "Failed to parse input '{idx}' with data '{data}'".format( idx=idx, data=data ) ) elements.append(element) sidebar = Nav( className="bg-light border-right", children=Div( children=elements, className="px-3 pb-5", ), style={ "bottom": 0, "left": 0, "overflowY": "scroll", "position": "fixed", "top": "56px", "width": "320px", "zIndex": 1, "padding-top": "1rem", }, ) return [sidebar]
def _create_dash_components(self): """Create the graph, slider, figure, etc.""" info = self._slice_info # Prep low-res slices. The get_thumbnail_size() is a bit like # a simulation to get the low-res size. if not self._thumbnail: thumbnail_size = None info["thumbnail_size"] = info["size"] else: thumbnail_size = self._thumbnail info["thumbnail_size"] = get_thumbnail_size( info["size"][:2], thumbnail_size) thumbnails = [ img_array_to_uri(self._slice(i), thumbnail_size) for i in range(info["size"][2]) ] # Create the figure object - can be accessed by user via slicer.graph.figure self._fig = fig = plotly.graph_objects.Figure(data=[]) fig.update_layout( template=None, margin={ "l": 0, "r": 0, "b": 0, "t": 0, "pad": 4 }, dragmode="pan", # good default mode ) fig.update_xaxes( showgrid=False, showticklabels=False, zeroline=False, autorange=True, constrain="range", ) fig.update_yaxes( showgrid=False, scaleanchor="x", showticklabels=False, zeroline=False, autorange="reversed" if self._reverse_y else True, constrain="range", ) # Create the graph (graph is a Dash component wrapping a Plotly figure) self._graph = Graph( id=self._subid("graph"), figure=fig, config={"scrollZoom": True}, ) # Create a slider object that the user can put in the layout (or not). # Note that the tooltip introduces a measurable performance penalty, # so maybe we can display it in a different way? self._slider = Slider( id=self._subid("slider"), min=0, max=info["size"][2] - 1, step=1, value=info["size"][2] // 2, updatemode="drag", tooltip={ "always_visible": False, "placement": "left" }, ) # Create the stores that we need (these must be present in the layout) # A dict of static info for this slicer self._info = Store(id=self._subid("info"), data=info) # A list of low-res slices, or the full-res data (encoded as base64-png) self._thumbs_data = Store(id=self._subid("thumbs"), data=thumbnails) # A list of mask slices (encoded as base64-png or null) self._overlay_data = Store(id=self._subid("overlay"), data=[]) # Slice data provided by the server self._server_data = Store(id=self._subid("server-data"), data={ "index": -1, "slice": None }) # Store image traces for the slicer. self._img_traces = Store(id=self._subid("img-traces"), data=[]) # Store indicator traces for the slicer. self._indicator_traces = Store(id=self._subid("indicator-traces"), data=[]) # Store user traces for the slider. self._extra_traces = Store(id=self._subid("extra-traces"), data=[]) # A timer to apply a rate-limit between slider.value and index.data self._timer = Interval(id=self._subid("timer"), interval=100, disabled=True) # The (public) state of the slicer. This value is rate-limited. Initially null. self._state = Store(id=self._subid("state", True), data=None) # Signal to set the position of other slicers with the same scene_id. self._setpos = Store(id=self._subid("setpos", True), data=None) self._stores = [ self._info, self._thumbs_data, self._overlay_data, self._server_data, self._img_traces, self._indicator_traces, self._extra_traces, self._timer, self._state, self._setpos, ]
logging.info(f'create_df_download - df_download.head(): \n{df_download.head()}\n') # save the variable inside the cache cache.set('download:df_download', df_download) return df_download df_download = create_df_download(df_base) minmax = get_minmax_from_df(df_download) layout = Div([ # a storage to save the signal to update the tables and graphs Store(id='download--store--signal'), # title and subtitle Div([ # title H1(children='catalog-dash'), # subtitle H3(children='Download table analysis') ], style={'textAlign': 'center', 'color': colors['text']}), # top tables - information table, date picker range and limit Div([ # left table - information table Div([ # title P(
value=1, style={"margin-bottom": "4%"}, ), ], className="scenario-input", style={ "background-color": "rgb(234, 234, 234)", "font-size": "16px" }, ) # Layout app.layout = Div( [ Div([Store(x + "-store-" + str(i)) for x in TAB_DICT.keys() for i in [1, 2]]), # header Div( Div( children=[ Span( "Using an ‘agent based model’ for data policy decision-making" ), Div( A( Img( src="/assets/basic-W-48px.png", height="80%", style={"align": "center"}, ), href="https://theodi.org",
logging.info(f'create_df_sd_ds_ym_long_lat - df_sd_ds_ym_long_lat.head(): \n{df_sd_ds_ym_long_lat.head()}\n') # save the variable inside the cache cache.set('scene:df_sd_ds_ym_long_lat', df_sd_ds_ym_long_lat) return df_sd_ds_ym_long_lat df_sd_ds_ym_long_lat = create_df_sd_ds_ym_long_lat(df_base) minmax = get_minmax_from_df(df_sd_ds_ym_long_lat) layout = Div([ # a storage to save the signal to update the tables and graphs Store(id='scene--store--signal'), # title and subtitle Div([ # title H1(children='catalog-dash'), # subtitle H3(children='Scene table analysis'), ], style={'textAlign': 'center', 'color': colors['text']}), # number of scenes and information tables Div([ # left div - number of scenes table Div([ # title P(
def setup_dash_layout(app: Dash, sk: DivSkeleton) -> dash.Dash: def create_sliders( ) -> tuple[RangeSlider, RangeSlider, RangeSlider, RangeSlider]: slider_height = 460 year_slider = RangeSlider( INPID_YEAR, min=(mn := etl.ATTRS.index.get_level_values("year").min()), max=(mx := etl.ATTRS.index.get_level_values("year").max()), value=[2012, 2018], marks={y: str(y) for y in range(mn, mx + 1)}, vertical=True, verticalHeight=slider_height, updatemode="mouseup", **PERSIST_ARGS, ) mileage_slider = RangeSlider( INPID_MILEAGE, min=0, max=etl.MAX_MILEAGE, value=[10000, 70000], marks={ y: f"{y // 1000}k" for y in range(0, etl.MAX_MILEAGE, 25_000) }, step=1, vertical=True, updatemode="mouseup", verticalHeight=slider_height, **PERSIST_ARGS, ) price_slider = RangeSlider( INPID_PRICE, min=0, max=etl.MAX_PRICE, value=[10000, 35000], marks={ int(y): f"{y // 1000}k" for y in range(0, etl.MAX_PRICE, 10_000) }, step=1, vertical=True, updatemode="mouseup", verticalHeight=slider_height, **PERSIST_ARGS, ) mpg_slider = RangeSlider( INPID_MPG, min=etl.ATTRS["mpg"].min(), max=(mx := etl.ATTRS["mpg"].max()), value=[20, mx], marks={int(y): f"{y:.0f}" for y in range(10, int(mx) + 1, 10)}, step=1, vertical=True, updatemode="mouseup", verticalHeight=slider_height, **PERSIST_ARGS, ) return year_slider, mileage_slider, price_slider, mpg_slider for name, slider, div_id in zip( ["Year", "Mileage", "Price", "MPG"], create_sliders(), [SK_SLIDER_MILEAGE, SK_SLIDER_PRICE, SK_SLIDER_YEAR, SK_SLIDER_MPG], ): sk.fill( div_id, [dbc.Badge(name, color="primary", className="slider"), slider], ) top_selectors = [ dbc.Alert("Select your location.", id="alert-loc-picker", color="primary"), Dropdown( id=INPID_ZIPCODE, placeholder="Zipcode", clearable=False, options=opts_from_vals(etl.LATLONG_BY_ZIP.keys()), **PERSIST_ARGS, ), Slider( id=INPID_MAX_DIST, className="form-control", min=10, max=250, marks={ mark: dict(label=str(mark) + ("mi." if mark == 10 else "")) for mark in [10, 50, 100, 150, 200, 250] }, value=50, **PERSIST_ARGS, ), dbc.Alert("Limit dealership states.", id="alert-state-picker", color="primary"), Dropdown( id=INPID_STATE, # options by callback multi=True, **PERSIST_ARGS, ), Div( id="plot-info-flex", children=[ dbc.Button(children="Plot Cars Now!", id=PLOT_BUTTON, color="success"), Div( id=PLOT_ALERT_BOX, children=dbc.Alert(id=PLOT_ALERT, children="", color="danger"), hidden=True, ), dbc.Alert("Plot does not refresh automatically.", color="light"), ], style={ "display": "flex", "flex-direction": "column-reverse" }, ), ] ## car options pickers top_selectors.extend([]) ### ## # === BOTTOM ROW === ## ### sk.fill(SK_TOP_SELECTORS, top_selectors) mm_picker_menu = [ dbc.Alert( "Select makes and models you are interested in. " "Filtered by sliders.", id=ALERT_MM_PICKER, color="primary", ), Dropdown( id=INPID_MM_PICKER, # options by callback multi=True, placeholder="Select makes", clearable=False, **PERSIST_ARGS, ), ] sk.fill(SK_MM_PICKER, mm_picker_menu) sk.fill( SK_LL_INFO, dbc.Alert( id="alert-site-info", children=( "Used car picker by Evgeny Naumov.", html.Br(), "Built on top of Truecar data with Plotly + Dash.", ), color="light", ), ) # car type options button_layout = { ("Transmission", INPID_OPTS_TRANS): scr.TRANSMISSIONS, ("Fuel Type", INPID_OPTS_FUEL): scr.KNOWN_FUEL_TYPES, ("Drivetrain", INPID_OPTS_DRIVETRAIN): scr.KNOWN_DRIVETRAINS, ("Body", INPID_OPTS_BODY): scr.KNOWN_BODIES, } car_opt_picker = [ dbc.Alert("Select car attributes.", color="primary"), Div( id="car-opts-box", className=TOGGLE_BUTTON_BOX, children=[ button for (inp_name, inp_id), inp_opts in button_layout.items() for button in ToggleButtonGroup.make_buttons( label=inp_name, values=inp_opts, selectors=dict(input=inp_id), ) ], ), ] sk.fill(SK_CAR_OPTS_BOX, car_opt_picker) mmt_refine_menu = [ dbc.Alert("Select models to refine trims.", id="mmt-alert", color="secondary"), Div(id="mmt-card-group"), ] sk.fill(SK_MMT_MATRIX, mmt_refine_menu) sk.fill( SK_CACHE, [ Interval(IVAL_TRIGGER_LOAD, max_intervals=1, interval=1), Store( id=STORE_ALL_CARS, storage_type="memory", data=etl.RAW_CLIENT_DATA, ), Store(id=STORE_FILTERED_CARS, storage_type="session"), Div(id="devnull"), ], ) ## GRAPH scatter_graph = html.Div( id="scatter-box", children=Graph(id="scatter-price-mileage"), hidden=True, ) sk.fill(SK_SCATTER, scatter_graph) ### ALERTS alert_link = dbc.Alert( id="output-link", children="A plot of listings will appear above when executed.", color="secondary", ) sk.fill(SK_INFO_A, alert_link) app.layout = sk["root"] return app
def get_store(self): return [Store(id='clientside-figure-store', data=self.__get_figures()), Store(id='clientside-data-store', data=self.src)]