# See [The dash examples index](https://dash-example-index.herokuapp.com/) for more examples.
from dash import Dash, dcc, html, Input, Output, State, Patch
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
from help_functions import *
# Get data for the example plots
df_tips = px.data.tips()
df_stock = px.data.stocks()
df_stock['date'] = pd.to_datetime(df_stock['date'])
df_gap = px.data.gapminder().query("year == 2007 and continent == 'Europe'")
# Create app object=================================================================
app = Dash(__name__, external_stylesheets=[dbc.themes.CERULEAN, #SANDSTONE,
dbc.icons.BOOTSTRAP,
dbc.icons.FONT_AWESOME,
"/assets/styles.css"])
#===================================================================================
# Get all sequential color scales from px.colors
sequential_colors = px.colors.sequential
# Create a dictionary to map template names to their background colors
templates_dict = {'ggplot2': 'rgb(237,237,237)', 'seaborn':'rgb(234,234,242)', 'simple_white':'white', 'plotly':'#E5ECF6', 'plotly_white':'white', 'plotly_dark':'rgb(17,17,17)'}
templates = list(templates_dict.keys())
# List all sequential color scales excluding internal attributes, 'swatches', and 'swatches_continuous'
options=[{'label': scale, 'value': scale} for scale in dir(px.colors.sequential)
if not scale.startswith("_") and scale not in ['swatches', 'swatches_continuous']]
# Create components================================================================
# Outputs for Modal Window
div_code = html.Div([
html.Div(id='code-output'),
dcc.Clipboard(id='copy-code', target_id='code-output'),
], className='d-flex')
div_array = html.Div([
html.Div(id='array-output'),
dcc.Clipboard(id='copy-array', target_id='array-output'),
], className='d-flex')
# Modal Window for The Save Options------------------------------------------------
modal_save_options = html.Div([
dbc.Modal([
dbc.ModalBody([
html.H5('Choose your favorite way of exporting the selected palette.', className='text-center'),
html.Hr(),
html.H6('Lists of CSS colors:'),
div_array,
html.H6('Python Code:'),
div_code
]),
dbc.ModalFooter(dbc.Button("Close", id="btn-close", n_clicks=0))
],
id='modal-save',
is_open=False,
keyboard=False,
backdrop='static',
style={
'position': 'fixed',
'top': '150px', # Position the modal at the top
'overflow': 'auto'} # Optional: enable scrolling if content overflows
),
])
file_path = 'https://raw.githubusercontent.com/natatsypora/colorscale_selection/refs/heads/main/assets/header_img.png'
header_card = dbc.Card([
dbc.CardImg(
src=file_path,
top=True,
style={"opacity": 0.9, 'height':'80px'}),
dbc.CardImgOverlay(
dbc.CardBody(html.H1("Plotly Express Sequential Colorscales", className="text-center text-white align-items-center"),
class_name='p-0'))
], class_name='mb-3')
# Create app layout=================================================================
app.layout = dbc.Container([
header_card,
dbc.Row([
dbc.Col([
dcc.Dropdown(id="dropdown-sequential", options=options, clearable=False, value='dense', optionHeight=30, className='mb-3'),
dbc.Card(dcc.Graph(id='color-bar', config=config_mode), body=True),
], width=3,),
dbc.Col([
dcc.Dropdown(id="dropdown-template", options=templates, value='plotly', placeholder='Select a template...', optionHeight=30, className='mb-3'),
dbc.Card(dcc.Graph(id='scatter-plot', config=config_mode), body=True, class_name='mb-3 '),
dbc.Card(dcc.Graph(id='treemap-plot', config=config_mode), body=True, ),
], width=5,),
dbc.Col([
dbc.Button([html.I(className='fas fa-download mx-2'),
'Export Options',
], id='btn-open', n_clicks=0, className='btn btn-primary w-100 py-1 mb-3' ),
dbc.Card(dcc.Graph(id='area-plot', config=config_mode), body=True, className='mb-3'),
dbc.Card(dcc.Graph(id='map-plot', config=config_mode), body=True),
modal_save_options,
], width=4),
]),
])
# Callback ========================================================================
@app.callback(
Output('modal-save', 'is_open'),
[Input('btn-open', 'n_clicks'), Input('btn-close', 'n_clicks')],
[State('modal-save', 'is_open')],
prevent_initial_call=True
)
def toggle_modal(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
@app.callback(
Output('color-bar', 'figure'),
Output('scatter-plot', 'figure'),
Output('area-plot', 'figure'),
Output('treemap-plot', 'figure'),
Output('map-plot', 'figure'),
Output('array-output', 'children'),
Output('code-output', 'children'),
Input('dropdown-sequential', 'value'),
Input('dropdown-template', 'value'),
)
def change_colorscale(palette_name, template):
# Access the selected colorscale dynamically
colorscale = getattr(px.colors.sequential, palette_name)
# Construct the full name dynamically
full_palette_name = f'px.colors.sequential.{palette_name}'
# Get the number of colors
n_colors = len(colorscale)
# Get the background color
bg_color = templates_dict.get(template)
# Create the colorbar for the selected colorscale
cb = create_colorscale_bar(palette_name, colorscale, n_colors, bg_color, template)
# Create the scatter plot figure
scatter_plot = create_scatter_plot(df_tips, x='total_bill', y='tip', color_v='tip',
size_v='total_bill', col_scale=colorscale, bg_color=bg_color, template=template)
# Create the area chart figure
area_chart = create_area_chart_with_gradient(df_stock, x='date', y='AAPL',
col_scale=colorscale, bg_color=bg_color, template=template)
# Create the treemap figure
path_c = [px.Constant('world'), 'continent', 'country']
treemap = create_treemap(df_gap, path_c, values='pop', color_v='lifeExp',
col_scale=colorscale, year=2007, bg_color=bg_color, template=template)
# Create the map figure
map_europe = create_map(df_gap, locations='iso_alpha', color_v='gdpPercap',
col_scale=colorscale, bg_color=bg_color
).update_layout(margin=dict(l=0, r=0, t=0, b=0))
# Create Markdown objects for saving options
md_array = html.Div(
dcc.Markdown(f'''
```python
{colorscale}
```
'''))
md_code = html.Div(
dcc.Markdown(f'''
```python
import plotly.express as px
{full_palette_name}
```
'''))
return cb, scatter_plot, area_chart, treemap, map_europe, md_array, md_code
if __name__ == "__main__":
app.run_server(debug=False)