Hello everyone,
This is my web app/dashboard for week 9.
Here’s a brief overview:
-
Data Handling: The app processes a CSV file containing treaty information, including cleaning and translating the “Status” column and extracting the first tag from the “Tags” column.
-
Filtering: Users can filter treaties by:
- Historical Period (e.g., Independence and Early Development)
- Region (e.g., America, Europe)
- Treaty Status (e.g., Active, Terminated)
-
Visualizations: The app includes two main visualizations:
- Line Chart: Shows the trend of treaty status over the years, filtered by the selected criteria.
- Choropleth Map: Displays the number of treaties per country, also filtered by the selected criteria.
-
Interactive Details: Clicking on a country in the map reveals a “Detailed Treaty Information” section. This section lists the number of treaties for that country, grouped and ordered by their tags (topics). The country name is also included in this section’s title.
Images
Web App Link:
Any comments/suggestion are more than welcome
Code
import dash
from dash import dcc, html, Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
df = pd.read_csv("Argentina-bilateral-instruments-1810-2023.csv", parse_dates=['Sign date'], date_format='mixed')
status_dict = {
'Vigente': 'Active',
'Extinguido': 'Terminated',
'No está en vigor': 'Not in Force',
'Vigente con Modificaciones': 'Active with Modifications',
'En aplicación provisional': 'Provisionally Applied'
}
df['Status'] = df['Status'].replace(status_dict).fillna('Not Available')
df['Tags'] = df.Tags.str.split('\n',expand=True)[0]
periods = {
'Independence and Early Development': (1810, 1852),
'National Unification and Expansion': (1852, 1916),
'20th Century Challenges': (1916, 2000),
'21st Century Globalization': (2000, 2023)
}
def period_filtered(df, period):
start, end = periods[period]
return df[(df['Sign year'] >= start) & (df['Sign year'] <= end)]
radio_style = {
'display': 'flex','flex-direction': 'row',
'justify-content': 'space-between','padding': '5px',
'border-radius': '5px',
'boxShadow': '3px 3px 3px rgba(177, 250, 249 0.3)',
'font-family': 'Aharoni, sans-serif','font-size': '20px',
}
header_style ={'text-align': 'center','margin': '10px 0',
'background': 'linear-gradient(to bottom, #d7f3fc, #FFFFFF, #d7f3fc)'}
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.ZEPHYR])
app.title = 'Argentina Bilateral Treaties'
app.layout = dbc.Container([
html.H1("An Overall Look at Argentina´s Bilateral Treaty Evolution", style=header_style),
dbc.Row([
dbc.Col([
dbc.Select(
id='period-dropdown',
options=[{'label': period, 'value': period} for period in periods],
value='National Unification and Expansion'),
dbc.Tooltip("Select A Period", target="period-dropdown")], width=3),
dbc.Col([
dbc.Select(
id='region-select',
options=[{'label': region,
'value': region} for region in ['America', 'Europe', 'Asia and Oceania', 'Africa and Middle East']],
value='America'),
dbc.Tooltip("Select A Region", target="region-select")
], width=3),
], style={'margin-bottom': '20px'}),
html.Hr(),
dbc.Row([
dbc.Col([
dbc.Card([
html.H4("Treaty Status Over the Years", style=header_style),
dcc.Graph(id='treaty-graph')
]),
dbc.Card([
html.H4("Bilateral Treaties by Region-Country", style=header_style),
dcc.Graph(id='choropleth-map')
])
], width=7),
dbc.Col([
dbc.Card([
html.H4("Treaty Status", style=header_style),
dbc.Checklist(
id='status-filter',
options=[
{"label": "Active", "value": "Active"},
{"label": "Active with Modifications", "value": "Active with Modifications"},
{"label": "Not in Force", "value": "Not in Force"},
{"label": "Terminated", "value": "Terminated"},
{"label": "Provisionally Applied", "value": "Provisionally Applied"},
],
value=['Active'],
inline=True,
style=radio_style,
),
], style={"margin-bottom": "20px"}),
dbc.Card([
html.H4("Detailed Treaty Information", style=header_style),
html.Div(id='treaty-info', style={"padding": "10px"})
])
], width=5)
])
], fluid=True)
@app.callback(
[Output('treaty-graph', 'figure'),
Output('choropleth-map', 'figure'),
Output('treaty-info', 'children')],
[Input('period-dropdown', 'value'),
Input('region-select', 'value'),
Input('status-filter', 'value'),
Input('choropleth-map', 'clickData')]
)
def update_graphs(selected_period, region, status_filter, clickData):
df_filtered = period_filtered(df, selected_period)
df_region = df_filtered[df_filtered['Region ENG'] == region]
if status_filter:
df_region = df_region[df_region['Status'].isin(status_filter)]
status_df = (df_region.groupby(['Sign year', 'Status'], as_index=False)
['Counterpart (original)'].count())
fig_line = px.line(status_df, x='Sign year', y='Counterpart (original)',
color='Status',
labels={'Counterpart (original)': 'Number of Agreements', 'Status': ''},
category_orders={"Status": ['Active', 'Active with Modifications', 'Not in Force',
'Terminated', 'Provisionally Applied']},
markers=True, template='xgridoff')
fig_line.update_layout(
legend=dict(orientation="h", y=1.1, yanchor='top', x=0.5, xanchor='center')
)
treaties_by_country = (df_region.groupby(['Counterpart ISO','Counterpart ENG'])
.size()
.reset_index(name='count'))
if treaties_by_country.empty:
fig_map = px.choropleth(title="No data available for selected options")
fig_map.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0}) # Ajustar márgenes si es necesario
else:
fig_map = px.choropleth(treaties_by_country,
locations='Counterpart ISO',
locationmode="ISO-3",
color='count',
hover_name='Counterpart ENG',
labels={'count': 'Number of Treats'},
projection="aitoff",
color_continuous_scale="haline")
fig_map.update_layout(
margin={"r": 0, "t": 0, "l": 0, "b": 0},
coloraxis_colorbar=dict(len=0.5, thickness=15,orientation="h", y=-0.15, x=0.5, xanchor='center')
)
country_info = "Click on a country in the map to see treaty details."
country_name = ""
if clickData:
country_iso = clickData['points'][0]['location']
country_treaties = df_region[df_region['Counterpart ISO'] == country_iso]
if not country_treaties.empty:
country_name = country_treaties['Counterpart ENG'].iloc[0]
treaties_by_tag = (country_treaties.groupby('Tags')
.size()
.reset_index(name='count')
.sort_values('count', ascending=False))
if not treaties_by_tag.empty:
country_info = html.Div([ # Contenedor para el título y la información
html.H6(f"Treaties with {country_name}"),
html.H6(f"Number of Treaties by Topic: "),
html.Ul([
html.Li(f"{row['Tags']}: {row['count']}")
for _, row in treaties_by_tag.iterrows()
])
])
else:
country_info = html.Div([
html.H6(f"Treaties with {country_name}"),
"No treaty information available for this country with the current filters."
])
return fig_line, fig_map, country_info
if __name__ == '__main__':
app.run_server(debug=True)type or paste code here