.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/tables_and_summaries/make_exposure.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_tables_and_summaries_make_exposure.py: Create exposure weights from forecast point density =================================================== This example teaches you how to use GeoPrior's ``make-exposure`` utility. Unlike the plotting scripts, this command builds a lightweight support artifact. It turns forecast point locations into a compact exposure table that later workflows can reuse. Why this matters ---------------- Some later analyses need a simple per-sample weight layer, even when no external population or asset raster is available. This builder creates exactly that from point geometry: - one row per spatial sample, - one exposure value per sample, - either uniform or density-based. That makes it a natural lesson for the ``tables_and_summaries`` gallery. .. GENERATED FROM PYTHON SOURCE LINES 28-33 Imports ------- We call the real production entrypoint from the project code. Then we read the generated CSV back in and build one compact preview for the lesson page. .. GENERATED FROM PYTHON SOURCE LINES 33-47 .. code-block:: Python from __future__ import annotations import tempfile from pathlib import Path import matplotlib.pyplot as plt import numpy as np import pandas as pd from geoprior.scripts.make_exposure import ( make_exposure_main, ) .. GENERATED FROM PYTHON SOURCE LINES 48-65 Build compact synthetic point clouds ------------------------------------ The production script only needs: - sample_idx - coord_x - coord_y in both eval and future CSVs. For the lesson, we create: - Nansha - Zhongshan with spatially non-uniform point clouds, so the density-based exposure mode has something interesting to detect. .. GENERATED FROM PYTHON SOURCE LINES 65-150 .. code-block:: Python rng = np.random.default_rng(17) def _clustered_city_points( *, city: str, centers: list[tuple[float, float]], scales: list[tuple[float, float]], counts: list[int], drift: tuple[float, float], ) -> tuple[pd.DataFrame, pd.DataFrame]: xs_eval: list[np.ndarray] = [] ys_eval: list[np.ndarray] = [] xs_future: list[np.ndarray] = [] ys_future: list[np.ndarray] = [] for (cx, cy), (sx, sy), n in zip( centers, scales, counts, strict=True, ): xe = rng.normal(cx, sx, size=n) ye = rng.normal(cy, sy, size=n) xf = rng.normal(cx + drift[0], sx * 1.05, size=n) yf = rng.normal(cy + drift[1], sy * 1.05, size=n) xs_eval.append(xe) ys_eval.append(ye) xs_future.append(xf) ys_future.append(yf) xe = np.concatenate(xs_eval) ye = np.concatenate(ys_eval) xf = np.concatenate(xs_future) yf = np.concatenate(ys_future) n_total = xe.shape[0] eval_df = pd.DataFrame( { "city": city, "sample_idx": np.arange(n_total, dtype=int), "coord_x": xe.astype(float), "coord_y": ye.astype(float), } ) future_df = pd.DataFrame( { "city": city, "sample_idx": np.arange(n_total, dtype=int), "coord_x": xf.astype(float), "coord_y": yf.astype(float), } ) return eval_df, future_df ns_eval_df, ns_future_df = _clustered_city_points( city="Nansha", centers=[(1180.0, 780.0), (1260.0, 820.0), (1125.0, 725.0)], scales=[(22.0, 16.0), (18.0, 13.0), (28.0, 20.0)], counts=[90, 35, 20], drift=(8.0, 4.0), ) zh_eval_df, zh_future_df = _clustered_city_points( city="Zhongshan", centers=[(1710.0, 1060.0), (1820.0, 1110.0), (1650.0, 980.0)], scales=[(28.0, 18.0), (22.0, 16.0), (35.0, 24.0)], counts=[80, 40, 25], drift=(10.0, 6.0), ) print("Nansha eval preview") print(ns_eval_df.head(6).to_string(index=False)) print("") print("Zhongshan future preview") print(zh_future_df.head(6).to_string(index=False)) .. rst-class:: sphx-glr-script-out .. code-block:: none Nansha eval preview city sample_idx coord_x coord_y Nansha 0 1204.2278 779.8649 Nansha 1 1187.4455 773.4675 Nansha 2 1168.1206 794.5660 Nansha 3 1152.2747 785.0112 Nansha 4 1138.3183 756.1716 Nansha 5 1180.4100 771.2821 Zhongshan future preview city sample_idx coord_x coord_y Zhongshan 0 1682.2417 1078.2608 Zhongshan 1 1690.1803 1085.8537 Zhongshan 2 1733.3494 1089.6276 Zhongshan 3 1708.0193 1077.3014 Zhongshan 4 1730.1795 1100.4336 Zhongshan 5 1666.5159 1061.4519 .. GENERATED FROM PYTHON SOURCE LINES 151-155 Write the lesson inputs ----------------------- We follow the real command's file-based workflow with explicit per-city eval/future CSVs. .. GENERATED FROM PYTHON SOURCE LINES 155-180 .. code-block:: Python tmp_dir = Path( tempfile.mkdtemp(prefix="gp_sg_exposure_") ) ns_eval_csv = tmp_dir / "nansha_eval.csv" ns_future_csv = tmp_dir / "nansha_future.csv" zh_eval_csv = tmp_dir / "zhongshan_eval.csv" zh_future_csv = tmp_dir / "zhongshan_future.csv" ns_eval_df.to_csv(ns_eval_csv, index=False) ns_future_df.to_csv(ns_future_csv, index=False) zh_eval_df.to_csv(zh_eval_csv, index=False) zh_future_df.to_csv(zh_future_csv, index=False) print("") print("Input files") for p in [ ns_eval_csv, ns_future_csv, zh_eval_csv, zh_future_csv, ]: print(" -", p.name) .. rst-class:: sphx-glr-script-out .. code-block:: none Input files - nansha_eval.csv - nansha_future.csv - zhongshan_eval.csv - zhongshan_future.csv .. GENERATED FROM PYTHON SOURCE LINES 181-189 Run the real exposure builder ----------------------------- We ask the production command to: - use explicit city CSVs, - build density-based exposure, - use a moderate kNN size, - and write one combined CSV. .. GENERATED FROM PYTHON SOURCE LINES 189-212 .. code-block:: Python out_csv = tmp_dir / "exposure_gallery.csv" make_exposure_main( [ "--ns-eval", str(ns_eval_csv), "--ns-future", str(ns_future_csv), "--zh-eval", str(zh_eval_csv), "--zh-future", str(zh_future_csv), "--mode", "density", "--k", "20", "--out", str(out_csv), ], prog="make-exposure", ) .. rst-class:: sphx-glr-script-out .. code-block:: none [OK] wrote /tmp/gp_sg_exposure_mzxsjmwk/exposure_gallery.csv .. GENERATED FROM PYTHON SOURCE LINES 213-216 Read the produced artifact -------------------------- The real script writes one CSV containing all selected cities. .. GENERATED FROM PYTHON SOURCE LINES 216-227 .. code-block:: Python expo = pd.read_csv(out_csv) print("") print("Written file") print(" -", out_csv.name) print("") print("Exposure table preview") print(expo.head(12).to_string(index=False)) .. rst-class:: sphx-glr-script-out .. code-block:: none Written file - exposure_gallery.csv Exposure table preview city sample_idx exposure Nansha 0 1.1662 Nansha 1 1.5676 Nansha 2 1.2586 Nansha 3 1.2625 Nansha 4 0.6851 Nansha 5 1.6690 Nansha 6 1.5766 Nansha 7 1.6172 Nansha 8 0.6902 Nansha 9 1.8073 Nansha 10 0.7365 Nansha 11 0.8443 .. GENERATED FROM PYTHON SOURCE LINES 228-233 Join exposure back to coordinates for plotting ---------------------------------------------- The output CSV does not repeat coordinates, so for the lesson preview we merge the exposure values back onto the eval point locations. .. GENERATED FROM PYTHON SOURCE LINES 233-256 .. code-block:: Python pts_eval = pd.concat( [ ns_eval_df.assign(city="Nansha"), zh_eval_df.assign(city="Zhongshan"), ], ignore_index=True, ) expo_plot = pts_eval.merge( expo, on=["city", "sample_idx"], how="inner", ) print("") print("Exposure summary by city") print( expo.groupby("city")["exposure"] .agg(["count", "min", "mean", "max"]) .to_string() ) .. rst-class:: sphx-glr-script-out .. code-block:: none Exposure summary by city count min mean max city Nansha 145 0.2849 1.0000 1.8491 Zhongshan 145 0.2744 1.0000 1.8135 .. GENERATED FROM PYTHON SOURCE LINES 257-267 Build one compact visual preview -------------------------------- This preview is not part of the production builder itself. It is a teaching aid for the gallery page. Left: Nansha point map colored by exposure. Right: city-wise exposure histograms. .. GENERATED FROM PYTHON SOURCE LINES 267-301 .. code-block:: Python fig, axes = plt.subplots( 1, 2, figsize=(10.0, 4.2), constrained_layout=True, ) # Point map for Nansha ax = axes[0] sub = expo_plot.loc[expo_plot["city"] == "Nansha"].copy() sc = ax.scatter( sub["coord_x"].to_numpy(float), sub["coord_y"].to_numpy(float), c=sub["exposure"].to_numpy(float), s=18, ) ax.set_title("Nansha density exposure") ax.set_xlabel("coord_x") ax.set_ylabel("coord_y") fig.colorbar(sc, ax=ax, fraction=0.046, pad=0.04).set_label( "Exposure" ) # Histograms ax = axes[1] for city in ["Nansha", "Zhongshan"]: sub = expo.loc[expo["city"] == city, "exposure"].to_numpy(float) ax.hist(sub, bins=18, alpha=0.6, label=city) ax.set_title("Exposure distribution by city") ax.set_xlabel("Exposure") ax.set_ylabel("Count") ax.legend(fontsize=8) .. image-sg:: /auto_examples/tables_and_summaries/images/sphx_glr_make_exposure_001.png :alt: Nansha density exposure, Exposure distribution by city :srcset: /auto_examples/tables_and_summaries/images/sphx_glr_make_exposure_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 302-307 Compare with uniform mode ------------------------- The command also supports a pure uniform mode. That mode is useful when you want a placeholder exposure layer without introducing any density effect. .. GENERATED FROM PYTHON SOURCE LINES 307-331 .. code-block:: Python uniform_csv = tmp_dir / "exposure_uniform_gallery.csv" make_exposure_main( [ "--cities", "ns", "--ns-eval", str(ns_eval_csv), "--ns-future", str(ns_future_csv), "--mode", "uniform", "--out", str(uniform_csv), ], prog="make-exposure", ) uniform_df = pd.read_csv(uniform_csv) print("") print("Uniform exposure preview") print(uniform_df.head(8).to_string(index=False)) .. rst-class:: sphx-glr-script-out .. code-block:: none [OK] wrote /tmp/gp_sg_exposure_mzxsjmwk/exposure_uniform_gallery.csv Uniform exposure preview city sample_idx exposure Nansha 0 1.0000 Nansha 1 1.0000 Nansha 2 1.0000 Nansha 3 1.0000 Nansha 4 1.0000 Nansha 5 1.0000 Nansha 6 1.0000 Nansha 7 1.0000 .. GENERATED FROM PYTHON SOURCE LINES 332-345 Learn how to read this artifact ------------------------------- The output is intentionally minimal. Each row contains: - ``city`` - ``sample_idx`` - ``exposure`` That means the artifact is designed to be joined back onto another table by ``(city, sample_idx)`` rather than to stand alone as a full spatial dataset. .. GENERATED FROM PYTHON SOURCE LINES 347-358 What density exposure means here -------------------------------- In density mode, the script computes a simple geometric proxy: - find the k nearest neighbors, - compute the mean neighbor distance, - take its inverse, - normalize the resulting scores to mean 1. So larger values indicate samples in denser local point regions, not necessarily regions with higher true population or damage. .. GENERATED FROM PYTHON SOURCE LINES 360-368 Why deduplication matters ------------------------- The builder concatenates eval and future point sets, then drops duplicate ``sample_idx`` values per city before computing exposure. That is important because the same spatial sample often appears in both files, and we want one exposure value per logical sample, not one per file row. .. GENERATED FROM PYTHON SOURCE LINES 370-381 Why this page belongs after make_district_grid.py ------------------------------------------------- A useful support-layer workflow is: 1. build a boundary, 2. build a district grid, 3. build an exposure proxy, 4. then use those layers in cluster or hotspot summaries. The artifacts are different, but they all reuse the same underlying point geometry. .. GENERATED FROM PYTHON SOURCE LINES 383-423 Command-line version -------------------- The same lesson can be reproduced from the CLI. Legacy dispatcher: .. code-block:: bash python -m scripts make-exposure \ --ns-eval results/nansha_eval.csv \ --ns-future results/nansha_future.csv \ --zh-eval results/zhongshan_eval.csv \ --zh-future results/zhongshan_future.csv \ --mode density \ --k 30 \ --out exposure Uniform mode: .. code-block:: bash python -m scripts make-exposure \ --ns-src results/nansha_run \ --split auto \ --mode uniform \ --out exposure_uniform Modern CLI: .. code-block:: bash geoprior build exposure \ --ns-src results/nansha_run \ --zh-src results/zhongshan_run \ --split auto \ --mode density \ --k 30 \ --out exposure The gallery page teaches the builder. The command line reproduces it in a workflow. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.392 seconds) .. _sphx_glr_download_auto_examples_tables_and_summaries_make_exposure.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: make_exposure.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: make_exposure.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: make_exposure.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_