Skip to content

Route /data/user_input

user_input is the country code (CODE_ISO3) that is use in the web address. For now year is 2024 (as a string) This data is created in the app.py file and loaded in data.js as a json. data.fsi returns the result of query1 and so on

Query 1 : Last year FSI (could be removed)

SELECT e.iso3, e.country, year_fsi, total,
    c1_security_apparatus, c2_factionalized_elites, c3_group_grievance, e1_economy,
    e2_economic_inequality, e3_human_flight_brain_drain, p1_state_legitimacy, p2_public_services,
    p3_human_rights, s1_demographic_pressures, s2_refugees_idps, x1_external_intervention
    FROM  draft_schema.fsi_exports as f 
    LEFT JOIN draft_schema.equivalency_table as e 
    ON f.country=e.fsi_name 
    WHERE (e.iso3 LIKE :user_input and f.year_fsi="""+year+""")""")

Query 2 : All year FSI

SELECT e.iso3, f.country, year_fsi, total,
    c1_security_apparatus, c2_factionalized_elites, c3_group_grievance, e1_economy,
    e2_economic_inequality, e3_human_flight_brain_drain, p1_state_legitimacy, p2_public_services,
    p3_human_rights, s1_demographic_pressures, s2_refugees_idps, x1_external_intervention
    FROM  draft_schema.fsi_exports as f 
    LEFT JOIN draft_schema.equivalency_table as e 
    ON f.country=e.fsi_name 
    WHERE e.iso3 LIKE :user_input""")

Query 2 : Last year FSI and region average

    query2a = text("""SELECT e.iso3, e.region, f.country, year_fsi, total,
    c1_security_apparatus, c2_factionalized_elites, c3_group_grievance, e1_economy,
    e2_economic_inequality, e3_human_flight_brain_drain, p1_state_legitimacy, p2_public_services,
    p3_human_rights, s1_demographic_pressures, s2_refugees_idps, x1_external_intervention
FROM draft_schema.fsi_exports AS f
LEFT JOIN draft_schema.equivalency_table AS e
ON f.country = e.fsi_name
WHERE e.iso3 LIKE :user_input AND f.year_fsi = 2024

UNION ALL

SELECT 'AVG' AS iso3, e.region, CONCAT(e.region, ' Average') AS country, 2024 AS year_fsi, AVG(total) AS total,
    AVG(c1_security_apparatus) AS c1_security_apparatus, AVG(c2_factionalized_elites) AS c2_factionalized_elites, AVG(c3_group_grievance) AS c3_group_grievance, AVG(e1_economy) AS e1_economy,
    AVG(e2_economic_inequality) AS e2_economic_inequality, AVG(e3_human_flight_brain_drain) AS e3_human_flight_brain_drain, AVG(p1_state_legitimacy) AS p1_state_legitimacy, AVG(p2_public_services) AS p2_public_services,
    AVG(p3_human_rights) AS p3_human_rights, AVG(s1_demographic_pressures) AS s1_demographic_pressures, AVG(s2_refugees_idps) AS s2_refugees_idps, AVG(x1_external_intervention) AS x1_external_intervention
FROM draft_schema.fsi_exports AS f
LEFT JOIN draft_schema.equivalency_table AS e
ON f.country = e.fsi_name
WHERE e.region = (SELECT region FROM draft_schema.equivalency_table WHERE iso3 LIKE :user_input)
AND f.year_fsi = 2024
group by e.region""")

Query 3 : acled_index

select * from  draft_schema.acled_index as a where a.iso3 LIKE :user_input

Query 4 : inform_index (unused)

select * from draft_schema.inform_index where iso3 LIKE :user_input

Query 5 : narrative

SELECT current_text FROM draft_schema.narrative WHERE narrative.iso3 LIKE :user_input

Query 6 : timeline

select json_text FROM draft_schema.timeline WHERE timeline.iso3 LIKE :user_input

Query 7 : acled_index_def

select * from draft_schema.acled_index_def

Query 8 : IHL

SELECT iso3, oecd, cahra, country,region, wbfcs FROM draft_schema.equivalency_table WHERE equivalency_table.iso3 LIKE :user_input

Query 9 : RULAC

SELECT appear FROM draft_schema.rulac AS r LEFT JOIN draft_schema.equivalency_table AS e ON r.country = e.fsi_name WHERE e.iso3 LIKE :user_input

Query 10 : FSI definitions

select * from draft_schema.fsi_definitions

Query 10b : FSI categories

select * from draft_schema.fsi_categories

Query 11 : ACLED events data

    query11 = text("SELECT iso,event_date,event_id_cnty,disorder_type,event_type,sub_event_type,admin1,admin2,admin3,location,actor1,actor2,assoc_actor_1,assoc_actor_2,inter1,inter2,interaction,civilian_targeting,fatalities,longitude,latitude,notes,source_scale,geom,ST_AsGeoJSON(geom) FROM draft_schema.acled_events LEFT JOIN draft_schema.equivalency_table ON acled_events.iso =equivalency_table.iso3166num where equivalency_table.iso3 like :user_input")
    gdf = gpd.read_postgis(query11, engine, geom_col='geom',params={"user_input": f"%{user_input}%"})
    gdf['event_date'] = gdf['event_date'].astype(str)
    #"gdf:\n%s", gdf.head(2))
    df11 = gdf.to_json()
    ```
## Query 12 : Salient narrative
```sql    
SELECT current_text FROM draft_schema.salient WHERE salient.iso3 LIKE :user_input

Query 13 : Due diligence

SELECT sector,current_text FROM draft_schema.due_diligence WHERE due_diligence.iso3 LIKE :user_input

Query 14 : ACLED actors (unused, for network graph)

SELECT actor1,actor2,assoc_actor_1,assoc_actor_2,inter1,inter2,fatalities FROM draft_schema.acled_events LEFT JOIN draft_schema.equivalency_table ON acled_events.iso =equivalency_table.iso3166num where equivalency_table.iso3 like :user_input

Actors information is separated in 6 columns: actor1,actor2,assoc_actor_1,assoc_actor_2,inter1,inter2. The inter columns give information about the category of actors but for actors present in associate actors columns, the information may be missing. These columns also can have more than one actor. So the challenge is to build back the relation between an event and all the actors.

# Create a DataFrame with actors and interactions
actors = []
# Collect all actors names 
for row in df14:
    if row['actor1']:
        actors.append({'actor': row['actor1']})
    if row['actor2']:
        actors.append({'actor': row['actor2']})
    if row['assoc_actor_1']:
        # if there is a ";" there is more than an actor, divide the string
        if ";" in row['assoc_actor_1']:
            for part in row['assoc_actor_1'].split(';'):
                actors.append({'actor': part.strip()})
        else:
            actors.append({'actor': row['assoc_actor_1']})
    if row['assoc_actor_2']:
        if ";" in row['assoc_actor_2']:
            for part in row['assoc_actor_2'].split(';'):
                actors.append({'actor': part.strip()})
        else:
            actors.append({'actor': row['assoc_actor_2']})

actors_df = pd.DataFrame(actors).drop_duplicates()
interactions = []
# Create list
for row in df14:
    interactions.append({'actor': row['actor1'], 'category': row['inter1']})
    if row['actor2']:
        interactions.append({'actor': row['actor2'], 'category': row['inter2']})
    if row['assoc_actor_1']:
        interactions.append({'actor': row['assoc_actor_1'], 'category': 'unknown'})
    if row['assoc_actor_2']:
        interactions.append({'actor': row['assoc_actor_2'], 'category': 'unknown'})

interactions_df = pd.DataFrame(interactions).drop_duplicates()

# Remove "unknown" interactions if there is another interaction for the same actor
known_interactions = interactions_df[interactions_df['category'] != 'unknown']
unknown_interactions = interactions_df[interactions_df['category'] == 'unknown']
filtered_unknown_interactions = unknown_interactions[~unknown_interactions['actor'].isin(known_interactions['actor'])]
interactions_df = pd.concat([known_interactions, filtered_unknown_interactions]).drop_duplicates()

data14 = pd.merge(actors_df, interactions_df, on='actor', how='left')

# Change NaN values in the 'interaction' column to 'unknown'
data14['category'] = data14['category'].fillna('unknown')
data14 = data14.to_dict(orient='records')

Query 15 : Extract information for describing outliers Admin level 1

SELECT a.admin1, EXTRACT(YEAR FROM a.event_date) AS year_acled,
    COUNT(a.*) AS event_count, sum(a.fatalities) as fatalities_count
    FROM draft_schema.acled_events AS a
    LEFT JOIN draft_schema.equivalency_table AS e
    ON a.iso = e.iso3166num
    WHERE e.iso3 LIKE :user_input GROUP BY a.admin1, year_acled
    ORDER BY year_acled, a.admin1;""")
df15 = pd.read_sql(query15, engine, params={"user_input": f"%{user_input}%"})
df15_grouped = df15.groupby('admin1').apply(lambda x: {
    'year_acled': x['year_acled'].tolist(),
    'event_count': x['event_count'].tolist(),
    'fatalities_count': x['fatalities_count'].tolist()
}).to_dict()

Query 16 : Extract information for describing outliers sub event type

SELECT a.sub_event_type, EXTRACT(YEAR FROM a.event_date) AS year_acled,
COUNT(a.*) AS event_count, sum(a.fatalities) as fatalities_count
FROM draft_schema.acled_events AS a
LEFT JOIN draft_schema.equivalency_table AS e
ON a.iso = e.iso3166num
WHERE e.iso3 LIKE :user_input GROUP BY a.sub_event_type, year_acled
ORDER BY year_acled, a.sub_event_type;""")

Fetch data

This data is not directly load with the rest. It contains geospatial information used on the webmap (ICCA and Views dataset) that has been entered manually, usually after creating a geojson file and loading it in the database. The python code is transofrming the collected data in a geodatabase that is then passed as json.

def load_icca_point(user_input):
    query = text("""SELECT s.iso3,name_eng, objectives, manag_auth, habit_type,comm_name, threats, geom,ST_AsGeoJSON(geom) 
    FROM draft_schema.icca_point as s 
    LEFT JOIN draft_schema.equivalency_table as e 
    ON s.iso3 =e.iso3
    where e.iso3 like :user_input""")
    gdf = gpd.read_postgis(query, engine, geom_col='geom',params={"user_input": f"%{user_input}%"})
    geojson = gdf.to_json()
    return jsonify(geojson)
    ```

## Javascript call
```js
fetch('/load_icca_point/'+data.iso3)
    .then(response => {
        // Log the response object
        return response.json();
    })
    .then(data => {
        console.log('ICCA Data:', data)
        ...
    })