Skip to content

Ejemplo 3: desarrollador de aplicaciones

Cómo incorporar datos de CalHeatScore en un servicio backend (para notificaciones) y en una aplicación cliente (para visualización en mapa).

Desarrollo de una aplicación de alerta de calor con CalHeatScore

Imagine que es un desarrollador de aplicaciones que está creando una aplicación de seguridad frente al calor para residentes de California, y desea integrar los datos de CalHeatScore en su herramienta. Su aplicación hará dos cosas: (i) enviará una notificación push cada mañana cuando el código postal del usuario alcance un puntaje Alto o Severo de CalHeatScore; (ii) mostrará un mapa interactivo para que el usuario pueda ver el riesgo de calor en su región al abrir la aplicación.

Usted planea usar la API de CalHeatScore para obtener los datos. La API es gratuita, no requiere autenticación y admite JSON para el servicio de notificaciones en el backend y GeoJSON para el mapa dentro de la aplicación.

El servicio backend consulta la API cada mañana, verifica el código postal de cada usuario registrado contra los puntajes más recientes y envía notificaciones push a cualquier usuario cuyo puntaje alcance el umbral de alerta.

En el lado cliente, la aplicación obtiene los datos en formato GeoJSON de la región del usuario y los presenta en un mapa.

Nota: El código de ejemplo que se muestra a continuación se centra únicamente en el acceso y la preparación de los datos.

Paso a paso: flujo de trabajo diario de datos de CalHeatScore

Paso 1: obtenga todos los datos de CalHeatScore (formato JSON)

Obtenga el conjunto de datos completo una vez cada mañana. Con aproximadamente 1,700 códigos postales de California y un límite de 2,000 registros por solicitud, una sola llamada normalmente devuelve todo:

import requests
import pandas as pd

BASE_URL = (
    "https://services1.arcgis.com/PCHfdHz4GlDNAhBb/arcgis/rest/services/"
    "CalHeatScore_Live_Data_for_API_Use/FeatureServer/0/query"
)

params = {
"where": "1=1",
"outFields": "ZIP_CODE,DATE,CHS_Day_0,CHS_Day_1,CHS_Day_2",
"returnGeometry": "false",
"f": "json"
}

response = requests.get(BASE_URL, params=params)
data = response.json()

# get dataframe
features = []

for f in data['features']:
    features.append(f['attributes'])

df = pd.DataFrame(features)

print(df)
const BASE_URL =
  "https://services1.arcgis.com/PCHfdHz4GlDNAhBb/arcgis/rest/services/" +
  "CalHeatScore_Live_Data_for_API_Use/FeatureServer/0/query";

async function fetchCalHeatScoreData() {
  const params = {
    where: "1=1",
    outFields: "ZIP_CODE,DATE,CHS_Day_0,CHS_Day_1,CHS_Day_2",
    returnGeometry: "false",
    f: "json"
  };

  const url = `${BASE_URL}?${new URLSearchParams(params)}`;
  const response = await fetch(url);
  const data = await response.json();

  // Extract attributes
  const df = data.features.map(f => f.attributes);

  console.log("CalHeatScore Data:", df);
  return df;
}

Paso 2: filtre a los usuarios por puntaje del código postal

Consulte su base de datos de usuarios registrados y sus códigos postales, luego verifique el puntaje de cada usuario contra su umbral de notificación:

# example user database
users = pd.DataFrame({
    'user_id': [1, 2, 3, 4, 5],
    'user_zipcode': ['94607', '94612', '94609', '94610', '94611']
})

print(users)

# merge with df
merged = pd.merge(
    users,
    df,
    how='left',
    left_on='user_zipcode',
    right_on='ZIP_CODE'
)

# get users who should be notified
alert_thresholds = ['3', '4']

merged_filtered = merged[merged['CHS_Day_0'].isin(alert_thresholds)]

print(merged_filtered)
// Example user database
  const users = [
    { user_id: 1, user_zipcode: "94607" },
    { user_id: 2, user_zipcode: "94612" },
    { user_id: 3, user_zipcode: "94609" },
    { user_id: 4, user_zipcode: "94610" },
    { user_id: 5, user_zipcode: "94611" }
  ];

  console.log("Users:", users);

// Merge users with CalHeatScore data
  function leftJoinUsersWithData(users, df) {
    return users.map(user => {
      const match = df.find(row => row.ZIP_CODE === user.user_zipcode);
      return {
        ...user,
        ...(match || {})
      };
    });
  }

// Filter by alert thresholds (CHS_Day_0)
  const alertThresholds = ["3", "4"];

  function filterUsersByThreshold(mergedData) {
    return mergedData.filter(row =>
      alertThresholds.includes(String(row.CHS_Day_0))
    );
  }

Paso 3: obtenga los datos en formato GeoJSON para visualizarlos en un mapa

Cuando el usuario abra la vista de mapa, obtenga los datos de CalHeatScore en formato GeoJSON para los códigos postales cercanos a su ubicación. Use outSR=4326 para coordenadas estándar de latitud/longitud:

  async function fetchGeoJSON(zipCodes) {
    const where = `ZIP_CODE IN (${zipCodes.map(z => `'${z}'`).join(",")})`;
    const params = new URLSearchParams({
      where,
      outFields:
        "ZIP_CODE,DATE,CHS_Day_0,CHS_Day_1,CHS_Day_2,CHS_Day_3,CHS_Day_4,CHS_Day_5,CHS_Day_6",
      outSR: "4326",
      f: "geojson"
    });

    const geojson = await fetch(`${BASE_URL}?${params}`).then(r => r.json());
    return geojson;
  }

Paso 4: obtenga el puntaje de un único código postal

async function fetchHeatScore(zip) {
  const params = new URLSearchParams({
    where: `ZIP_CODE='${zip}'`,
    outFields:
      "ZIP_CODE,DATE,CHS_Day_0,CHS_Day_1,CHS_Day_2,CHS_Day_3,CHS_Day_4,CHS_Day_5,CHS_Day_6",
    returnGeometry: "false",
    f: "json",
  });

  const data = await fetch(`${BASE_URL}?${params}`).then(r => r.json());
  return data.features?.[0]?.attributes || null;
}

Paso 5: ejecuta el código

(async () => {
  console.log("Fetching full CalHeatScore dataset...");
  const df = await fetchCalHeatScoreData();

  console.log("Merging user ZIPs with heat score data...");
  const merged = leftJoinUsersWithData(users, df);
  console.log("Merged Data:", merged);

  console.log("Filtering users requiring alerts...");
  const usersToNotify = filterUsersByThreshold(merged);
  console.log("Users to Notify:", usersToNotify);

  console.log("Fetching GeoJSON for those ZIP codes...");
  const zips = usersToNotify.map(u => u.user_zipcode);
  const geojson = await fetchGeoJSON(zips);
  console.log("GeoJSON:", geojson);

  console.log("Fetching individual ZIP heat score example...");
  const heatScore = await fetchHeatScore("94612");
  console.log("Heat Score for 94612:", heatScore);
})();

Resumen

  • Obtención de datos en formato JSON por el backend para las notificaciones programadas
  • Obtención de datos en formato GeoJSON por una aplicación cliente para presentarlos en un mapa
  • Consulta de un único código postal para tarjetas de resumen