Py.Cafe

banana0000/

Argentina's Bilaterals Treaties

Modal

DocsPricing
  • assets/
  • Argentina-bilateral-instruments-1810-2023.csv
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
from dash import Dash, dcc, html, Output, Input, State
import plotly.express as px
import pandas as pd
import dash_bootstrap_components as dbc
import plotly.graph_objects as go

# Load the data
df = pd.read_csv("Argentina-bilateral-instruments-1810-2023.csv")

# Filter for years after 2000
df = df[df["Sign year"] >= 2000]

# Initialize the Dash app with Bootstrap theme
app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP], suppress_callback_exceptions=True)


# App Layout
app.layout = html.Div(
    children=[
        dcc.Interval(id="title-delay", interval=2000, n_intervals=0, max_intervals=10),
        # Header Section with Title in a 100% wide container
        html.Div(
            dbc.Row(
                dbc.Col(
                    html.H1("Argentina's Bilaterals Treaties (from 2000 - 2023)", className="header-title"),
                    width=12  # Full width for the header
                ),
                justify="center",  # Center the row content
            ),
            className="header-container"  # 100% width container for header
        ),

        html.Br(),
        html.Br(),

        # Main chart (only annotation and smooth line)
        dcc.Graph(id="main-chart", style={"height": "500px", "width": "80%"}, className="main-chart"),

        # Hidden Store to manage modal state
        dcc.Store(id="modal-state", data=False),

        # Modal (initially hidden)
        dbc.Modal([
            dbc.ModalHeader("Treaties Details", className="modal-header "),
            dbc.ModalBody(id="modal-content", className="modal-body")  # Dynamic content
        ], id="year-modal", is_open=False, className="modal-container")
    ],
    className="layout-container"
)

# Callback to show the title after delay
@app.callback(
    Output("header-container", "style"),
    Input("title-delay", "n_intervals")
)
def show_title(n):
    if n > 0:
        return {"display": "block"}
    return {"display": "none"}


# Callback to display the modal when a year is clicked
@app.callback(
    [Output("year-modal", "is_open"),
     Output("modal-content", "children"),
     Output("modal-state", "data")],  # We only manage modal state
    [Input("main-chart", "clickData")],
    [State("modal-state", "data")],
    prevent_initial_call=True
)
def display_year_modal(clickData, is_open):
    if clickData:
        selected_year = clickData["points"][0]["x"]
        year_df = df[df["Sign year"] == selected_year]

        if year_df.empty:
            return True, html.P("No data for this year."), True

        country_counts = year_df["Counterpart ENG"].value_counts().reset_index()
        country_counts.columns = ["Country", "Count"]

        total_agreements = year_df.shape[0]
        top_country = country_counts.iloc[0]["Country"] if not country_counts.empty else "N/A"

        # KPI Cards
        kpi_cards = dbc.Row([  
            dbc.Col(dbc.Card([  
                dbc.CardBody([  
                    html.H6("Treaties", className="text-uppercase"),  
                    html.H3(f"{total_agreements}", className="text-primary")  
                ])  
            ], className="kpi-card shadow-sm p-3"), width=6),  

            dbc.Col(dbc.Card([  
                dbc.CardBody([  
                    html.H6("Top Country", className="text-uppercase"),  
                    html.H3(f"{top_country}", className="text-primary")  
                ])  
            ], className="kpi-card shadow-sm p-3"), width=6)  
        ], className="mb-3")

        # Horizontal bar chart
        bar_chart = dcc.Graph(
            figure=px.bar(
                country_counts.sort_values("Count", ascending=True),
                x="Count", y="Country", orientation="h",
                title="Treaties per Country",
                labels={"Count": "Number of Treaties", "Country": "Country"},
                color_discrete_sequence=["lightblue"],
                template="plotly_dark",
            ),
            style={"height": "500px", "width": "100%"}
        )

        # Remove Y-axis title from the bar chart
        bar_chart.figure.update_layout(
            yaxis_title=""  # Set the Y-axis title to an empty string to remove it
        )

        # Modal content
        modal_content = html.Div([
            html.H5(f"Year: {selected_year}"),
            kpi_cards,  
            bar_chart
        ])

        return True, modal_content, True  # Open modal and reset state

    return is_open, None, is_open  # Keep modal closed if no click data

# Callback to update the main chart
@app.callback(
    Output("main-chart", "figure"),
    Input("main-chart", "id")  # This is just for initialization
)
def update_main_chart(_):
    # Aggregate data by year
    yearly_data = df.groupby('Sign year').size().reset_index(name='Count')

    # Find the max value for annotation
    max_value = yearly_data["Count"].max()
    max_year = yearly_data[yearly_data["Count"] == max_value]["Sign year"].values[0]

    # Create the main chart without bars (just annotation and smooth line)
    main_fig = go.Figure()

    # Smooth line
    smooth_line = go.Scatter(
        x=yearly_data["Sign year"], 
        y=yearly_data["Count"],  
        mode='lines+markers',
        name='Count Line',
        line=dict(width=5, color='red'),
        marker=dict(color='red', size=15)
    )

    main_fig.add_trace(smooth_line)

    # Annotation for max value
    main_fig.add_annotation(
        x=max_year,
        y=max_value,
        text=f"Max Treaties: {max_value} in {max_year}",
        showarrow=True,
        arrowhead=2,
        ax=0,
        ay=-50,
        font=dict(size=24, color="red", family="Arial"),
        bgcolor="white",
        arrowcolor="white"
    )

    # Layout customization
    main_fig.update_layout(
        margin={"t": 50, "b": 100, "l": 50, "r": 50},
        height=500,
        showlegend=False,
        plot_bgcolor="black",
        paper_bgcolor="black",
        font=dict(color="white"),
        xaxis=dict(showgrid=False, zeroline=False, showline=False),
        yaxis=dict(showgrid=False, gridcolor='gray', zeroline=False, showline=False)
    )

    return main_fig

# Run the app
if __name__ == "__main__":
    app.run(debug=True)