Reposted from plotly/dash/issues/811 (should have been here anyway, but original post was to see if there were alternatives to something like html.Fragment()
)
I plan to open a PR to add html.Fragment()
(Update: will create PR against dcc
)
From the getting started guide, app.layout = html.Div(children=[...])
creates an unnecessary <div>...</div>
element, which would instead be a Fragment if written directly in React (React.Fragment).
Full example below:
# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
# > Proposed html.Fragment below! <
app.layout = html.Fragment(children=[
html.H1(children='Hello Dash'),
html.Div(children='''
Dash: A web application framework for Python.
'''),
dcc.Graph(
id='example-graph',
figure={
'data': [
{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
],
'layout': {
'title': 'Dash Data Visualization'
}
}
)
])
if __name__ == '__main__':
app.run_server(debug=True)
A more realistic example would be for laying out tiles with Bulma CSS
import dash_html_components as html
import numpy as np
import pandas as pd
import plotly_express as px
from dash_charts.helpers import MinGraph
class BulmaStylingDemo:
"""Demo laying out a 3 column grid with Bulma where.
- the first column has three tiles
- the middle column is half the full screen width
- the tiles will wrap on smaller screens
"""
def __init__(self):
"""Initialize app."""
self.app = helpers.initApp()
def run(self, *, debug=True, **kwargs):
"""Run the application passing any kwargs to dash."""
self._createLayout()
self.app.run_server(debug=debug, **kwargs)
def _createLayout(self):
"""Create application layout."""
# Initialize the dashboard layout
self.app.layout = html.Div(className='section', children=[
html.Div(className='tile is-ancestor', children=[
html.Div(className='tile is-parent is-vertical is-3', children=[
html.Article(className='tile is-child notification', children=[
html.P(className='title', children='Top Vertical Tile'),
html.P(
className='subtitle',
children='Uses notification class for grey background and internal padding',
),
html.P(className='subtitle', children='Could also add is-info, is-warning, etc.'),
]),
html.Article(className='tile is-child', children=[
html.P(className='title', children='Vertical...'),
html.P(className='subtitle', children='(Top tile)'),
MinGraph(
figure=px.scatter(px.data.iris(), x="sepal_width", y="sepal_length", height=200),
),
]),
html.Article(className='tile is-child', children=[
html.P(className='title', children='...tiles'),
html.P(className='subtitle', children='(Bottom tile)'),
MinGraph(
figure=px.scatter(px.data.iris(), x="sepal_width", y="sepal_length", height=200),
),
]),
]),
MinGraph(
className='tile is-child is-6 is-block-desktop',
figure=px.scatter(px.data.iris(), x="sepal_width", y="sepal_length"),
),
html.Article(className='tile is-child is-3 is-block-desktop', children=[
html.P(className='title', children='A Small Chart'),
MinGraph(
figure=px.scatter(px.data.iris(), x="sepal_width", y="sepal_length", height=350),
),
html.P(className='subtitle', children='An Image'),
html.Img(src='https://media.giphy.com/media/JGQe5mxayVF04/giphy.gif')
]),
]),
])
if __name__ == '__main__':
BulmaStylingDemo().run()
Where for a more complicated layout, I might want to write something like:
def _createLayout(self):
"""Create application layout."""
# Initialize the dashboard layout
self.app.layout = html.Div(className='section', children=[
html.Div(className='tile is-ancestor', children=[
self.leftVerticalTiles(),
MinGraph(
className='tile is-child is-6 is-block-desktop',
figure=self.exRolling.createFigure(df=self.dfDemo, dataLbl='Demo Data', rollingCount=4),
),
html.Article(className='tile is-child is-3 is-block-desktop', children=[
html.P(className='title', children='A Small Chart'),
MinGraph(
figure=px.scatter(px.data.iris(), x="sepal_width", y="sepal_length", height=350),
),
html.P(className='subtitle', children='An Image'),
html.Img(src='https://media.giphy.com/media/JGQe5mxayVF04/giphy.gif')
]),
]),
])
def leftVerticalTiles(self):
"""Would not work with: `return html.Div(...)`"""
return html.Fragment(children=[
html.Div(className='tile is-parent is-vertical is-3', children=[
html.Article(className='tile is-child notification', children=[
html.P(className='title', children='Top Vertical Tile'),
html.P(
className='subtitle',
children='Uses notification class for grey background and internal padding',
),
html.P(className='subtitle', children='Could also add is-info, is-warning, etc.'),
]),
html.Article(className='tile is-child', children=[
html.P(className='title', children='Vertical...'),
html.P(className='subtitle', children='(Top tile)'),
MinGraph(
figure=px.scatter(px.data.iris(), x="sepal_width", y="sepal_length", height=200),
),
]),
html.Article(className='tile is-child', children=[
html.P(className='title', children='...tiles'),
html.P(className='subtitle', children='(Bottom tile)'),
MinGraph(
figure=px.scatter(px.data.iris(), x="sepal_width", y="sepal_length", height=200),
),
]),
]),
])
Where if return html.Div(...
was used instead of return html.Fragment(...
(of course, assuming html.Fragment
existed), the extra div would cause the vertical tiles to be aligned incorrectly
Note: I've been experimenting with classes for laying out Dash apps and it is really helpful to avoid pitfalls of having global variables. I'm working on a class-based boilerplate charting library and a full, class-based Dash app Personal Finance Explorer - Example OOP profile page"