Announcing Dash Bio 1.0.0 🎉 : a one-stop-shop for bioinformatics and drug development visualizations.

Plotly charts inheriting dash-bootstrap-components color scheme

I’ve been trying to figure out how to implement a light/dark mode switch to my page. How do you “inherit” the color scheme from dash-bootstrap-components themes into a plotly chart?

I’ve been successful in manually copying and pasting the rbg values/hex values into the color_discrete_sequence parameter but short of doing a callback to change the figure, I’m not sure how it would work. Any ideas?

    fig = px.pie(df, 
                values='cnt_client_ip', 
                names='type',
                title='Request Types',
                color_discrete_sequence=["#5cb85c", "#5bc0de", "#ffc107"])

Hi @tphil10

You are in luck! You can try using the Bootstrap-themed plotly figure templates from the dash-bootstrap-templates library. There is also a theme switch component and a stylesheet for appying a Bootstrap theme to dash-core-components and the DataTable.

Also, as you mentioned, it is necessary to update the figure in a callback when you change the theme, otherwise the new theme won’t be applied.

See also this post for more information:

oh! i dont think i knew this existed, nice! Will peruse.

Thanks!

Had some time to peruse the lib. It looks like the dbc style sheet is loading into the console but the style isn’t being applied to the chart.

from dash import dash
import dash_bootstrap_components as dbc

dbc_css = ("https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates@V1.0.4/dbc.min.css")

app = dash.Dash(__name__, 
    external_stylesheets=[dbc.themes.SUPERHERO, dbc_css], 
    external_scripts=[{
        'crossorigin': 'anonymous'
    }],
    suppress_callback_exceptions=True)

I applied the dbc class to a pie charts but the colors seem to remain the same.

request_type_chart = dcc.Graph(id='req-type-chrt', 
                               className='mb-5 bg-body rounded text-center dbc')

I do see in one of the examples theres a call to

from dash_bootstrap_templates import load_figure_template

Do i need to load a specific figure template and then use that template in the callback that generates the pie chart?

@app.callback(
    Output('req-type-chrt', 'figure'),
    Input('url', 'pathname')
)
def load_type_chart(path):

    fig = px.pie(df, 
                values='cnt_client_ip', 
                names='type',
                title='Request Types'
               template=<SOME TEMPLATE GOES HERE>
            )

    fig.update_layout(
        paper_bgcolor = 'rgba(0,0,0,0)',
        margin={'l':0, 'r':0, 'b':0},
        font_color='white',
        font_size=18,
        hoverlabel={'bgcolor':'white', 'font_size':16, 'font_family':'Lato'}
    )

    fig.update_traces(
        hovertemplate = "%{label}: %{value}   (%{percent})"
    )

    return fig

Most likely doing something dumb, it’s entirely possible I haven’t had enough coffee yet…lol

Hey @tphil10

Ok, grab a cup of coffee, :coffee: and let’s step through creating a minimal working example of an app with a theme switcher, and I’ll show how all the features available in the `dash-bootstrap-templates library work together.

As you’ve noticed, the plotly figures aren’t updated based on a CSS stylesheet. You can update the figure manually like you are doing with fig.update(...) This updates the currently selected figure template. The default template is called “plotly” Learn more about plotly figure templates and how to change them here. In any Dash app, you can choose from one of the 12 built-in plotly figure templates.

You can find an additional 26 plotly figure templates in the dash-bootstrap-templates library. There is one for each of the themes available in the dash-bootstrap-components library.

Here is how to load the “cyborg” themed template and make it the default template in your app:

from dash_bootstrap_templates import load_figure_template
load_figure_template("cyborg")

Now “cyborg” is the default template instead of “plotly” . If you didn’t want to include a theme switch component, then that’s all you need to do. Now all your figures would have the fonts, background color, text colors and trace colors etc based on the Bootstrap “cyborg” theme.

But since we want to make an app with a theme switch, let’s load two templates. Here is an example: This loads “minty” and “cyborg”


from dash import Dash, dcc,  Input, Output
import plotly.express as px
import dash_bootstrap_components as dbc

from dash_bootstrap_templates import load_figure_template

# This loads the "cyborg" and "minty" themed figure template from dash-bootstrap-templates library,
# adds it to plotly.io and makes "cyborg" (The first template in the list) the default figure template.
load_figure_template(["cyborg", "minty"])

app = Dash(__name__, external_stylesheets=[dbc.themes.MINTY])

df = px.data.tips()


app.layout = dbc.Container([
    dcc.Dropdown(
        id='values',
        value='total_bill',
        options=[{'value': x, 'label': x}
                 for x in ['total_bill', 'tip', 'size']],
        clearable=False
    ),
    dcc.Graph(id="pie-chart"),
], fluid=True)

@app.callback(
    Output("pie-chart", "figure"),
    Input("values", "value"))
def generate_chart(value):
    fig = px.pie(df, values=value, names="day", template="minty")
    return fig


if __name__ == "__main__":
    app.run_server(debug=True)





Now, to manually change to the Cyborg theme, change these two lines of code:


app = Dash(__name__, external_stylesheets=[dbc.themes.CYBORG])

fig = px.pie(df, values=value, names="day", template="cyborg")



Here is what the figure looks like now:


But notice how the dropdown doesn’t look good in the dark theme - it’s still white, and in some themes you can’t read the text in the dropdown at all.

image

So this is where the dbc_css stylesheet comes in handy. It will automatically style the dash-core-components like the dropdown with your Bootstrap theme.

So let’s add that to the app:


from dash import Dash, dcc, Input, Output
import plotly.express as px
import dash_bootstrap_components as dbc

from dash_bootstrap_templates import load_figure_template

# This loads the "cyborg" and "minty" themed figure template from dash-bootstrap-templates library,
# adds it to plotly.io and makes "cyborg" (The first template in the list) the default figure template.
load_figure_template(["cyborg", "minty"])

dbc_css = (
    "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates@V1.0.4/dbc.min.css"
)
app = Dash(__name__, external_stylesheets=[dbc.themes.CYBORG, dbc_css])

df = px.data.tips()


app.layout = dbc.Container(
    [
        dcc.Dropdown(
            id="values",
            value="total_bill",
            options=[{"value": x, "label": x} for x in ["total_bill", "tip", "size"]],
            clearable=False,
        ),
        dcc.Graph(id="pie-chart"),
    ],
    fluid=True,
    className="dbc",
)


@app.callback(Output("pie-chart", "figure"), Input("values", "value"))
def generate_chart(value):
    fig = px.pie(df, values=value, names="day", template="cyborg")
    return fig


if __name__ == "__main__":
    app.run_server(debug=True)

image

You can see the dropdown is now dark. So now when you change the theme, the dropdown is also automatically styled with the Bootstrap theme.

OK, so finally, let’s add the theme switch component. The cool thing about the theme switch components is that it automatically loads the figure templates for you, so you can skip that step from the apps above.

Here’s the app using the ThemeSwitchAIO component from the dash-bootstrap-templates library:


from dash import Dash, dcc, Input, Output
import plotly.express as px
import dash_bootstrap_components as dbc
from dash_bootstrap_templates import ThemeSwitchAIO


dbc_css = (
    "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates@V1.0.4/dbc.min.css"
)
app = Dash(__name__, external_stylesheets=[dbc.themes.MINTY, dbc_css])

df = px.data.tips()


app.layout = dbc.Container(
    [
        ThemeSwitchAIO(aio_id="theme", themes=[dbc.themes.MINTY, dbc.themes.CYBORG]),
        dcc.Dropdown(
            id="values",
            value="total_bill",
            options=[{"value": x, "label": x} for x in ["total_bill", "tip", "size"]],
            clearable=False,
        ),
        dcc.Graph(id="pie-chart"),
    ],
    fluid=True,
    className="dbc",
)


@app.callback(
    Output("pie-chart", "figure"),
    Input("values", "value"),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
)
def generate_chart(value, toggle):
    template = "minty" if toggle else "cyborg"
    fig = px.pie(df, values=value, names="day", template=template)
    return fig


if __name__ == "__main__":
    app.run_server(debug=True)

theme_switch_pie



I hope that helps - let me know if you have other questions :slight_smile:

1 Like

Awesome! So i was able to apply cyborg color scheme to the chart, works really well.

I think my original issue has to do with the ‘superhero’ theme that doesn’t seem to apply correctly to the charts. The color scheme seems to be just the default plotly colors. I know it says it’s an available theme however on your demo site if i change the theme, the superhero theme has a black box around it, does that mean its unavailable?

Thanks for the help!!

Hi @tphil10

Hmm - superhero should be there. The black box around the theme indicates it’s a dark theme.

Can you try running this sample app?


from dash import Dash, dcc, html
import plotly.express as px
import dash_bootstrap_components as dbc

from dash_bootstrap_templates import load_figure_template

load_figure_template("superhero")
app = Dash(__name__, external_stylesheets=[dbc.themes.SUPERHERO])

df = px.data.gapminder()

dff = df[df.year.between(1952, 1982)]
dff = dff[dff.continent.isin(df.continent.unique()[1:])]
line_fig = px.line(
    dff, x="year", y="gdpPercap", color="continent", line_group="country"
)

scatter_fig = px.scatter(
    df.query("year==2007"),
    x="gdpPercap",
    y="lifeExp",
    size="pop",
    color="continent",
    log_x=True,
    size_max=60,
    title="Gapminder 2007",
)

avg_lifeExp = (dff["lifeExp"] * dff["pop"]).sum() / dff["pop"].sum()
map_fig = px.choropleth(
    dff,
    locations="iso_alpha",
    color="lifeExp",
    title="%.0f World Average Life Expectancy was %.1f years" % (1982, avg_lifeExp),
)

hist_fig = px.histogram(dff, x="lifeExp", nbins=10, title="Life Expectancy")

graphs = html.Div(
    [
        dbc.Row(
            [
                dbc.Col(dcc.Graph(figure=line_fig), lg=6),
                dbc.Col(dcc.Graph(figure=scatter_fig), lg=6),
            ],
            className="mt-4",
        ),
        dbc.Row(
            [
                dbc.Col(dcc.Graph(figure=hist_fig), lg=6),
                dbc.Col(dcc.Graph(figure=map_fig), lg=6),
            ],
            className="mt-4",
        ),
    ]
)

# These buttons are added to the app just to show the Boostrap theme colors
buttons = html.Div(
    [
        dbc.Button("Primary", color="primary"),
        dbc.Button("Secondary", color="secondary"),
        dbc.Button("Success", color="success"),
        dbc.Button("Warning", color="warning"),
        dbc.Button("Danger", color="danger"),
        dbc.Button("Info", color="info"),
        dbc.Button("Light", color="light"),
        dbc.Button("Dark", color="dark"),
        dbc.Button("Link", color="link"),
    ],
)

heading = html.H1("Dash Bootstrap Template Demo", className="bg-primary text-white p-2")

app.layout = dbc.Container([heading, buttons, graphs], fluid=True)

if __name__ == "__main__":
    app.run_server(debug=True)


It should look like this:

One thing that might be causing the issue – in your code you have:

fig.update_layout(
        paper_bgcolor = 'rgba(0,0,0,0)',
        margin={'l':0, 'r':0, 'b':0},
        font_color='white',
        font_size=18,
        hoverlabel={'bgcolor':'white', 'font_size':16, 'font_family':'Lato'}
    )

This will override whatever is in the template. So to start, remove this then add back only the things you would like to modify.

Hmm ok maybe it is just me then, the color scheme on my pie chart with superhero theme must just be very close to the bootstrap theme or the regular plotly one.

Colors are prominent enough, works for me.

Thanks for all the help!!

Yes, Superhero accent colors are close to the Bootstrap theme. For something different, you could try Vapor :slight_smile: