CoolFace
Apppublic

nohadkeltayeb/religious-targeting-monitor

sourceHugging Faceupdated 4mo agoView on Hugging Face
0likes
App README

<!-- The YAML block above configures the Hugging Face Space; it is ignored by GitHub and by the app itself. -->

Religious Targeting Monitor

Unified Dash application combining two views over ACLED conflict data:

  1. 1.Religious Targeting Monitor — country-level monitoring of violence against religious groups: trend alert, event timeline with PELT change detection, interactive map over religious-majority geography (Joshua Project), and perpetrator/region breakdowns.
  2. 2.Actor Footprint & Profiles — hex-level armed-actor territories (dominance & contestation, Dirichlet evidence model) with behavioral profile cards, including per-actor religious-targeting metrics.

Methodology

  • —docs/methodology_religious_targeting.md — event classification (assocactor2 based), trend alert, religion choropleth, profile metrics.
  • —docs/methodology_hex.md — the hex footprint model (scoring, decay, diffusion, contestation).

Structure

FileRole
config.pyAll parameters — country list (`TARGET_COUNTRIES`), data paths, model tunables
religion_classification.pyShared religious-targeting classifier (assocactor2 only)
run_pipeline.pyOrchestrator: monitor parquet + hex footprint + actor profiles
data_preprocessing.pyLoad + filter ACLED (file or API), country filter
state_forces.py / hex_assignment.py / actor_scoring.py / periods.py / actor_hex_output.pyHex footprint pipeline
actor_profiles.pyBehavioral profiles incl. religious-targeting metrics
build_admin_religion.pyAdmin1 religion choropleth from Joshua Project (writes output/*.geojson)
app.pyThe Dash application (both tabs)

Data directories (tracked files are parquet; raw inputs stay local — see .gitignore):

  • —data/ — joshua_project.parquet, bandit_map.parquet (tracked); the raw ACLED export (path in config.py) is local-only
  • —map data/ — preprocessed hex_population_{country}.parquet, hex_infrastructure_{country}.parquet (CSV fallback supported)
  • —map data v3/ — pipeline outputs read by the app
  • —output/ — {country}_admin1_religion.geojson choropleths
  • —Global_Admin1_v1_July2025/ — admin1 boundary shapefile (local-only, used by build_admin_religion.py)

Setup & run

bash
pip install -r requirements.txt

# optional: Mapbox styling
cp .env.example .env   # then fill in MAPBOX_TOKEN / MAPBOX_STYLE

# 1. build all derived data (monitor parquet, footprint, profiles)
python run_pipeline.py

# 2. (only when countries change) rebuild the religion choropleths
python build_admin_religion.py

# 3. launch the app → http://127.0.0.1:8051
python app.py

Changing the country list

Edit TARGET_COUNTRIES in config.py, then:

  1. 1.ensure the ACLED export (ACLED_FILE_PATH) covers the new countries,
  2. 2.add hex_population_{country}.csv / hex_infrastructure_{country}.csv to map data/ (preprocessed in the actor-footprint-tool project),
  3. 3.re-run run_pipeline.py and build_admin_religion.py.

Updating the data

Drop a new ACLED export into data/, point ACLED_FILE_PATH in config.py at it, and re-run run_pipeline.py. (Alternatively set DATA_SOURCE = "api" with ACLED_EMAIL/ACLED_PASSWORD in .env.)

Deploying to Render

The deployed app only serves pre-built data — map data v3/, map data/, output/*.geojson, and the two parquet files in data/ — all of which are tracked in git. Raw ACLED exports and the boundary shapefile are gitignored; run the pipeline locally and commit the regenerated outputs to update the deployment.

  1. 1.Run python run_pipeline.py locally, commit, and push to GitHub.
  2. 2.On render.com: New → Blueprint, connect the repo — render.yaml configures the service (gunicorn, Python version). Or create a Web Service manually with:
  3. 3.Build: pip install -r requirements.txt
  4. 4.Start: gunicorn app:server --bind 0.0.0.0:$PORT --workers 1 --threads 4 --timeout 120
  5. 5.Optionally set MAPBOX_TOKEN / MAPBOX_STYLE in the service's Environment tab (the map falls back to a free CartoDB basemap without them).

Note: the free plan spins down after ~15 min idle (cold start on next visit); the starter plan stays warm.