from dash import Dash, dcc, html, Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
# Load data
df = pd.read_csv("https://raw.githubusercontent.com/plotly/Figure-Friday/refs/heads/main/2025/week-10/Popularity%20of%20Programming%20Languages%20from%202004%20to%202024.csv")
# Convert 'Date' to year format
df['Date'] = pd.to_datetime(df['Date']).dt.year
df['Date'] = df['Date'].astype(int)
# Get available years and languages
available_years = sorted(df['Date'].unique())[-5:]
available_languages = df.columns[1:].tolist()
# List of Plotly colorscales
colorscales = ["plasma", "viridis", "magma", "cividis", "inferno", "turbo", "sunset"]
# Initialize Dash app with Bootstrap
app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
# Layout
app.layout = dbc.Container(fluid=True, children=[
dbc.Row([
dbc.Col(html.H1("Programming Languages Popularity in the last 5 years", className="text-center text-dark my-4"), width=12)
]),
html.Br(),
dbc.Row([
dbc.Col([
html.Label("Select Year(s):", className="text-dark"),
dcc.Dropdown(
id="year-selector",
options=[{"label": str(year), "value": year} for year in available_years],
value=2024,
multi=False, #you can select False or True!!!!!!!!
#multi=True,
clearable=True,
),
html.Br(),
html.Label("Select Language(s):", className="text-dark"),
dcc.Dropdown(
id="language-selector",
options=[{"label": lang, "value": lang} for lang in available_languages] + [{"label": "All", "value": "All"}],
value=available_languages[:8],
multi=True
),
html.Br(),
html.Label("Select Colorscale:", className="text-dark"),
dcc.Dropdown(
id="colorscale-selector",
options=[{"label": cs, "value": cs} for cs in colorscales],
value="plasma",
clearable=False
),
], width=3),
dbc.Col([
dcc.Tabs(
id="tabs",
children=[
dcc.Tab(
label="Bar Chart",
children=[
dbc.Card(
dbc.CardBody([
dcc.Graph(id="ranked-bar-chart", style={"height": "70vh"})
])
)
],
style={'backgroundColor': 'white', 'color': 'black'},
selected_style={'backgroundColor': 'black', 'color': 'white'},
),
dcc.Tab(
label="Sunburst Chart",
children=[
dbc.Card(
dbc.CardBody([
dcc.Graph(id="ranked-sunburst-chart", style={"height": "70vh"})
])
)
],
style={'backgroundColor': 'white', 'color': 'black'},
selected_style={'backgroundColor': 'black', 'color': 'white'},
)
]
)
], width=9),
]),
dbc.Row([
dbc.Col(html.P("Data from Plotly's Figure Friday", className="text-center text-muted my-4"), width=12)
])
], style={"max-width": "1200px", "margin": "0 auto", "backgroundColor": "whitesmoke"})
# Callback for bar chart
@app.callback(
Output("ranked-bar-chart", "figure"),
[Input("year-selector", "value"),
Input("language-selector", "value"),
Input("colorscale-selector", "value")]
)
def update_bar_chart(selected_years, selected_languages, selected_colorscale):
if not isinstance(selected_years, list):
selected_years = [selected_years]
if not isinstance(selected_languages, list):
selected_languages = [selected_languages]
if "All" in selected_languages:
selected_languages = available_languages
df_filtered = df[df["Date"].isin(selected_years)]
df_filtered = df_filtered[["Date"] + selected_languages]
# Calculate average popularity for each language
language_averages = {}
for lang in selected_languages:
yearly_averages = []
for year in selected_years:
yearly_averages.append(df_filtered[df_filtered["Date"] == year][lang].mean())
language_averages[lang] = sum(yearly_averages) / len(yearly_averages) if yearly_averages else 0
language_averages_df = pd.DataFrame(list(language_averages.items()), columns=['Programming Language', 'Popularity'])
language_averages_df = language_averages_df.sort_values(by='Popularity', ascending=False)
bar_chart_fig = px.bar(
language_averages_df,
x="Popularity",
y="Programming Language",
orientation='h',
color="Popularity",
color_continuous_scale=selected_colorscale,
labels={"Popularity": "Average Popularity (%)", "Programming Language": ""},
category_orders={"Programming Language": language_averages_df["Programming Language"].tolist()}
)
bar_chart_fig.update_layout(
plot_bgcolor="white",
paper_bgcolor="white",
xaxis=dict(showline=True, linewidth=2, linecolor="black"),
yaxis=dict(showline=True, linewidth=2, linecolor="black"),
showlegend=False,
coloraxis_showscale=False,
)
# Update tooltip with percentage (2 decimal places)
bar_chart_fig.update_traces(
hovertemplate="%{customdata[0]}<br>Popularity: %{customdata[1]:.2f}%<extra></extra>",
customdata=language_averages_df[['Programming Language', 'Popularity']].values
)
return bar_chart_fig
# Callback for sunburst chart
@app.callback(
Output("ranked-sunburst-chart", "figure"),
[Input("year-selector", "value"),
Input("language-selector", "value"),
Input("colorscale-selector", "value")]
)
def update_sunburst_chart(selected_years, selected_languages, selected_colorscale):
if not isinstance(selected_years, list):
selected_years = [selected_years]
if not isinstance(selected_languages, list):
selected_languages = [selected_languages]
if "All" in selected_languages:
selected_languages = available_languages
df_filtered = df[df["Date"].isin(selected_years)]
df_filtered = df_filtered[["Date"] + selected_languages]
# Group by Date and calculate mean for each language
data = []
for year in selected_years:
year_df = df_filtered[df_filtered['Date'] == year]
for lang in selected_languages:
if year_df[lang].notna().all():
average_popularity = year_df[lang].mean()
data.append({'Date': year, 'Programming Language': lang, 'Popularity': average_popularity})
df_grouped = pd.DataFrame(data).dropna()
sunburst_fig = px.sunburst(
df_grouped,
path=["Date", "Programming Language"],
values="Popularity",
color="Popularity",
color_continuous_scale=selected_colorscale
)
# Update tooltip with percentage (2 decimal places)
sunburst_fig.update_traces(
hovertemplate="<b>%{label}</b><br>Popularity: %{value:.2f}%<extra></extra>"
)
sunburst_fig.update_layout(showlegend=False, coloraxis_showscale=False)
return sunburst_fig
if __name__ == "__main__":
app.run(debug=True)