Additional elements inline with Dash's dcc.Tabs? - python

For my Dash app, I want to create a navigation bar that has links to the different pages but also additional stuff, e.g. the currently logged in user, and logos and stuff.
However, I unfortunately cannot use pages (Like in the "Navbar" example in dbc) since the WebApp has to be hosted as a single-url app inside another tool. My only option is to got with dcc.Tabs.
However, it looks to me like dcc.Tabs forces a newline behind the Tabs. I tried different things to prevent that, but nothing seems to be working. The best I got so far is the example below. How do I make it so that the text is in the same row as the Tabs element?
tabs_styles = {
'height': '44px', "width": "49%", "display":"inline-block"
}
app.layout = html.Div(children=[
html.Div(children=[
dcc.Tabs(id="tabs-styled-with-inline", value='tab-1', children=[
dcc.Tab(label='Page1', value='tab-1', style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label='Page2', value='tab-2', style=tab_style, selected_style=tab_selected_style),
], style=tabs_styles)]),
html.Span(children=[
" Logged in as ",
html.Strong(id="username")
], style = tabs_styles),
html.Div(children=[
# Distance to header:
html.Hr(),
html.Div(id='tabs-content-inline')
])
])

Your inline style should be applied to the parent div of your Tabs component. I made some small modifications here (look at tabs_container_styles):
tabs_styles = {"height": "44px"}
tabs_container_styles = {"width": "49%", "display": "inline-block"}
app.layout = html.Div(
children=[
html.Div(
children=[
dcc.Tabs(
id="tabs-styled-with-inline",
value="tab-1",
children=[
dcc.Tab(label="Page1", value="tab-1"),
dcc.Tab(label="Page2", value="tab-2"),
],
style=tabs_styles,
)
],
style=tabs_container_styles,
),
html.Span(
children=[" Logged in as ", html.Strong(id="username")], style=tabs_styles
),
html.Div(
children=[
# Distance to header:
html.Hr(),
html.Div(id="tabs-content-inline"),
]
),
]
)

Set the parent_style property of your Tabs component instead of the style property and move your Span component to be a child of the div containing your Tabs component.
parent_style (dict; optional): Appends (inline) styles to the top-level parent container holding both the Tabs container and the content container.
style (dict; optional): Appends (inline) styles to the Tabs container holding the individual Tab components.
https://dash.plotly.com/dash-core-components/tabs
MRE
from dash import Dash, html, dcc
tabs_styles = {"height": "44px", "width": "49%", "display": "inline-block"}
app = Dash()
app.layout = html.Div(
children=[
html.Div(
children=[
dcc.Tabs(
id="tabs-styled-with-inline",
value="tab-1",
children=[
dcc.Tab(
label="Page1", value="tab-1", style={}, selected_style={}
),
dcc.Tab(
label="Page2", value="tab-2", style={}, selected_style={}
),
],
parent_style=tabs_styles,
),
html.Span(
children=[" Logged in as ", html.Strong(id="username")], style=tabs_styles
),
]
),
html.Div(
children=[
# Distance to header:
html.Hr(),
html.Div(id="tabs-content-inline"),
]
),
]
)
if __name__ == "__main__":
app.run_server()

Related

Dash and Plotly - using CSS to style elements of the same class name

I would like to use a css stylesheet to keep most of the styling for my dash app in a separate file, but the problem is that a lot of my components use the name classname: className='col-2' or className='col-3'. My understanding is that using className='col-2' specifies the number of columns and helps with layout, but I want to create a boarder next to some divs and it's impossible using classnames. Is there another way to do this?
Below are two columns from my code, they both use className='col-3'. Problem is that when I create a stylesheet with background color and border, the same style is applied to my header which also has a component with col-3.
/////STYLESHEET///////
.col-3{
border: 2px solid darkgray;
background-color:#FFFFFF
}
//////DASH-APP/////// fragment of code
row1_col1 = html.Div(children=[
#DIV 6 - row
html.Div(children=[
html.Br(),
#DIV 2
html.Div(children=[
html.H4(children="Select By University",
style={'textAlign':'center','height': '25px','fontSize': 18}),
# DIV 3 selection
html.Div(children=dd1_select_univ,
style={'padding-left':'3%'})
],
#className='row',
style={'color':font_color, 'fontSize': 12},className='col-6'),
#DIV 3
html.Div(children=[
html.H4(children="Search by Publication",
style={'textAlign':'center','height': '25px','fontSize': 18}),
# DIV 5- selection
html.Div(children=inp1_public_title,
style={'padding-left':'1%'}),
],
style={ 'color':font_color, 'fontSize': 12},className='col-6')],
className='row'),
html.Div(children=[
html.Br(),
html.Div(children=[html.H4("Year Range",
style={'textAlign':'center','fontSize': 14,'height':'20px'}),
rs1_year],
className='col-12',
)],
className='row')
# ], className='row',style={'margin-left':12})
],className='col-6',
style={"background":background_color,'width':'45%','height':'40%','borderWidth':'3px','borderColor':'gray','margin-left':'1%'} )
row1_col2 = html.Div(children=[
html.Div(children=[
html.H4("The Most Popular Keyword in the Academic World",
style={'textAlign':'center','padding-top':'3%','fontSize': 20}),
html.Div(rb1_popular_keyword,
style={'height':'20%'}),
html.H5(id='val-popular-keyword', style={'padding-top':'1%',"background":'yellow'}),
]
)
] , className='col-3',style={"background":background_color,'width':'27%','margin-left':'0.5%'})
row1_col3 = html.Div(children=[
html.Div(children=[
html.H4("Number of Publications Referencing the Most Popular Keyword",
style={'textAlign':'center','padding-top':'3%','fontSize': 20,}),
html.Div(
style={"background":'red'}),
html.H5(id='val-pub_cnt', style={'padding-top':'2%','fontSize': 24})
]
)
] , className='col-3',style={"background":background_color,'width':'25%','color':font_color,'margin-left':'0.5%'})
So you want to have some styles associated with one class name, and different styles associated with another? You can do this. Define the styles for each class name in your CSS file, and then give class names to your components as needed. Example:
html.Div(
id='whatever',
children='Some text',
className='col-3 another-class-name yet-a-third-class-name'
)

Route in Dash without creating inefficient, hidden items

I am inheriting a plotly Dash app which currently has an app.layout as follows:
def serve_layout():
return html.Div(
className="app",
children=[
dcc.Location(id="url", refresh=False),
build_navbar(),
html.Div(
id="app-container",
className="main-content",
children=[
dcc.Store(id="usecase-store", storage_type="session", data=LiveGraph.use_case_library),
dcc.Store(id="gen-config-store", storage_type="session", data=LiveGraph.gen_config),
dcc.Store(id="control-config-store", storage_type="session", data=LiveGraph.control_config),
dcc.Store(id="data-config-store", storage_type="session", data=LiveGraph.data_config),
dcc.Store(id="data-store", storage_type="session"),
dcc.Store(id="liveplot-store", storage_type="session"),
build_settings_tab(),
build_simulation_tab(),
build_network_tab(),
dcc.Interval(id='graph-update', interval=1000, max_intervals=1000, n_intervals=0,
disabled=True)
],
),
],
)
where there are 3 separate routes for each of the build_* functions; with a callback setting {display: none} on the divs returned by the non-selected functions. I propose the following code:
def serve_layout():
return html.Div(
className="app",
children=[
dcc.Location(id="url", refresh=False),
build_navbar(),
html.Div(
id="app-container",
className="main-content",
children=[
dcc.Store(id="usecase-store", storage_type="session", data=LiveGraph.use_case_library),
dcc.Store(id="gen-config-store", storage_type="session", data=LiveGraph.gen_config),
dcc.Store(id="control-config-store", storage_type="session", data=LiveGraph.control_config),
dcc.Store(id="data-config-store", storage_type="session", data=LiveGraph.data_config),
dcc.Store(id="data-store", storage_type="session"),
dcc.Store(id="liveplot-store", storage_type="session"),
dcc.Interval(id='graph-update', interval=1000, max_intervals=1000, n_intervals=0,
disabled=True),
html.Div(id="main-content")
],
),
],
)
#app.callback(Output("main-content", "children"), [Input("url", "pathname")])
def route(path):
if path == "/":
return build_settings_tab()
# ...only return the individual function necessary for the path
Note that I have removed the three function calls from serve_layout() and added a div#main-content. The issue I'm running into is that I have callbacks set up to watch various inputs across the three pages, so I get an Error loading dependencies if I try to use the second code block. Is there a way around this, or do I really have to put everything in app.layout that I want to access later on? This would be really inefficient, as one of my pages creates charts and I don't want to render the charts and then set {display: none}, seems backwards and certainly sets off a lot of warning bells in my head... Are there any other solutions?

How to insert several dropdowns in plotly dash

I am trying to get into using Plotly Dash and I am getting stuck on this one piece where I would like to dynamically add a user-defined number of dropdowns. Here is what I tried:
# Import required libraries
import dash
import math
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
# App Begins
app = dash.Dash(
__name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = "Tool"
server = app.server
# Create global chart template
mapbox_access_token = "pk.eyJ1IjoicGxvdGx5bWFwYm94IiwiYSI6ImNrOWJqb2F4djBnMjEzbG50amg0dnJieG4ifQ.Zme1-Uzoi75IaFbieBDl3A"
layout = dict(
autosize=True,
automargin=True,
margin=dict(l=30, r=30, b=20, t=40),
hovermode="closest",
plot_bgcolor="#F9F9F9",
paper_bgcolor="#F9F9F9",
legend=dict(font=dict(size=10), orientation="h"),
title="Satellite Overview",
mapbox=dict(
accesstoken=mapbox_access_token,
style="light",
center=dict(lon=-78.05, lat=42.54),
zoom=7,
),
)
# Create app layout
app.layout = html.Div(
[
dcc.Store(id="aggregate_data"),
# empty Div to trigger javascript file for graph resizing
html.Div(id="output-clientside"),
html.Div(
[
html.Div(
[
html.Img(
src=app.get_asset_url("dash-logo.png"),
id="plotly-image",
style={
"height": "60px",
"width": "auto",
"margin-bottom": "25px",
},
)
],
className="one-third column",
),
html.Div(
[
html.Div(
[
html.H3(
"Dash Tool",
style={"margin-bottom": "0px"},
),
]
)
],
className="one-half column",
id="title",
),
],
id="header",
className="row flex-display",
style={"margin-bottom": "25px"},
),
html.Div(
[
html.Div(
[
html.P("Quantity 1:", className="control_label"),
dcc.Input(
id="quantity_1",
type="number",
placeholder=33.
),
html.P("Quantity 2:", className="control_label"),
dcc.Input(
id="quantity_2",
type="number",
placeholder=-115.
),
html.P("Number of Drop Downs:", className="control_label"),
dcc.Slider(
id="drop_downs",
min=2,
max=10,
value=2,
step=1.0,
className="dcc_control",
),
html.P("Load Inputs:", className="control_label"),
dcc.Checklist(
id='sources_flag',
options=[
{'label': 'Yes', 'value': 'Y'},
],
value=['Y'],
labelStyle={'display': 'inline-block'}
),
html.Div(id='source_dropdown_container', children=[]),
html.Div(id='source_dropdown_container_output'),
html.Div(id='source_file_container', children=[]),
html.Div(id='source_file_container_output'),
],
className="pretty_container four columns",
id="cross-filter-options",
),
],
className="row flex-display",
),
],
id="mainContainer",
style={"display": "flex", "flex-direction": "column"},
)
# Create callbacks
#app.callback(
[
Output(component_id='source_dropdown_container_output', component_property='children'),
],
[
Input(component_id='drop_downs', component_property='value'),
Input(component_id='sources_flag', component_property='value'),
]
)
def update_source_dropdowns(value, value_1):
"""Controls the number of drop-downs available to choose sources"""
if value_1 == 'Y':
children = []
for i in range(0, value):
new_dropdown = dcc.Dropdown(
id=f'''source_dropdown_{str(i)}''',
options=['GOOG', 'FB', 'TDOC', 'FANG']
)
children.append(new_dropdown)
print(children)
print(type(children))
return children
I keep running into a callback error. The drop down is constructed properly, so I am kind of confused as to why that error is being invoked.
dash.exceptions.InvalidCallbackReturnValue: The callback ..source_dropdown_container_output.children.. is a multi-output.
Expected the output type to be a list or tuple but got:
None.
Any guidance or help is appreciated. All I am trying to do is add based on user input a dynamic number of drop downs to the layout.
you have three errors in your callback
there is only one return, hence do not define Output as a list
conditional check is wrong, should be if value_1 == ['Y']:
doc.Dropdown() options argument needs to define list of dict
# Create callbacks
#app.callback(
Output(component_id='source_dropdown_container_output', component_property='children'),
[
Input(component_id='drop_downs', component_property='value'),
Input(component_id='sources_flag', component_property='value'),
]
)
def update_source_dropdowns(value, value_1):
"""Controls the number of drop-downs available to choose sources"""
print("cb", value, value_1)
if value_1 == ['Y']:
children = []
for i in range(0, value):
new_dropdown = dcc.Dropdown(
id=f'''source_dropdown_{str(i)}''',
options=[{"label":v, "value":v } for v in ['GOOG', 'FB', 'TDOC', 'FANG']],
)
children.append(new_dropdown)
print(children)
print(type(children))
return children

plotly-dash: embed indicator graph inside of a dbc card

I have been banging my head off the wall all day and cannot find a way to fit a dash indicator inside of a dash_bootstrap_components card.
It seems that the body of the card and the graph do not live inside of the card. I am not very familiar with dash so it is difficult to find a way to solve the issue.
here is what I have been able to do so far in terms of plotting the indicator:
fig3 = go.Figure()
fig3.add_trace(go.Indicator(
mode = "number+delta",
number = {"font":{"size":40},'prefix': "$"},
value = 2045672,
delta = {'reference': 30000},
gauge = {'shape': "bullet"},
title = {"text": "On Hand<br><span style='font-size:0.9em;color:gray'></span>"},
#title='Stock On Hand',
domain = {'x': [0, 1], 'y': [0, 1]},
))
fig3.update_layout(paper_bgcolor = "rgba(0,0,0,0)",
plot_bgcolor = "rgba(0,0,0,0)",
autosize=False,
width = 200,
height=200,
)
fig3.update_traces(align="center", selector=dict(type='indicator'))
I am forced to specify width and height for the indicator otherwise it is way too big, however this cause issues because its size does not adjust in regards to the card.
here is the html dash code for the box and the plot:
html.Div(children=[
html.Div(children=[
html.Div(children=[
html.Div(children=[
dbc.Card(
[dbc.CardBody(
[dcc.Graph(figure=fig3)
]
)],className="card", style={"width": "15rem", "height":"8rem"}
),
], className='jumbotron', style={'background-color': '#fffffff'}),
])
],className="col-3 mx-auto"),
],className="row p-0 h-100", style={'background-color': '#f7f7f7', 'height':110}),
], className="full-width p-0 h-100", style={'background-color': '#fffffff'}),
and here is what the final output looks like:
I am not sure what else I can try to bring the graph inside of the box, any help would be appreciated
Remove the instances where you set the height in the style of dash components and the indicator doesn't get cut off.
So you can do something like this:
app.layout = html.Div(
children=[
html.Div(
children=[
html.Div(
children=[
html.Div(
children=[
dbc.Card(
[
dbc.CardBody(
[dcc.Graph(figure=fig3)],
style={"width": "15rem"},
)
]
)
],
className="jumbotron",
style={"backgroundColor": "#fffffff"},
)
],
className="col-3 mx-auto",
)
],
className="row p-0 h-100",
style={"backgroundColor": "#f7f7f7"},
)
],
className="full-width p-0 h-100",
style={"backgroundColor": "#fffffff"},
)
I've also changed the casing of the style properties to camelCase as this is what React (which dash uses) likes.

Align dash core components horizontally

I want to align two Dropdown menus and a DatePickerRange horizontally. But with the following code:
import dash
import dash_core_components as dcc
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
style_dict = dict(width='100%',
border='1.5px black solid',
height='50px',
textAlign='center',
fontSize=25)
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(children=[
html.H1(children='Hello Dash'),
# placeholder
html.Div(style={'width': '2%', 'display': 'inline-block'}),
html.Div(
dcc.Dropdown(
id = 'start_hour',
options = [{'label': i, 'value': i} for i in list(range(0,24))],
style=style_dict,
), style={'width': '20%', 'display': 'inline-block'}),
# placeholder
html.Div(style={'width': '2%', 'display': 'inline-block'}),
html.Div(
dcc.DatePickerRange(
id='date_picker_range',
style=style_dict
), style={'width': '14%', 'display': 'inline-block', 'fontSize': 20}),
# placeholder
html.Div(style={'width': '2%', 'display': 'inline-block'}),
html.Div(
dcc.Dropdown(
id = 'end_hour',
options = [{'label': i, 'value': i} for i in list(range(0,24))],
style=style_dict
), style={'width': '20%', 'display': 'inline-block'}),
])
if __name__ == '__main__':
app.run_server(debug=False, use_reloader=False)
I got this layout:
If I zoom in I got this:
Is it possible to force the components to be aligned at the top edge, no matter how I zoom in or out?
As browser I use Firefox.
I had a problem similar to the one you are describing. I was creating a dashboard that looked like this:
dcc components without proper alignement
As you can see in the image, my dcc components, as well as their titles were not aligned correctly. I tried adding the style parameter verticalAlign and it worked as I expected. This is how the dashboard looked after adding that style parameter:
dcc components aligned
I'm attaching my dashboard Layout code so you can see where I placed the parameter mentioned:
## Dashboard layout
app.layout = html.Div( ## Master div
[
html.Div( ## Dashboard title
[
dcc.Markdown(dash_title)
]
),
html.Div( ## Select menus
[
html.Div( ## Stock select
[
dcc.Markdown(dash_stock_sel),
dcc.Dropdown(
id="select_stock",
options=[{"label": cmp, "value": tickers_base[cmp]["symbol"]} for cmp in tickers_base],
value="TSLA"
)
],
style={
"display": "inline-block",
"width": "20%"
}
),
html.Div( ## Date select dcc components
[
dcc.Markdown(dash_date_sel),
dcc.DatePickerRange(
id="select_dates",
min_date_allowed=date(2015, 1, 1),
max_date_allowed=date.today(),
initial_visible_month=date(2015, 1, 1),
end_date=date.today()
)
],
style={
"display": "inline-block",
"width": "30%",
"margin-left": "20px",
"verticalAlign": "top"
}
),
]
),
html.Div( ## Stock prices graph
[
dcc.Graph(
id="cstock_graph",
figure=stock_graph(def_company, datareader_api, def_start, def_end)
)
]
)
]
)
I hope this answer helps!

Categories

Resources