def test_slsh002_sliders_marks_si_unit_format(dash_dcc): LAYOUT = [] # Showing SI Units LAYOUT.extend( [ html.Div( "Testing SI units", style={"marginBottom": 10, "marginTop": 30}, ), ] ) for n in range(-20, 20): min = 0 max = pow(10, n) LAYOUT.extend( [ html.Div( [ html.B( f"min={min}, max={max}(=10^{n})", style={"marginBottom": 15, "marginTop": 25}, ), ( html.Div( "(Known issue: Slider does not seem to work for precision below 10^(-6))" ) if n <= -6 else None ), html.Div("value is undefined"), dcc.Slider(min, max), dcc.RangeSlider(min, max), html.Div(f"value=0.4 * 10^{n}"), dcc.Slider(min, max, value=0.4 * max), dcc.RangeSlider(min, max, value=[0.2 * max, 0.4 * max]), html.Div(f"value=0.5 * 10^{n}"), dcc.Slider(min, max, value=0.5 * max), dcc.RangeSlider(min, max, value=[0.2 * max, 0.5 * max]), ] ) ] ) app = Dash(__name__) app.layout = html.Div(LAYOUT) dash_dcc.start_server(app) dash_dcc.wait_for_element(".rc-slider") dash_dcc.percy_snapshot("slsh002 - test_slsh002_sliders_marks_si_unit_format", True)
def test_slsl013_horizontal_range_slider(dash_dcc): app = Dash(__name__) app.layout = html.Div([ html.Label("Horizontal Range Slider"), dcc.RangeSlider( id="horizontal-range-slider", min=0, max=9, marks={ i: "Label {}".format(i) if i == 1 else str(i) for i in range(1, 6) }, value=[4, 6], ), ]) dash_dcc.start_server(app) dash_dcc.wait_for_element("#horizontal-range-slider") dash_dcc.percy_snapshot("horizontal range slider") dash_dcc.wait_for_element( '#horizontal-range-slider div.rc-slider-handle-1[role="slider"]' ).click() dash_dcc.wait_for_element( '#horizontal-range-slider div.rc-slider-handle-2[role="slider"]' ).click() assert dash_dcc.get_logs() == []
def test_slsl002_always_visible_rangeslider(dash_dcc): app = Dash(__name__) app.layout = html.Div( style={"width": "400px"}, children=[ dcc.RangeSlider( id="rangeslider", min=0, max=20, step=1, value=[5, 15], tooltip={"always_visible": True}, ), html.Div(id="out"), ], ) @app.callback(Output("out", "children"), [Input("rangeslider", "value")]) def update_output(rng): return "You have selected {}-{}".format(*rng) dash_dcc.start_server(app) dash_dcc.wait_for_text_to_equal("#out", "You have selected 5-15") slider = dash_dcc.find_element("#rangeslider") dash_dcc.click_at_coord_fractions(slider, 0.15, 0.25) dash_dcc.wait_for_text_to_equal("#out", "You have selected 2-15") dash_dcc.click_at_coord_fractions(slider, 0.5, 0.25) dash_dcc.wait_for_text_to_equal("#out", "You have selected 2-10") assert dash_dcc.get_logs() == []
def test_slsl014_vertical_range_slider(dash_dcc): app = Dash(__name__) app.layout = html.Div( [ html.Label("Vertical Range Slider"), dcc.RangeSlider( id="vertical-range-slider", min=0, max=9, marks={ i: "Label {}".format(i) if i == 1 else str(i) for i in range(1, 6) }, value=[4, 6], vertical=True, ), ], style={"height": "500px"}, ) dash_dcc.start_server(app) dash_dcc.wait_for_element("#vertical-range-slider") dash_dcc.percy_snapshot("vertical range slider") dash_dcc.wait_for_element( '#vertical-range-slider div.rc-slider-handle-1[role="slider"]').click( ) dash_dcc.wait_for_element( '#vertical-range-slider div.rc-slider-handle-2[role="slider"]').click( ) assert dash_dcc.get_logs() == []
def test_slsl004_out_of_range_marks_rangeslider(dash_dcc): app = Dash(__name__) app.layout = html.Div([ dcc.RangeSlider(min=0, max=5, marks={i: "Label {}".format(i) for i in range(-1, 10)}) ]) dash_dcc.start_server(app) assert len(dash_dcc.find_elements("span.rc-slider-mark-text")) == 6 assert dash_dcc.get_logs() == []
def test_slsl010_range_loading_state(dash_dcc): lock = Lock() app = Dash(__name__) app.layout = html.Div([ html.Button(id="test-btn"), html.Label(id="test-div", children=["Horizontal Range Slider"]), dcc.RangeSlider( id="horizontal-range-slider", min=0, max=9, marks={ i: "Label {}".format(i) if i == 1 else str(i) for i in range(1, 6) }, value=[4, 6], ), ]) @app.callback(Output("horizontal-range-slider", "value"), [Input("test-btn", "n_clicks")]) def delayed_value(children): with lock: return [4, 6] with lock: dash_dcc.start_server(app) dash_dcc.wait_for_element( '#horizontal-range-slider[data-dash-is-loading="true"]') dash_dcc.wait_for_element( '#horizontal-range-slider:not([data-dash-is-loading="true"])') with lock: dash_dcc.wait_for_element("#test-btn").click() dash_dcc.wait_for_element( '#horizontal-range-slider[data-dash-is-loading="true"]') dash_dcc.wait_for_element( '#horizontal-range-slider:not([data-dash-is-loading="true"])') assert dash_dcc.get_logs() == []
def test_slsl008_drag_value_rangeslider(dash_dcc): app = Dash(__name__) app.layout = html.Div([ dcc.RangeSlider( id="slider", min=0, max=20, step=1, value=(5, 15), tooltip={"always_visible": True}, ), html.Div(id="out-value"), html.Div(id="out-drag-value"), ]) @app.callback(Output("out-drag-value", "children"), [Input("slider", "drag_value")]) def update_output1(value): value = value or (None, None) return "You have dragged {}-{}".format(*value) @app.callback(Output("out-value", "children"), [Input("slider", "value")]) def update_output2(value): return "You have selected {}-{}".format(*value) dash_dcc.start_server(app) slider = dash_dcc.find_element("#slider") dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 5-15") dash_dcc.wait_for_text_to_equal("#out-drag-value", "You have dragged 5-15") dash_dcc.click_and_hold_at_coord_fractions(slider, 0.25, 0.25) dash_dcc.move_to_coord_fractions(slider, 0.5, 0.25) dash_dcc.wait_for_text_to_equal("#out-drag-value", "You have dragged 10-15") dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 5-15") dash_dcc.release() dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 10-15") assert dash_dcc.get_logs() == []
def make_menu(self): authoritative_group = self.dao_dnsprobe.make_authoritative_group() probe_group = self.dao_dnsprobe.make_probe_group() rrtype_group = self.dao_dnsprobe.make_rrtype_group() default_authoritative = None default_probe = None default_rrtype = None if authoritative_group: default_authoritative = authoritative_group[0]["value"] if probe_group: default_probe = probe_group[0]["value"] if rrtype_group: default_rrtype = rrtype_group[0]["value"] menu = html.Div([ html.Div([ "Filter by measurement time:", dcc.RangeSlider(id="main-content-menu-filter_measurement_time", min=1, max=24, step=1, value=[21, 24], marks={ 2: "22 hours ago", 9: "15 hours ago", 16: "8 hours ago", 23: "1 horus ago"})], style=dict(width="95%", paddingTop="0.5%", paddingLeft="0%", marginLeft="3%", marginRight="3%", color=self.text_color )), html.Div([ "Filter by authoritative server:", dcc.Dropdown(id="main-content-menu-filter_authoritative", options=authoritative_group, value=default_authoritative, multi=False, style=dict(backgroundColor=self.dropdown_background_color)) ], style=dict(display="inline-block", width="30%", marign="auto", marginTop="0.5%", marginLeft="3%", marginRight="1%", marginBottom="1%", color=self.text_color )), html.Div([ "Filter by Resource Record type:", dcc.Dropdown(id="main-content-menu-filter_rrtype", options=rrtype_group, value=default_rrtype, multi=False, style=dict(backgroundColor=self.dropdown_background_color)) ], style=dict(display="inline-block", width="30%", marign="auto", marginTop="0.5%", marginRight="1%", marginLeft="1%", marginBottom="1%", color=self.text_color )), html.Div([ "Filter by measurer:", dcc.Dropdown(id="main-content-menu-filter_probe", options=probe_group, value=[default_probe], multi=True, style=dict(backgroundColor=self.dropdown_background_color)), ], style=dict(display="inline-block", width="30%", margin="auto", marginTop="0.5%", marginLeft="1%", marginRight="3%", marginBottom="1%", color=self.text_color )) ], id="main-content-menu", style=dict(marginBottom="0.5%", backgroundColor=self.floating_area_background, boxShadow="0 0 10px black")) return menu
def serve_layout(): global cached_layout if cached_layout is None: logger.debug("Create new layout") fig_filter = FigureFilter() try: range_slider = dcc.RangeSlider( id='date-slider', min=min_millis, max=max_millis, step=step, marks=marks, value=[min_millis, max_millis], ) summary_tab = [ dbc.Container(dbc.Row(id="summary-cards", children=create_card( figures.SUMMARY_CARDS)), fluid=True), fig_filter.add_graph(dcc.Graph(id="consumption_fig"), "start_at", ["consumption_km"], figures.consumption_fig), fig_filter.add_graph(dcc.Graph(id="consumption_fig_by_speed"), "speed_average", ["consumption_km"] * 2, figures.consumption_fig_by_speed), fig_filter.add_graph(dcc.Graph(id="consumption_graph_by_temp"), "consumption_by_temp", ["consumption_km"] * 2, figures.consumption_fig_by_temp) ] maps = fig_filter.add_map( dcc.Graph(id="trips_map", style={"height": '90vh'}), "lat", ["long", "start_at"], figures.trips_map) fig_filter.add_table("trips", figures.table_fig) fig_filter.add_table("chargings", figures.battery_table) fig_filter.src = { "trips": trips.get_trips_as_dict(), "chargings": chargings } fig_filter.set_clientside_callback(dash_app) create_callback() except (IndexError, TypeError, NameError, AssertionError, NameError, AttributeError): summary_tab = figures.ERROR_DIV maps = figures.ERROR_DIV logger.warning( "Failed to generate figure, there is probably not enough data yet", exc_info_debug=True) range_slider = html.Div() figures.battery_table = figures.ERROR_DIV data_div = html.Div([ *fig_filter.get_store(), html.Div([ range_slider, dbc.Tabs([ dbc.Tab(label="Summary", tab_id="summary", children=summary_tab), dbc.Tab( label="Trips", tab_id="trips", id="tab_trips", children=[ html.Div(id="tab_trips_fig", children=figures.table_fig), dbc.Modal( [ dbc.ModalHeader("Altitude"), dbc.ModalBody( html.Div(id="tab_trips_popup_graph")), dbc.ModalFooter( dbc.Button("Close", id="tab_trips_popup-close", className="ml-auto")), ], id="tab_trips_popup", size="xl", ) ]), dbc.Tab(label="Charge", tab_id="charge", id="tab_charge", children=[ figures.battery_table, dbc.Modal( [ dbc.ModalHeader("Charging speed"), dbc.ModalBody( html.Div( id="tab_battery_popup_graph")), dbc.ModalFooter( dbc.Button( "Close", id="tab_battery_popup-close", className="ml-auto")), ], id="tab_battery_popup", size="xl", ) ]), dbc.Tab(label="Map", tab_id="map", children=[maps]), dbc.Tab(label="Control", tab_id="control", children=html.Iframe( src=request.url_root + "control?header=false", style={ "position": "absolute", "height": "100%", "width": "100%", "border": "none" })) ], id="tabs", active_tab="summary", persistence=True), html.Div(id=EMPTY_DIV) ]) ]) cached_layout = data_div return cached_layout
def test_slsl006_rangeslider_tooltip(dash_dcc): app = Dash(__name__) app.layout = html.Div([ html.Div( [ html.Div( dcc.RangeSlider( min=0, max=100, value=[0, 65], tooltip={ "always_visible": True, "placement": "top" }, ), style=dict(height=100, marginTop=25), ), html.Div( dcc.RangeSlider( min=0, max=100, value=[0, 65], tooltip={ "always_visible": True, "placement": "top" }, ), style=dict(height=100), ), html.Div( dcc.RangeSlider( min=0, max=100, value=[0, 65], tooltip={ "always_visible": True, "placement": "top" }, ), style=dict(height=100), ), html.Div( dcc.RangeSlider( min=0, max=100, value=[0, 65], tooltip={ "always_visible": True, "placement": "top" }, ), style=dict(height=100), ), html.Div( dcc.RangeSlider( id="test-slider", min=0, max=100, value=[0, 65], tooltip={ "always_visible": True, "placement": "top" }, ), style=dict(height=100), ), ], style=dict( maxHeight=300, overflowX="scroll", backgroundColor="#edf9f7", width=400, ), ) ]) dash_dcc.start_server(app) dash_dcc.wait_for_element("#test-slider") dash_dcc.percy_snapshot("slsl006- dcc.RangeSlider tooltip position")
def __init__( self, device: List[str], calibrate: bool, calibration: List[float], dashboard_host: str, dashboard_port: int, dashboard_signals: int, signal_min_duration_ms: int, signal_max_duration_ms: int, signal_threshold_dbw: float, snr_threshold_db: float, sample_rate: int, center_freq: int, signal_threshold_dbw_max: float = -20, snr_threshold_db_max: float = 50, **kwargs, ): threading.Thread.__init__(self) self.device = device self.calibrate = calibrate self.calibration = calibration self.signal_queue: Deque[Signal] = collections.deque( maxlen=dashboard_signals) self.matched_queue: Deque[MatchingSignal] = collections.deque( maxlen=dashboard_signals) # compute boundaries for sliders and initialize filters frequency_min = center_freq - sample_rate / 2 frequency_max = center_freq + sample_rate / 2 self.app = dash.Dash(__name__, url_base_pathname='/radiotracking/', meta_tags=[{ "name": "viewport", "content": "width=device-width, initial-scale=1" }]) graph_columns = html.Div(children=[], style={"columns": "2 359px"}) graph_columns.children.append( dcc.Graph(id="signal-noise", style={"break-inside": "avoid-column"})) self.app.callback(Output("signal-noise", "figure"), [ Input("update", "n_intervals"), Input("power-slider", "value"), Input("snr-slider", "value"), Input("frequency-slider", "value"), Input("duration-slider", "value"), ])(self.update_signal_noise) graph_columns.children.append( dcc.Graph(id="frequency-histogram", style={"break-inside": "avoid-column"})) self.app.callback(Output("frequency-histogram", "figure"), [ Input("update", "n_intervals"), Input("power-slider", "value"), Input("snr-slider", "value"), Input("frequency-slider", "value"), Input("duration-slider", "value"), ])(self.update_frequency_histogram) graph_columns.children.append( dcc.Graph(id="signal-match", style={"break-inside": "avoid-column"})) self.app.callback(Output("signal-match", "figure"), [ Input("update", "n_intervals"), ])(self.update_signal_match) graph_columns.children.append( dcc.Graph(id="signal-variance", style={"break-inside": "avoid-column"})) self.app.callback(Output("signal-variance", "figure"), [ Input("update", "n_intervals"), Input("power-slider", "value"), Input("snr-slider", "value"), Input("frequency-slider", "value"), Input("duration-slider", "value"), ])(self.update_signal_variance) graph_tab = dcc.Tab(label="tRackIT Signals", children=[]) graph_tab.children.append( html.H4("Running in calibration mode.", hidden=not calibrate, id="calibration-banner", style={ "text-align": "center", "width": "100%", "background-color": "#ffcccb", "padding": "20px", })) self.app.callback(Output("calibration-banner", "hidden"), [ Input("update", "n_intervals"), ])(self.update_calibration_banner) graph_tab.children.append(dcc.Interval(id="update", interval=1000)) self.app.callback(Output("update", "interval"), [Input("interval-slider", "value")])( self.update_interval) graph_tab.children.append(html.Div([ dcc.Graph(id="signal-time"), ])) self.app.callback(Output("signal-time", "figure"), [ Input("update", "n_intervals"), Input("power-slider", "value"), Input("snr-slider", "value"), Input("frequency-slider", "value"), Input("duration-slider", "value"), ])(self.update_signal_time) graph_columns.children.append( html.Div(children=[], id="calibration_output")) self.app.callback(Output("calibration_output", "children"), [ Input("update", "n_intervals"), ])(self.update_calibration) graph_columns.children.append( html.Div( id="settings", style={"break-inside": "avoid-column"}, children=[ html.H2("Vizualization Filters"), html.H3("Signal Power"), dcc.RangeSlider( id="power-slider", min=signal_threshold_dbw, max=signal_threshold_dbw_max, step=0.1, value=[signal_threshold_dbw, signal_threshold_dbw_max], marks={ int(signal_threshold_dbw): f"{signal_threshold_dbw} dBW", int(signal_threshold_dbw_max): f"{signal_threshold_dbw_max} dBW", }, ), html.H3("SNR"), dcc.RangeSlider( id="snr-slider", min=snr_threshold_db, max=snr_threshold_db_max, step=0.1, value=[snr_threshold_db, snr_threshold_db_max], marks={ int(snr_threshold_db): f"{snr_threshold_db} dBW", int(snr_threshold_db_max): f"{snr_threshold_db_max} dBW", }, ), html.H3("Frequency Range"), dcc.RangeSlider( id="frequency-slider", min=frequency_min, max=frequency_max, step=1, marks={ int(frequency_min): f"{frequency_min/1000/1000:.2f} MHz", int(center_freq): f"{center_freq/1000/1000:.2f} MHz", int(frequency_max): f"{frequency_max/1000/1000:.2f} MHz", }, value=[frequency_min, frequency_max], allowCross=False, ), html.H3("Signal Duration"), dcc.RangeSlider( id="duration-slider", min=signal_min_duration_ms, max=signal_max_duration_ms, step=0.1, marks={ int(signal_min_duration_ms): f"{signal_min_duration_ms} ms", int(signal_max_duration_ms): f"{signal_max_duration_ms} ms", }, value=[signal_min_duration_ms, signal_max_duration_ms], allowCross=False, ), html.H2("Dashboard Update Interval"), dcc.Slider( id="interval-slider", min=0.1, max=10, step=0.1, value=1.0, marks={ 0.1: "0.1 s", 1: "1 s", 5: "5 s", 10: "10 s", }, ), ])) graph_tab.children.append(graph_columns) tabs = dcc.Tabs(children=[]) tabs.children.append(graph_tab) self.app.layout = html.Div([tabs]) self.app.layout.style = {"font-family": "sans-serif"} self.server = ThreadedWSGIServer(dashboard_host, dashboard_port, self.app.server) self.calibrations: Dict[float, Dict[str, float]] = {}
def test_slsh001_rangeslider_shorthand_props(dash_dcc): NUMBERS = [10 * N for N in np.arange(1, 2, 0.5)] # TEST_RANGES = [] LAYOUT = [] TEST_CASES = [] for n in NUMBERS: TEST_CASES.extend( [ [n, n * 1.5, abs(n * 1.5 - n) / 5], [-n, 0, n / 10], [-n, n, n / 10], [-1.5 * n, -1 * n, n / 7], ] ) for t in TEST_CASES: min, max, steps = t marks = { i: "Label {}".format(i) if i == 1 else str(i) for i in range(math.ceil(min), math.floor(max)) } LAYOUT.extend( [ html.Div( [ html.Div( f"{min} - {max}", style={"marginBottom": 15, "marginTop": 25}, ), dcc.Slider(min, max), ] ), html.Div( [ html.Div( f"{min} - {max}", style={"marginBottom": 15, "marginTop": 25}, ), dcc.RangeSlider(min, max), ] ), html.Div( [ html.Div( f"{min} - {max}, {steps}", style={"marginBottom": 15, "marginTop": 25}, ), dcc.Slider(min, max, steps), ] ), html.Div( [ html.Div( f"{min} - {max}, {steps}", style={"marginBottom": 15, "marginTop": 25}, ), dcc.RangeSlider(min, max, steps), ] ), html.Div( [ html.Div( f"{min} - {max}, {steps}, value={min + steps}", style={"marginBottom": 15, "marginTop": 25}, ), dcc.Slider(min, max, steps, value=min + steps), ] ), html.Div( [ html.Div( f"{min} - {max}, {steps}, value=[{min + steps},{min + steps * 3}]", style={"marginBottom": 15, "marginTop": 25}, ), dcc.RangeSlider( min, max, steps, value=[min + steps, min + steps * 3] ), ] ), html.Div( [ html.Div( f"{min} - {max}, {steps}, value={min + steps}, marks={marks}", style={"marginBottom": 15, "marginTop": 25}, ), dcc.Slider( min, max, steps, value=min + steps, marks=marks, ), ] ), html.Div( [ html.Div( f"{min} - {max}, {steps},value=[{min + steps},{min + steps * 3}], marks={marks}", style={"marginBottom": 15, "marginTop": 25}, ), dcc.RangeSlider( min, max, steps, value=[min + steps, min + steps * 3], marks=marks, ), ] ), html.Div( [ html.Div( f"{min} - {max}, {steps},value=[{min + steps},{min + steps * 3}], marks=None", style={"marginBottom": 15, "marginTop": 25}, ), dcc.RangeSlider( min, max, steps, value=[min + steps, min + steps * 3], marks=None, ), ] ), ] ) app = Dash(__name__) app.layout = html.Div(LAYOUT) dash_dcc.start_server(app) dash_dcc.wait_for_element(".rc-slider") dash_dcc.percy_snapshot("slsh001 - test_slsh001_rangeslider_shorthand_props", True)
"label": "Option 1", "value": 1 }, { "label": "Option 2", "value": 2 }, ], ), ], className="mb-3", ) slider = html.Div( [ dbc.Label("Slider", html_for="slider"), dcc.Slider(id="slider", min=0, max=10, step=0.5, value=3), ], className="mb-3", ) range_slider = html.Div( [ dbc.Label("RangeSlider", html_for="range-slider"), dcc.RangeSlider(id="range-slider", min=0, max=10, value=[3, 7]), ], className="mb-3", ) form = dbc.Form([dropdown, slider, range_slider])
def filter_layout(self) -> Optional[list]: """Makes dropdowns for each dataframe column used for filtering.""" if not self.use_filter: return None df = self.data dropdowns = [html.H4("Set filters")] for col in self.filter_cols: if df[col].dtype in [np.float64, np.int64]: min_val = df[col].min() max_val = df[col].max() mean_val = df[col].mean() dropdowns.append( html.Div( children=[ html.Details( open=True, children=[ html.Summary(col.lower().capitalize()), dcc.RangeSlider( id=self.uuid(f"filter-{col}"), min=min_val, max=max_val, step=(max_val - min_val) / 10, marks={ min_val: f"{min_val:.2f}", mean_val: f"{mean_val:.2f}", max_val: f"{max_val:.2f}", }, value=[min_val, max_val], ), ], ) ] ) ) else: elements = list(self.data[col].unique()) dropdowns.append( html.Div( children=[ html.Details( open=True, children=[ html.Summary(col.lower().capitalize()), wcc.Select( id=self.uuid(f"filter-{col}"), options=[ {"label": i, "value": i} for i in elements ], value=elements if self.filter_defaults is None else [ element for element in self.filter_defaults.get( col, elements ) if element in elements ], size=min(15, len(elements)), ), ], ) ] ) ) return dropdowns
placeholder="Select a Launch Site here", searchable=True, ), html.Br(), # TASK 2: Add a pie chart to show the total successful launches count for all sites # If a specific launch site was selected, show the Success vs. Failed counts for the site html.Div(dcc.Graph(id="success-pie-chart")), html.Br(), html.P("Payload range (Kg):"), # TASK 3: Add a slider to select payload range dcc.RangeSlider( id="payload-slider", min=0, max=10000, step=1000, marks={ 0: "0", 100: "100" }, value=[min_payload, max_payload], ), # TASK 4: Add a scatter chart to show the correlation between payload and launch success html.Div(dcc.Graph(id="success-payload-scatter-chart")), ]) # TASK 2: # Add a callback function for `site-dropdown` as input, `success-pie-chart` as output @app.callback( Output(component_id="success-pie-chart", component_property="figure"), Input(component_id="site-dropdown", component_property="value"),
def test_msps001_basic_persistence(dash_dcc): app = Dash(__name__) app.layout = html.Div([ dcc.Checklist( id="checklist", options=[ { "label": u"Slow 🐢", "value": u"🐢" }, { "label": u"Fast 🏎️", "value": u"🏎️" }, { "label": u"Faster 🚀", "value": u"🚀" }, ], value=[u"🏎️"], persistence=True, ), dcc.DatePickerRange( id="datepickerrange", start_date="2017-08-21", end_date="2024-04-08", start_date_id="start_date", end_date_id="end_date", initial_visible_month="2019-05-01", persistence=True, ), dcc.DatePickerSingle(id="datepickersingle", date="2019-01-01", persistence=True), dcc.Dropdown( id="dropdownsingle", options=[ { "label": u"One 1️⃣", "value": u"1️⃣" }, { "label": u"Two 2️⃣", "value": u"2️⃣" }, { "label": u"Three 3️⃣", "value": u"3️⃣" }, ], value=u"2️⃣", persistence=True, ), dcc.Dropdown( id="dropdownmulti", options=[ { "label": u"Four 4️⃣", "value": u"4️⃣" }, { "label": u"Five 5️⃣", "value": u"5️⃣" }, { "label": u"Six 6️⃣", "value": u"6️⃣" }, ], value=[u"4️⃣"], multi=True, persistence=True, ), dcc.Input(id="input", value="yes", persistence=True), dcc.RadioItems( id="radioitems", options=[ { "label": "Red", "value": "r" }, { "label": "Green", "value": "g" }, { "label": "Blue", "value": "b" }, ], value="b", persistence=True, ), dcc.RangeSlider(id="rangeslider", min=0, max=10, value=[3, 7], persistence=True), dcc.Slider(id="slider", min=20, max=30, value=25, persistence=True), dcc.Tabs( id="tabs", children=[ dcc.Tab(label="Eh?", children="Tab A", value="A"), dcc.Tab(label="Bee", children="Tab B", value="B"), dcc.Tab(label="Sea", children="Tab C", value="C"), ], value="A", persistence=True, ), dcc.Textarea(id="textarea", value="knock knock", persistence=True), html.Div(id="settings"), ]) @app.callback( Output("settings", "children"), [ Input("checklist", "value"), Input("datepickerrange", "start_date"), Input("datepickerrange", "end_date"), Input("datepickersingle", "date"), Input("dropdownsingle", "value"), Input("dropdownmulti", "value"), Input("input", "value"), Input("radioitems", "value"), Input("rangeslider", "value"), Input("slider", "value"), Input("tabs", "value"), Input("textarea", "value"), ], ) def make_output(*args): return json.dumps(args) initial_settings = [ [u"🏎️"], "2017-08-21", "2024-04-08", "2019-01-01", u"2️⃣", [u"4️⃣"], "yes", "b", [3, 7], 25, "A", "knock knock", ] dash_dcc.start_server(app) dash_dcc.wait_for_text_to_equal("#settings", json.dumps(initial_settings)) dash_dcc.find_element("#checklist label:last-child input").click() # 🚀 dash_dcc.select_date_range("datepickerrange", day_range=(4, )) dash_dcc.select_date_range("datepickerrange", day_range=(14, ), start_first=False) dash_dcc.find_element("#datepickersingle input").click() dash_dcc.select_date_single("datepickersingle", day="20") dash_dcc.find_element("#dropdownsingle .Select-input input").send_keys( "one" + Keys.ENTER) dash_dcc.find_element("#dropdownmulti .Select-input input").send_keys( "six" + Keys.ENTER) dash_dcc.find_element("#input").send_keys(" maybe") dash_dcc.find_element("#radioitems label:first-child input").click() # red range_slider = dash_dcc.find_element("#rangeslider") dash_dcc.click_at_coord_fractions(range_slider, 0.5, 0.25) # 5 dash_dcc.click_at_coord_fractions(range_slider, 0.8, 0.25) # 8 slider = dash_dcc.find_element("#slider") dash_dcc.click_at_coord_fractions(slider, 0.2, 0.25) # 22 dash_dcc.find_element("#tabs .tab:last-child").click() # C dash_dcc.find_element("#textarea").send_keys(Keys.ENTER + "who's there?") edited_settings = [ [u"🏎️", u"🚀"], "2019-05-04", "2019-05-14", "2019-01-20", u"1️⃣", [u"4️⃣", u"6️⃣"], "yes maybe", "r", [5, 8], 22, "C", "knock knock\nwho's there?", ] dash_dcc.wait_for_text_to_equal("#settings", json.dumps(edited_settings)) # now reload the page - all of these settings should persist dash_dcc.wait_for_page() dash_dcc.wait_for_text_to_equal("#settings", json.dumps(edited_settings)) assert dash_dcc.get_logs() == []
app.layout = html.Div( [ html.H3("Results quick browsing analysis"), dcc.Markdown("Select a **primary** feature to filter:"), dcc.Dropdown( id="filter-select-A", options=[{ "label": key, "value": key } for key in df.columns if df[key].dtype == 'float64'], value=df.columns[0], persistence=True, ), dcc.RangeSlider( id="filter-slider-A", persistence=False, ), html.P(id="filter-callback-A"), dcc.Markdown("Select a **secondary** feature to filter:"), dcc.Dropdown( id="filter-select-B", options=[{ "label": key, "value": key } for key in df.columns if df[key].dtype == 'float64'], value=df.columns[0], persistence=True, ), dcc.RangeSlider( id="filter-slider-B", persistence=False,
[ dbc.Container([ dcc.Markdown( d(""" **Recombination points:** Slide to see graph for only part of the sequence. """)), ]), dbc.Container( [ dcc.RangeSlider( id='seq-slider', min=0, max=1000, value=[0, 1000], # step=None, marks={ 0: '0', 1000: '1' }, pushable=30, ) ], style={'padding-bottom': 20}), ], className='pretty_container', ), ], style={ 'padding': 20, 'padding-left': 0, 'padding-top': 0
}, ], value='Degree', searchable=False, ), html.H5('Appearence', className="mt-5 mb-3"), html.H6('Label Size', className="mt-1 mb-2"), dcc.RangeSlider(id='label_size_map', min=0, max=10, step=1, marks={ 0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', }, value=[4, 6]), html.H6('Node Size', className="mt-1 mb-2"), dcc.RangeSlider(id='node_size_map', min=0, max=10, step=1, marks={ 0: '0',
def make_dash_app(self, template='plotly_white', server_mode='external', port=8050, app_type='jupyter', plot_height=680, external_stylesheets=[ 'https://codepen.io/chriddyp/pen/bWLwgP.css' ], infer_proxy=False, slider_width=140, cutout_hdu=None, cutout_size=10): """ Create a Plotly/Dash app for interactive exploration Parameters ---------- template : str `plotly` style `template <https://plotly.com/python/templates/#specifying-themes-in-graph-object-figures>`_. server_mode, port : str, int If not `None`, the app server is started with `app.run_server(mode=server_mode, port=port)`. app_type : str If ``jupyter`` then `app = jupyter_dash.JupyterDash()`, else `app = dash.Dash()` plot_height : int Height in pixels of the scatter and SED+P(z) plot windows. infer_proxy : bool Run `JupyterDash.infer_jupyter_proxy_config()`, before app initilization, e.g., for running on GoogleColab. Returns ------- app : object App object following `app_type`. """ import dash from dash import dcc from dash import html import plotly.express as px from urllib.parse import urlparse, parse_qsl, urlencode import astropy.wcs as pywcs if app_type == 'dash': app = dash.Dash(__name__, external_stylesheets=external_stylesheets) else: from jupyter_dash import JupyterDash if infer_proxy: JupyterDash.infer_jupyter_proxy_config() app = JupyterDash(__name__, external_stylesheets=external_stylesheets) PLOT_TYPES = [ 'zphot-zspec', 'Mag-redshift', 'Mass-redshift', 'UVJ', 'RA/Dec', 'UV-redshift', 'chi2-redshift' ] for _t in self.extra_plots: PLOT_TYPES.append(_t) COLOR_TYPES = ['z_phot', 'z_spec', 'mass', 'sSFR', 'chi2'] #_title = f"{self.photoz.param['MAIN_OUTPUT_FILE']}" #_subhead = f"Nobj={self.photoz.NOBJ} Nfilt={self.photoz.NFILT}" _title = [ html.Strong(self.photoz.param['MAIN_OUTPUT_FILE']), ' / N', html.Sub('obj'), f'={self.photoz.NOBJ}', ' / N', html.Sub('filt'), f'={self.photoz.NFILT}', ] slider_row_style = { 'width': '90%', 'float': 'left', 'margin-left': '10px' } slider_container = { 'width': f'{slider_width}px', 'margin-left': '-25px' } check_kwargs = dict(style={ 'text-align': 'center', 'height': '14pt', 'margin-top': '-20px' }) # bool_options = {'has_zspec': 'z_spec > 0', # 'use': 'Use == 1'} if cutout_hdu is not None: cutout_wcs = pywcs.WCS(cutout_hdu.header, relax=True) cutout_data = cutout_hdu.data print('xxx', cutout_data.shape) cutout_div = html.Div( [dcc.Graph(id='cutout-figure', style={})], style={ 'right': '70px', 'width': '120px', 'height': '120px', 'border': '1px solid rgb(200,200,200)', 'top': '10px', 'position': 'absolute' }) cutout_target = 'figure' else: cutout_div = html.Div(id='cutout-figure', style={ 'left': '1px', 'width': '1px', 'height': '1px', 'bottom': '1px', 'position': 'absolute' }) cutout_data = None cutout_target = 'children' ####### App layout app.layout = html.Div([ # Selectors html.Div( [ dcc.Location(id='url', refresh=False), html.Div([ html.Div(_title, id='title-bar', style={ 'float': 'left', 'margin-top': '4pt' }), html.Div([ html.Div([ dcc.Dropdown(id='plot-type', options=[{ 'label': i, 'value': i } for i in PLOT_TYPES], value='zphot-zspec', clearable=False, style={ 'width': '120px', 'margin-right': '5px', 'margin-left': '5px', 'font-size': '8pt' }), ], style={'float': 'left'}), html.Div([ dcc.Dropdown(id='color-type', options=[{ 'label': i, 'value': i } for i in COLOR_TYPES], value='sSFR', clearable=False, style={ 'width': '80px', 'margin-right': '5px', 'font-size': '8pt' }), ], style={ 'display': 'inline-block', 'margin-left': '10px' }), ], style={'float': 'right'}), ], style=slider_row_style), html.Div( [ html.Div([ dcc.Dropdown( id='mag-filter', options=[{ 'label': i, 'value': i } for i in self.photoz.flux_columns], value=self.DEFAULT_FILTER, style={ 'width': f'{slider_width-45}px', 'margin-right': '20px', 'font-size': '8pt' }, clearable=False), ], style={'float': 'left'}), html.Div([ dcc.RangeSlider(id='mag-slider', min=12, max=32, step=0.2, value=[18, 27], updatemode='drag', tooltip={"placement": 'left'}), dcc.Checklist(id='mag-checked', options=[{ 'label': 'AB mag', 'value': 'checked' }], value=['checked'], **check_kwargs), ], style=dict(display='inline-block', **slider_container)), # html.Div([ dcc.RangeSlider(id='chi2-slider', min=0, max=20, step=0.1, value=[0, 6], updatemode='drag', tooltip={"placement": 'left'}), dcc.Checklist(id='chi2-checked', options=[{ 'label': 'chi2', 'value': 'checked' }], value=[], **check_kwargs), ], style=dict(display='inline-block', **slider_container)), html.Div([ dcc.RangeSlider(id='nfilt-slider', min=1, max=self.MAXNFILT, step=1, value=[3, self.MAXNFILT], updatemode='drag', tooltip={"placement": 'left'}), dcc.Checklist(id='nfilt-checked', options=[{ 'label': 'nfilt', 'value': 'checked' }], value=['checked'], **check_kwargs), ], style=dict(display='inline-block', **slider_container)), ], style=slider_row_style), html.Div( [ html.Div([ dcc.RangeSlider(id='zphot-slider', min=-0.5, max=12, step=0.1, value=[0, self.ZMAX], updatemode='drag', tooltip={"placement": 'left'}), dcc.Checklist(id='zphot-checked', options=[{ 'label': 'z_phot', 'value': 'checked' }], value=['checked'], **check_kwargs), ], style=dict(float='left', **slider_container)), html.Div([ dcc.RangeSlider(id='zspec-slider', min=-0.5, max=12, step=0.1, value=[-0.5, 6.5], updatemode='drag', tooltip={"placement": 'left'}), dcc.Checklist(id='zspec-checked', options=[{ 'label': 'z_spec', 'value': 'checked' }], value=['checked'], **check_kwargs), ], style=dict(display='inline-block', **slider_container)), html.Div([ dcc.RangeSlider(id='mass-slider', min=7, max=13, step=0.1, value=[8, 11.8], updatemode='drag', tooltip={"placement": 'left'}), dcc.Checklist(id='mass-checked', options=[{ 'label': 'mass', 'value': 'checked' }], value=['checked'], **check_kwargs), ], style=dict(display='inline-block', **slider_container)), # Boolean dropdown # dcc.Dropdown(id='bool-checks', # options=[{'label': self.bool_options[k], # 'value': k} # for k in self.bool_options], # value=[], # multi=True, # style={'width':'100px', # 'display':'inline-block', # 'margin-left':'0px', # 'font-size':'8pt'}, # clearable=True), ], style=slider_row_style), ], style={ 'float': 'left', 'width': '55%' }), # Object-level controls html.Div([ html.Div([ html.Div('ID / RA,Dec.', style={ 'float': 'left', 'width': '100px', 'margin-top': '5pt' }), dcc.Input(id='id-input', type='text', style={ 'width': '120px', 'padding': '2px', 'display': 'inline', 'font-size': '8pt' }), html.Div(children='', id='match-sep', style={ 'margin': '5pt', 'display': 'inline', 'width': '50px', 'font-size': '8pt' }), dcc.RadioItems(id='sed-unit-selector', options=[{ 'label': i, 'value': i } for i in ['Fλ', 'Fν', 'νFν']], value='Fλ', labelStyle={ 'display': 'inline', 'padding': '3px', }, style={ 'display': 'inline', 'width': '130px' }) ], style={ 'width': '260pix', 'float': 'left', 'margin-right': '20px' }), ]), html.Div( [ # html.Div([ # ], style={'width':'120px', 'float':'left'}), html.Div(id='object-info', children='ID: ', style={ 'margin': 'auto', 'margin-top': '10px', 'font-size': '10pt' }) ], style={ 'float': 'right', 'width': '45%' }), # Plots html.Div( [ # Scatter plot dcc.Graph(id='sample-selection-scatter', hoverData={ 'points': [{ 'customdata': (self.df['id'][0], 1.0, -9.0) }] }, style={'width': '95%'}) ], style={ 'float': 'left', 'height': '70%', 'width': '49%' }), html.Div( [ # SED dcc.Graph(id='object-sed-figure', style={'width': '95%'}) ], style={ 'float': 'right', 'width': '49%', 'height': '70%' }), cutout_div ]) ##### Callback functions @app.callback(dash.dependencies.Output('url', 'search'), [ dash.dependencies.Input('plot-type', 'value'), dash.dependencies.Input('color-type', 'value'), dash.dependencies.Input('mag-filter', 'value'), dash.dependencies.Input('mag-slider', 'value'), dash.dependencies.Input('mass-slider', 'value'), dash.dependencies.Input('chi2-slider', 'value'), dash.dependencies.Input('nfilt-slider', 'value'), dash.dependencies.Input('zphot-slider', 'value'), dash.dependencies.Input('zspec-slider', 'value'), dash.dependencies.Input('id-input', 'value') ]) def update_url_state(plot_type, color_type, mag_filter, mag_range, mass_range, chi2_range, nfilt_range, zphot_range, zspec_range, id_input): search = f'?plot_type={plot_type}&color_type={color_type}' search += f'&mag_filter={mag_filter}' search += f'&mag={mag_range[0]},{mag_range[1]}' search += f'&mass={mass_range[0]},{mass_range[1]}' search += f'&chi2={chi2_range[0]},{chi2_range[1]}' search += f'&nfilt={nfilt_range[0]},{nfilt_range[1]}' search += f'&zphot={zphot_range[0]},{zphot_range[1]}' search += f'&zspec={zspec_range[0]},{zspec_range[1]}' if id_input is not None: search += f"&id={id_input.replace(' ', '%20')}" return search @app.callback([ dash.dependencies.Output('plot-type', 'value'), dash.dependencies.Output('color-type', 'value'), dash.dependencies.Output('mag-filter', 'value'), dash.dependencies.Output('mag-slider', 'value'), dash.dependencies.Output('mass-slider', 'value'), dash.dependencies.Output('chi2-slider', 'value'), dash.dependencies.Output('nfilt-slider', 'value'), dash.dependencies.Output('zphot-slider', 'value'), dash.dependencies.Output('zspec-slider', 'value'), dash.dependencies.Output('id-input', 'value'), ], [dash.dependencies.Input('url', 'href')]) def set_state_from_url(href): plot_type = 'zphot-zspec' color_type = 'sSFR' mag_filter = self.DEFAULT_FILTER mag_range = [18, 27] mass_range = [8, 11.6] chi2_range = [0, 4] nfilt_range = [1, self.MAXNFILT] zphot_range = [0, self.ZMAX] zspec_range = [-0.5, 6.5] id_input = None if '?' not in href: return (plot_type, color_type, mag_filter, mag_range, mass_range, chi2_range, nfilt_range, zphot_range, zspec_range, id_input) search = href.split('?')[1] params = search.split('&') for p in params: if 'plot_type' in p: val = p.split('=')[1] if val in PLOT_TYPES: plot_type = val elif 'color_type' in p: val = p.split('=')[1] if val in COLOR_TYPES: color_type = val elif 'mag_filter' in p: val = p.split('=')[1] if val in self.photoz.flux_columns: mag_filter = val elif 'mag=' in p: try: vals = [float(v) for v in p.split('=')[1].split(',')] if len(vals) == 2: mag_range = vals except ValueError: pass elif 'mass' in p: try: vals = [float(v) for v in p.split('=')[1].split(',')] if len(vals) == 2: mass_range = vals except ValueError: pass elif 'nfilt=' in p: try: vals = [int(v) for v in p.split('=')[1].split(',')] if len(vals) == 2: nfilt_range = vals except ValueError: pass elif 'zspec' in p: try: vals = [float(v) for v in p.split('=')[1].split(',')] if len(vals) == 2: zspec_range = vals except ValueError: pass elif 'zphot' in p: try: vals = [float(v) for v in p.split('=')[1].split(',')] if len(vals) == 2: zphot_range = vals except ValueError: pass elif 'id' in p: try: id_input = p.split('=')[1].replace('%20', ' ') except ValueError: id_input = None if not id_input: id_input = None return (plot_type, color_type, mag_filter, mag_range, mass_range, chi2_range, nfilt_range, zphot_range, zspec_range, id_input) @app.callback( dash.dependencies.Output('sample-selection-scatter', 'figure'), [ dash.dependencies.Input('plot-type', 'value'), dash.dependencies.Input('color-type', 'value'), dash.dependencies.Input('mag-filter', 'value'), dash.dependencies.Input('mag-slider', 'value'), dash.dependencies.Input('mag-checked', 'value'), dash.dependencies.Input('mass-slider', 'value'), dash.dependencies.Input('mass-checked', 'value'), dash.dependencies.Input('chi2-slider', 'value'), dash.dependencies.Input('chi2-checked', 'value'), dash.dependencies.Input('nfilt-slider', 'value'), dash.dependencies.Input('nfilt-checked', 'value'), dash.dependencies.Input('zphot-slider', 'value'), dash.dependencies.Input('zphot-checked', 'value'), dash.dependencies.Input('zspec-slider', 'value'), dash.dependencies.Input('zspec-checked', 'value'), dash.dependencies.Input('id-input', 'value') ]) def update_selection(plot_type, color_type, mag_filter, mag_range, mag_checked, mass_range, mass_checked, chi2_range, chi2_checked, nfilt_range, nfilt_checked, zphot_range, zphot_checked, zspec_range, zspec_checked, id_input): """ Apply slider selections """ sel = np.isfinite(self.df['z_phot']) if 'checked' in zphot_checked: sel &= (self.df['z_phot'] > zphot_range[0]) sel &= (self.df['z_phot'] < zphot_range[1]) if 'checked' in zspec_checked: sel &= (self.df['z_spec'] > zspec_range[0]) sel &= (self.df['z_spec'] < zspec_range[1]) if 'checked' in mass_checked: sel &= (self.df['mass'] > mass_range[0]) sel &= (self.df['mass'] < mass_range[1]) if 'checked' in chi2_checked: sel &= (self.df['chi2'] >= chi2_range[0]) sel &= (self.df['chi2'] <= chi2_range[1]) if 'checked' in nfilt_checked: sel &= (self.df['nusefilt'] >= nfilt_range[0]) sel &= (self.df['nusefilt'] <= nfilt_range[1]) #print('redshift: ', sel.sum()) if mag_filter is None: mag_filter = self.DEFAULT_FILTER #self.self.df['mag'] = self.ABZP #self.self.df['mag'] -= 2.5*np.log10(self.photoz.cat[mag_filter]) mag_col = 'mag_' + mag_filter if 'checked' in mag_checked: sel &= (self.df[mag_col] > mag_range[0]) sel &= (self.df[mag_col] < mag_range[1]) self.df['mag'] = self.df[mag_col] #print('mag: ', sel.sum()) if plot_type == 'zphot-zspec': sel &= self.df['z_spec'] > 0 #print('zspec: ', sel.sum()) if id_input is not None: id_i, dr_i = parse_id_input(id_input) if id_i is not None: self.df['is_selected'] = self.df['id'] == id_i sel |= self.df['is_selected'] else: self.df['is_selected'] = False else: self.df['is_selected'] = False dff = self.df[sel] # Color-coding by color-type pulldown if color_type == 'z_phot': color_kwargs = dict(color=np.clip(dff['z_phot'], *zphot_range), color_continuous_scale='portland') elif color_type == 'z_spec': color_kwargs = dict(color=np.clip(dff['z_spec'], *zspec_range), color_continuous_scale='portland') elif color_type == 'mass': color_kwargs = dict(color=np.clip(dff['mass'], *mass_range), color_continuous_scale='magma_r') elif color_type == 'chi2': color_kwargs = dict(color=np.clip(dff['chi2'], *chi2_range), color_continuous_scale='viridis') else: color_kwargs = dict(color=np.clip(dff['ssfr'], -12., -8.), color_continuous_scale='portland_r') # Scatter plot plot_defs = { 'Mass-redshift': ('z_phot', 'mass', 'z<sub>phot</sub>', 'log Stellar mass', (-0.1, self.ZMAX), (7.5, 12.5)), 'Mag-redshift': ('z_phot', 'mag', 'z<sub>phot</sub>', f'AB mag ({mag_filter})', (-0.1, self.ZMAX), (18, 28)), 'RA/Dec': ('ra', 'dec', 'R.A.', 'Dec.', self.ra_bounds, self.dec_bounds), 'zphot-zspec': ('z_spec', 'z_phot', 'z<sub>spec</sub>', 'z<sub>phot</sub>', (0, 4.5), (0, 4.5)), 'UVJ': ('vj', 'uv', '(V-J)', '(U-V)', (-0.1, 2.5), (-0.1, 2.5)), 'UV-redshift': ('z_phot', 'uv', 'z<sub>phot</sub>', '(U-V)<sub>rest</sub>', (0, 4), (-0.1, 2.50)), 'chi2-redshift': ('z_phot', 'chi2', 'z<sub>phot</sub>', 'chi<sup>2</sup>', (0, 4), (0.1, 30)) } if plot_type in self.extra_plots: args = (*self.extra_plots[plot_type], {}, color_kwargs) elif plot_type in plot_defs: args = (*plot_defs[plot_type], {}, color_kwargs) else: args = (*plot_defs['zphot-zspec'], {}, color_kwargs) fig = update_sample_scatter(dff, *args) # Update ranges for some parameters if ('Mass' in plot_type) & ('checked' in mass_checked): fig.update_yaxes(range=mass_range) if ('Mag' in plot_type) & ('checked' in mag_checked): fig.update_yaxes(range=mag_range) if ('redshift' in plot_type) & ('checked' in zphot_checked): fig.update_xaxes(range=zphot_range) if ('zspec' in plot_type) & ('checked' in zspec_checked): fig.update_yaxes(range=zspec_range) return fig def update_sample_scatter(dff, xcol, ycol, x_label, y_label, x_range, y_range, extra, color_kwargs): """ Make scatter plot """ import plotly.graph_objects as go fig = px.scatter( data_frame=dff, x=xcol, y=ycol, custom_data=['id', 'z_phot', 'mass', 'ssfr', 'mag'], **color_kwargs) htempl = '(%{x:.2f}, %{y:.2f}) <br>' htempl += 'id: %{customdata[0]:0d} z_phot: %{customdata[1]:.2f}' htempl += '<br> mag: %{customdata[4]:.1f} ' htempl += 'mass: %{customdata[2]:.2f} ssfr: %{customdata[3]:.2f}' fig.update_traces(hovertemplate=htempl, opacity=0.7) if dff['is_selected'].sum() > 0: dffs = dff[dff['is_selected']] _sel = go.Scatter(x=dffs[xcol], y=dffs[ycol], mode="markers+text", text=[f'{id}' for id in dffs['id']], textposition="bottom center", marker=dict(color='rgba(250,0,0,0.5)', size=20, symbol='circle-open')) fig.add_trace(_sel) fig.update_xaxes(range=x_range, title_text=x_label) fig.update_yaxes(range=y_range, title_text=y_label) fig.update_layout(template=template, autosize=True, showlegend=False, margin=dict(l=0, r=0, b=0, t=20, pad=0, autoexpand=True)) if plot_height is not None: fig.update_layout(height=plot_height) fig.update_traces(marker_showscale=False, selector=dict(type='scatter')) fig.update_coloraxes(showscale=False) if (xcol, ycol) == ('z_spec', 'z_phot'): _one2one = go.Scatter(x=[0, 8], y=[0, 8], mode="lines", marker=dict(color='rgba(250,0,0,0.5)')) fig.add_trace(_one2one) fig.add_annotation(text=f'N = {len(dff)} / {len(self.df)}', xref="x domain", yref="y domain", x=0.98, y=0.05, showarrow=False) return fig def sed_cutout_figure(id_i): """ SED cutout """ from plotly.subplots import make_subplots if cutout_data is not None: ix = np.where(self.df['id'] == id_i)[0] ri, di = self.df['ra'][ix], self.df['dec'][ix] xi, yi = np.squeeze(cutout_wcs.all_world2pix([ri], [di], 0)) xp = int(np.round(xi)) yp = int(np.round(yi)) slx = slice(xp - cutout_size, xp + cutout_size + 1) sly = slice(yp - cutout_size, yp + cutout_size + 1) try: cutout = cutout_data[sly, slx] except: cutout = np.zeros((2 * cutout_size, 2 * cutout_size)) fig = px.imshow(cutout, color_continuous_scale='gray_r') fig.update_coloraxes(showscale=False) fig.update_layout(width=120, height=120, margin=dict(l=0, r=0, b=0, t=0, pad=0, autoexpand=True)) fig.update_xaxes(range=(0, 2 * cutout_size), visible=False, showticklabels=False) fig.update_yaxes(range=(0, 2 * cutout_size), visible=False, showticklabels=False) return fig def parse_id_input(id_input): """ Parse input as id or (ra dec) """ if id_input in ['None', None, '']: return None, None inp_split = id_input.replace(',', ' ').split() if len(inp_split) == 1: return int(inp_split[0]), None ra, dec = np.cast[float](inp_split) cosd = np.cos(self.df['dec'] / 180 * np.pi) dx = (self.df['ra'] - ra) * cosd dy = (self.df['dec'] - dec) dr = np.sqrt(dx**2 + dy**2) * 3600. imin = np.nanargmin(dr) return self.df['id'][imin], dr[imin] @app.callback([ dash.dependencies.Output('object-sed-figure', 'figure'), dash.dependencies.Output('object-info', 'children'), dash.dependencies.Output('match-sep', 'children'), dash.dependencies.Output('cutout-figure', cutout_target) ], [ dash.dependencies.Input('sample-selection-scatter', 'hoverData'), dash.dependencies.Input('sed-unit-selector', 'value'), dash.dependencies.Input('id-input', 'value') ]) def update_object_sed(hoverData, sed_unit, id_input): """ SED + p(z) plot """ id_i, dr_i = parse_id_input(id_input) if id_i is None: id_i = hoverData['points'][0]['customdata'][0] else: if id_i not in self.zout['id']: id_i = hoverData['points'][0]['customdata'][0] if dr_i is None: match_sep = '' else: match_sep = f'{dr_i:.1f}"' show_fnu = {'Fλ': 0, 'Fν': 1, 'νFν': 2} layout_kwargs = dict(template=template, autosize=True, showlegend=False, margin=dict(l=0, r=0, b=0, t=20, pad=0, autoexpand=True)) fig = self.photoz.show_fit_plotly(id_i, show_fnu=show_fnu[sed_unit], vertical=True, panel_ratio=[0.6, 0.4], show=False, layout_kwargs=layout_kwargs) if plot_height is not None: fig.update_layout(height=plot_height) ix = self.df['id'] == id_i if ix.sum() == 0: object_info = 'ID: N/A' else: ix = np.where(ix)[0][0] ra, dec = self.df['ra'][ix], self.df['dec'][ix] object_info = [ f'ID: {id_i} | α, δ = {ra:.6f} {dec:.6f} ', ' | ', html.A('ESO', href=utils.eso_query(ra, dec, radius=1.0, unit='s')), ' | ', html.A('CDS', href=utils.cds_query(ra, dec, radius=1.0, unit='s')), ' | ', html.A('LegacySurvey', href=utils.show_legacysurvey(ra, dec, layer='ls-dr9')), html.Br(), f"z_phot: {self.df['z_phot'][ix]:.3f} ", f" | z_spec: {self.df['z_spec'][ix]:.3f}", html.Br(), f"mag: {self.df['mag'][ix]:.2f} ", f" | mass: {self.df['mass'][ix]:.2f} ", f" | sSFR: {self.df['ssfr'][ix]:.2f}", html.Br() ] if cutout_data is None: cutout_fig = [''] else: cutout_fig = sed_cutout_figure(id_i) return fig, object_info, match_sep, cutout_fig if server_mode is not None: app.run_server(mode=server_mode, port=port) return app
# create slider layouts # obtain numerical values num_values = [] new_slider = [] for idx, item in enumerate(num_keys): # use `.tolist()` to convert numpy type ot python type var_min = np.floor(np.min(new_data[item])).tolist() var_max = np.ceil(np.max(new_data[item])).tolist() new_slider.append(dbc.Label(keys_dict[item]['description'])) new_slider.append( dcc.RangeSlider(id={ 'type': 'filter-slider', 'index': idx }, min=var_min, max=var_max, marks=None, step=round((var_max - var_min) / 100, 3), value=[var_min, var_max], tooltip={'always_visible': False})) num_values.append([var_min, var_max]) # save categorical values and numerical values to Redis filter_kwargs['num_values'] = num_values filter_kwargs['cat_values'] = cat_values cache_set(filter_kwargs, session_id, CACHE_KEYS['filter_kwargs']) # dimensions picker default value if len(cat_keys) == 0: t_values_cat = None
placeholder="Select a launch site", searchable=True), html.Br(), # TASK 2: Add a pie chart to show the total successful launches count for all sites # If a specific launch site was selected, show the Success vs. Failed counts for the site html.Div(dcc.Graph(id='success-pie-chart')), html.Br(), html.P("Payload range (Kg):"), # TASK 3: Add a slider to select payload range dcc.RangeSlider(id='payload-slider', min=0, max=10000, step=1000, marks={ 0: '0', 2500: '2500', 5000: '5000', 7500: '7500', 10000: '10000' }, value=[min_payload, max_payload]), # TASK 4: Add a scatter chart to show the correlation between payload and launch success html.Div(dcc.Graph(id='success-payload-scatter-chart')), ]) # TASK 2: # Add a callback function for `site-dropdown` as input, `success-pie-chart` as output @app.callback( Output(component_id='success-pie-chart', component_property='figure'),
style={ "textDecoration": "underline", "fontSize": 20 }, ), dcc.RangeSlider( id="years-range", min=2005, max=2016, step=1, value=[2005, 2006], marks={ 2005: "2005", 2006: "'06", 2007: "'07", 2008: "'08", 2009: "'09", 2010: "'10", 2011: "'11", 2012: "'12", 2013: "'13", 2014: "'14", 2015: "'15", 2016: "2016", }, ), dbc.Button( id="my-button", children="Submit", n_clicks=0, color="primary",
}, ], value='ALL', placeholder='select a Launch Site here', searchable=True), html.Br(), # TASK 2: Add a pie chart to show the total successful launches count for all sites # If a specific launch site was selected, show the Success vs. Failed counts for the site html.Div(dcc.Graph(id='success-pie-chart')), html.Br(), html.P("Payload range (Kg):"), # TASK 3: Add a slider to select payload range dcc.RangeSlider(id='payload-slider', min=0, max=10000, step=1000, value=[min_payload, max_payload]), # TASK 4: Add a scatter chart to show the correlation between payload and launch success html.Div(dcc.Graph(id='success-payload-scatter-chart')), ]) # TASK 2: # Add a callback function for `site-dropdown` as input, `success-pie-chart` as output @app.callback( Output(component_id='success-pie-chart', component_property='figure'), Input(component_id='site-dropdown', component_property='value')) def pie(site_dropdown): if site_dropdown == 'ALL':
"label": i, "value": i } for i in df_stations.Stationsname.unique()], placeholder="Select weather station...", value="Essen-Bredeney", ), ]), html.Br(), html.Div([ html.Label("Year Slider", id="time-range-label"), dcc.RangeSlider( id="year-slider", min=df_weather["year"].min(), max=df_weather["year"].max(), value=[df_weather["year"].min(), df_weather["year"].max()], marks={ str(year): str(year) for year in df_weather["year"].unique() if year % 5 == 0 }, step=1, ), ]), html.Br(), html.Div([ html.Label("Period Slider", id="period-range-label"), dcc.RangeSlider( id="period-slider", min=df_weather["period_int"].min(), max=df_weather["period_int"].max(), value=[ df_weather["period_int"].min(),