I have the code below that has a bootstrap offcanvas at the left. I wondered how I can change the width of the collapsed sidebar. Bootstrap does not have a style tag to do that. I searched and I saw some people suggested using a customized CSS style to define new styling. Can you please help me with that I am pretty new to styling, and I don’t know where I should start.
from dash import Dash, html, dcc, Input, Output, State
import dash_bootstrap_components as dbc
from dash_iconify import DashIconify
app = Dash(__name__, use_pages=True, external_stylesheets=[dbc.themes.SPACELAB])
sidebar = dbc.Nav([
dbc.NavLink([
html.Div(page["name"], className="ms-2"),
], href=page["path"],
active="exact",
)
for page in dash.page_registry.values()
], vertical=True,
pills=True,
className="bg-light",
)
download_icon = DashIconify(icon='ic:baseline-menu', width=40, style={})
app.layout = dbc.Container([
dbc.Row([
dbc.Col(
html.Div("Drilling Dashboard",
style={'fontSize': 40,
'textAlign': 'center',
'color': 'white'}
)
),
dbc.Col([
dbc.Button([download_icon, ''], id="open-offcanvas", n_clicks=0),
], width=1,
style={'margin-right': 0,
'padding': 5}
),
]),
html.Hr(
style={'margin-top': 0}
),
dbc.Row([
dbc.Offcanvas(
dbc.Col([sidebar], width=5), id="offcanvas", title="Title", is_open=False, style={'horizontal-width': 10}
),
]),
dbc.Row([
dbc.Col([dash.page_container], xs=8, sm=8, md=10, lg=10, xl=10, xxl=10)
])
], fluid=True,
style={'background-color': 'black'})
#app.callback(
Output("offcanvas", "is_open"),
Input("open-offcanvas", "n_clicks"),
[State("offcanvas", "is_open")],
)
def toggle_offcanvas(n1, is_open):
if n1:
return not is_open
return is_open
if __name__ == "__main__":
app.run(debug=True)
You can change the width of sidebar by the following attribute:
dbc.Offcanvas(
dbc.Col([sidebar], width=8),
id="offcanvas",
title="Title",
is_open=False,
style={'width': 100} #<---- this attribute instead of horizental-width
)
Output
Related
I’m trying to change automatically the vol when someone choose the option from the dropdown, I have eje2.npz, eje3.npz, eje4.npz. This in order to have a different database and show different images with dashslider.
The dash_slider doesnt have an id as other ddc.
I am out of ideas.
import dash
import dash_html_components as html
import imageio
import dash_bootstrap_components as dbc
from dash_slicer import VolumeSlicer
from dash import Dash, dcc, html, Input, Output
app = dash.Dash(__name__, update_title=None)
vol = imageio.volread("eje1.npz")
slicer = VolumeSlicer(app, vol)
slicer.graph.config["scrollZoom"] = False
app.layout = dbc.Container([
dbc.Row([
html.H1("Reporte sobre postura", style={'text-align': 'center'}),
]),
dbc.Row([
dbc.Col([
dcc.Dropdown(id="slct_30",
options=[
{"label": "PRIMER", "value": 1},
{"label": "SEGUNDO", "value": 2},
{"label": "TERCERO", "value": 3},
{"label": "CUARTO", "value": 4}],
multi=False,
value=1,
style={'width': "80%"}
),
html.Div(id='output_container', children=[]),
html.Br(),
],width={'size':5, 'offset':5},),
]),
dbc.Row([
slicer.graph, slicer.slider, *slicer.stores
]),
])
#app.callback(
[Output(component_id='output_container',component_property='children')],
[Output(component_id='post_%', component_property='figure')],
[Input(component_id='slct_30', component_property='value')]
)
def update_graph(option_slctd):
print(option_slctd)
print(type(option_slctd))
container = "LAPSO DE 30 MINUTOS: {}".format(option_slctd)
return container
if __name__ == "__main__":
app.run_server(debug=True, dev_tools_props_check=False)
`
I am trying to program a sidebar with some filters but the callback update_output of this dropdown is not working (not throwing an error, just doing nothing).
I think it is because this dropdown is not in the main layout, because my layout is composed of the sidebar and a content. My dropdowns in this sidebar will be filters that will be applied to the dataframe that feeds the graphs of the dashboard and dashboard2 layouts.
My question is how or where should I program those callbacks to give functionality to my sidebar dropdowns?
sidebar = html.Div(
[
html.H2("Sidebar", className="display-4"),
html.Hr(),
html.P(
"Sidebar", className="lead"
),
dbc.Nav(
[
dbc.NavLink("Home", href="/", active="exact"),
dbc.NavLink("Page 1", href="/page-1", active="exact"),
dbc.NavLink("Page 2", href="/page-2", active="exact"),
],
vertical=True,
pills=True,
),
dcc.Dropdown(id='dropdown',value="City"),
html.Br(),
dcc.Dropdown(id='dropdown2',options=[])
],
style=SIDEBAR_STYLE,
)
content = html.Div(id="page-content", children=[], style=CONTENT_STYLE)
app.layout = html.Div([
dcc.Location(id="url"),
sidebar,
content
])
#app.callback(
Output('dropdown2', 'options'),
Input('dropdown', 'value')
)
def update_output(value):
return df[df["cities"].isin(value)]
#app.callback(
Output("page-content", "children"),
[Input("url", "pathname")]
)
def render_page_content(pathname):
if pathname == "/":
return dashboard.layout
elif pathname == "/page-1":
return dashboard.layout
elif pathname == "/page-2":
return dashboard2.layout
# return a 404 message when user tries to reach a different page
return dbc.Jumbotron(
[
html.H1("404: Not found", className="text-danger"),
html.Hr(),
html.P(f"The pathname {pathname} was not recognised..."),
]
)
if __name__=='__main__':
app.run_server(debug=True, port=8000)
I find checklists to be better for this purpose. If you're open to using that instead of dropdown menu to filter your dataframe, then the complete snippet below will produce the following Plotly Dash App.
Complete code:
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import pandas as pd
import plotly.graph_objs as go
import numpy as np
import plotly.express as px
app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])
df = px.data.stocks()
df = df.set_index('date')
controls = dbc.Card(
[
dbc.FormGroup(
[
dbc.Label("Checklist"),
dcc.Checklist(
id="column_select",
options=[{"label":col, "value": col} for col in df.columns],
value=[df.columns[0]],
labelStyle={'display': 'inline-block', 'width': '12em', 'line-height':'0.5em'}
),
],
),
],
body=True,
style = {'font-size': 'large'}
)
app.layout = dbc.Container(
[
html.H1("Dropdowns and checklists"),
html.Hr(),
dbc.Row([
dbc.Col([controls],xs = 4),
dbc.Col([
dbc.Row([
dbc.Col(dcc.Graph(id="graph"), style={'height': '420px'}),
])
]),
]),
],
fluid=True,
)
#app.callback(
Output("graph", "figure"),
[Input("column_select", "value"),],
)
def make_graph(cols):
fig = px.line(df, x = df.index, y = cols, template = 'plotly_dark')
return fig
app.run_server(mode='external', port = 8982)
I am using Dash in python, I am trying to align the logo header and paragraph in the same horizontal level in a jumbotron but it is not working for me. I am getting something like this.
But I want to make it look like the image below
I am using these external style sheets
external_stylesheets = [dbc.themes.BOOTSTRAP,'https://codepen.io/chriddyp/pen/bWLwgP.css']
this is the code for the layout I tried to implement
html.A(
dbc.Jumbotron(
[
dbc.Col( html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode()),style={'height':'100px',
'align':'center'})),
dbc.Col( html.H1(children='header',
style={
'text-align':'center',
'color':'white'
}
)),
dbc.Col(html.P(children='version',
style={
'text-align':'right',
'color':'white'
})),
],
style={
'height':'auto',
'width':'auto',
'background-color':'#0067b9',
}
),
)
any help would of great help to me Thank you.
latest change in code :
html.A(
# Use row and col to control vertical alignment of logo / brand
dbc.Jumbotron(
[
dbc.Col( html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode()),style={'height':'100px',
'width':'15%',
'align':'left'})),
dbc.Col( html.H1(children='Header',
style={
'text-align':'center',
'color':'white'
}
)),
dbc.Col(html.H6(children='version',
style={
'text-align':'right',
'color':'white'
})),
],
style={
'height':'auto',
'width':'auto',
'text-align':'left',
'background-color':'#0067b9',
'align-items': 'center'
}
),
)
here is the result
after adding display:flex
html.A(
# Use row and col to control vertical alignment of logo / brand
dbc.Row(
[
dbc.Col( html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode()),style={'height':'100px',
'width':'15%',
'align':'left'})),
dbc.Col( html.H1(children='Header',
style={
'text-align':'center',
'color':'white'
}
)),
dbc.Col(html.H6(children='version',
style={
'text-align':'right',
'color':'white'
})),
],
style={
'height':'auto',
'width':'auto',
'text-align':'left',
'background-color':'#0067b9',
'align-items': 'center'
}
),
)
I am quite new to front-end development and HTML and I'm struggling to understand how to order a range slider with two inputs in the same line when using Dash
I have tried to separate the html.Div, Putting the components in the same Div without separating them
adjust the different parameters and some morebut I still can't get it to appear the way I want
what I want:
what I have:
My code (that reproduce what I have):
import dash
import dash_core_components as dcc
import dash_html_components as html
app.layout = html.Div([
html.Div([
html.Div([dcc.Input(
id='slider-min-value',
placeholder=str(min_value))],
style={'width': '10%'}
),
html.Div([dcc.RangeSlider(
id='condition-range-slider',
min=0,
max=30,
value=[10, 15],
allowCross=False)],
style={'width': '25%'}
),
html.Div([dcc.Input(
id='slider-max-value',
placeholder=str(max_value))],
style={'width': '10%'}
),
],
style={'display': 'inline-block'})])
if __name__ == '__main__':
app.run_server(debug=True)
what do I need to do in order to get the rangeslider and the inputs to appear the way I want?
Ok, using {"display": "grid", "grid-template-columns": "10% 40% 10%"} gave me what I wanted.
layout:
app.layout = html.Div(
html.Div(
[
dcc.Input(type='text', value=min_value),
dcc.RangeSlider(
id='condition-range-slider',
min=0,
max=30,
value=[10, 15],
allowCross=False
),
dcc.Input(type='text', value=max_value)
],
style={"display": "grid", "grid-template-columns": "10% 40% 10%"}),
style={'width': '20%'}
)
what I got:
You can try updating the html.Div style with 'float': 'left',
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.Div(
style={'width':'10%', 'float':'left', 'marginLeft': 20, 'marginRight': 20},
children=[
dcc.Input(id='slider-min-value')
]
),
html.Div(
style={'width':'50%', 'float':'left','marginLeft': 20, 'marginRight': 20},
children=[
dcc.RangeSlider(
id='condition-range-slider',
min=0,
max=30,
value=[10, 15],
allowCross=False
)
]
),
html.Div(
style={'width':'10%', 'float':'left','marginLeft': 20, 'marginRight': 20},
children=[
dcc.Input(id='slider-max-value')
]
),
])
if __name__ == '__main__':
app.run_server(debug=True)
In the sample Dash application below, I am attempting to create a dynamic layout with a variable number of rows and columns. This dynamic grid-style layout will be populated with various graphs that can be modified by dropdowns, etc.
The main issue I have run into thus far pertains to viewport-units and attempting to style the individual graphs appropriately to accommodate the dynamic layout. For example, I am modifying the style of the dcc.Graph() components via viewport-units, where the dimensions (e.g. height and width may be either 35vw or 23vw depending on the number of columns). When I change the number of columns from 3 to 2, for example, the height and width of the dcc.Graph() component are clearly changed, however this change is not reflected in the actual rendered layout until the window is physically resized (see the images below the sample code).
How do I force the dcc.Graph() components to propagate these changes without having to resize the window?
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions = True
app.layout = html.Div([
html.Div(className='row', children=[
html.Div(className='two columns', style={'margin-top': '2%'}, children=[
html.Div(className='row', style={'margin-top': 30}, children=[
html.Div(className='six columns', children=[
html.H6('Rows'),
dcc.Dropdown(
id='rows',
options=[{
'label': i,
'value': i
} for i in [1,2,3,4]],
placeholder='Select number of rows...',
clearable=False,
value=2
),
]),
html.Div(className='six columns', children=[
html.H6('Columns'),
dcc.Dropdown(
id='columns',
options=[{
'label': i,
'value': i
} for i in [1,2,3]],
placeholder='Select number of columns...',
clearable=False,
value=3
),
])
]),
]),
html.Div(className='ten columns', id='layout-div', style={'border-style': 'solid', 'border-color': 'gray'}, children=[])
])
])
#app.callback(
Output('layout-div', 'children'),
[Input('rows', 'value'),
Input('columns', 'value')])
def configure_layout(rows, cols):
mapping = {1: 'twelve columns', 2: 'six columns', 3: 'four columns', 4: 'three columns'}
sizing = {1: '40vw', 2: '35vw', 3: '23vw'}
layout = [html.Div(className='row', children=[
html.Div(className=mapping[cols], children=[
dcc.Graph(
id='test{}'.format(i+1+j*cols),
config={'displayModeBar': False},
style={'width': sizing[cols], 'height': sizing[cols]}
),
]) for i in range(cols)
]) for j in range(rows)]
return layout
#Max layout is 3 X 4
for k in range(1,13):
#app.callback(
[Output('test{}'.format(k), 'figure'),
Output('test{}'.format(k), 'style')],
[Input('columns', 'value')])
def create_graph(cols):
sizing = {1: '40vw', 2: '35vw', 3: '23vw'}
style = {
'width': sizing[cols],
'height': sizing[cols],
}
fig = {'data': [], 'layout': {}}
return [fig, style]
if __name__ == '__main__':
app.server.run()
Relevant screenshots (Image 1 - page load, Image 2 - change columns to 2):
Here is how to proceed:
app.py must import:
from dash.dependencies import Input, Output, State, ClientsideFunction
let’s include the below Div somewhere in the Dash layout:
html.Div(id="output-clientside"),
asset folder must include either your own script, or the default script resizing_script.js, which contains:
if (!window.dash_clientside) {
window.dash_clientside = {};
}
window.dash_clientside.clientside = {
resize: function(value) {
console.log("resizing..."); // for testing
setTimeout(function() {
window.dispatchEvent(new Event("resize"));
console.log("fired resize");
}, 500);
return null;
},
};
Among your callbacks, put this one, without #:
app.clientside_callback(
ClientsideFunction(namespace="clientside", function_name="resize"),
Output("output-clientside", "children"),
[Input("yourGraph_ID", "figure")],
)
At this point, when you manually resize the window, in your browser, the resize function is triggered.
We aim to achieve the same result, but without manual window resizing. For instance, the trigger could be a className update.
So, we apply the following changes:
Step 1: unchanged
Step 2: unchanged
Step 3: let’s add a “resize2” function inside our javascript file, which takes 2 arguments:
if (!window.dash_clientside) {
window.dash_clientside = {};
}
window.dash_clientside.clientside = {
resize: function(value) {
console.log("resizing..."); // for testing
setTimeout(function() {
window.dispatchEvent(new Event("resize"));
console.log("fired resize");
}, 500);
return null;
},
resize2: function(value1, value2) {
console.log("resizingV2..."); // for testing
setTimeout(function() {
window.dispatchEvent(new Event("resize"));
console.log("fired resizeV2");
}, 500);
return value2; // for testing
}
};
Function “resize2” now takes 2 arguments, one for each Input defined in the below callback. It will return the value of “value2” in the Output, specified in this very same callback. You can set it back to “null”, it’s just to illustrate.
Step4: our callback now becomes:
app.clientside_callback(
ClientsideFunction(namespace="clientside", function_name="resize2"),
Output("output-clientside", "children"),
[Input("yourGraph_ID", "figure"), Input("yourDivContainingYourGraph_ID", "className")],
)
Finally, you need a button to trigger the event which will change the className of your container.
let’s say your have:
daq.ToggleSwitch(
id='switchClassName',
label={
'label':['Option1', 'Option2'],
},
value=False,
),
And the following callback:
#app.callback(Output("yourDivContainingYourGraph_ID", "className"),
[Input("switchClassName","value")]
)
def updateClassName(value):
if value==False:
return "twelve columns"
else:
return "nine columns"
Now, if you save everything, refresh, everytime you press on your toggleSwitch,it resizes the container, triggers the function, and refreshes the figure.
Given the way it’s done, I assume it must also be possible to run more Javascript functions, the same way, but I didnt check yet.
Hope it will help some
The behavior looks like a Plotly bug to me.
Here is a possible workaround/short-termin solution.
There is a nice library visdcc which allows callbacks with Javascript. You can install it via
pip install visdcc
Add it to your div:
visdcc.Run_js(id='javascript'),
and add a callback
#app.callback(
Output('javascript', 'run'),
[Input('rows', 'value'),
Input('columns', 'value')])
def resize(_, __):
return "console.log('resize'); window.dispatchEvent(new Event('resize'));"
Plotly will throw an error in the console after the resize event (this also happens when the windows is manually resized) but the plots are shown correctly.
Full code
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import visdcc
SIZING = {1: '40vw', 2: '35vw', 3: '23vw'}
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions = True
app.layout = html.Div([
visdcc.Run_js(id='javascript'),
html.Div(className='row', children=[
html.Div(className='two columns', style={'margin-top': '2%'}, children=[
html.Div(className='row', style={'margin-top': 30}, children=[
html.Div(className='six columns', children=[
html.H6('Rows'),
dcc.Dropdown(
id='rows',
options=[{
'label': i,
'value': i
} for i in [1,2,3,4]],
placeholder='Select number of rows...',
clearable=False,
value=2
),
]),
html.Div(className='six columns', children=[
html.H6('Columns'),
dcc.Dropdown(
id='columns',
options=[{
'label': i,
'value': i
} for i in [1,2,3]],
placeholder='Select number of columns...',
clearable=False,
value=3
),
])
]),
]),
html.Div(className='ten columns', id='layout-div', style={'border-style': 'solid', 'border-color': 'gray'}, children=[])
])
])
#app.callback(
Output('layout-div', 'children'),
[Input('rows', 'value'),
Input('columns', 'value')])
def configure_layout(rows, cols):
mapping = {1: 'twelve columns', 2: 'six columns', 3: 'four columns', 4: 'three columns'}
layout = [html.Div(className='row', children=[
html.Div(className=mapping[cols], style={'width': SIZING[cols], 'height': SIZING[cols]}, children=[
dcc.Graph(
id='test{}'.format(i+1+j*cols),
config={'displayModeBar': False},
style={'width': SIZING[cols], 'height': SIZING[cols]}
),
]) for i in range(cols)
]) for j in range(rows)]
return layout
#app.callback(
Output('javascript', 'run'),
[Input('rows', 'value'),
Input('columns', 'value')])
def resize(_, __):
return "console.log('resize'); window.dispatchEvent(new Event('resize'));"
#Max layout is 3 X 4
for k in range(1,13):
#app.callback(
[Output('test{}'.format(k), 'figure'),
Output('test{}'.format(k), 'style')],
[Input('columns', 'value')])
def create_graph(cols):
style = {
'width': SIZING[cols],
'height': SIZING[cols],
}
fig = {'data': [], 'layout': {}}
return [fig, style]
if __name__ == '__main__':
app.server.run()