Live Demo: NEXRAD Mapbox on Netlify
NOTE: Current demo displays data from March 21, 2025 for the KPDT site only. Real-time data functionality is available, but turned off for the moment due to cost.
Frontend Repository: NEXRAD Mapbox frontend repository
This repository contains the backend services for the NEXRAD Mapbox Viewer. It consists of two main parts:
- Data Processing Scripts: Python scripts that fetch raw NEXRAD Level 2 and Level 3 data from public AWS S3 buckets (NOAA and Unidata), process them using Py-ART and Matplotlib to generate PNG image overlays and JSON metadata, and upload these processed files to a dedicated project S3 bucket.
- Flask API: A Python Flask web server that serves the processed data (images, metadata, file lists) from the project S3 bucket to the frontend application via a REST API.
The backend utilizes a standard Python src
layout for organization:
src/nexrad_backend/
: The main Python package containing all core logic.api/
: Handles the Flask web application setup (app_factory.py
) and defines the HTTP API endpoints/routes (routes.py
) using a Flask Blueprint.services/
: Contains modules that interact with external systems or manage specific data domains:s3_service.py
: Low-level functions for all interactions with AWS S3 (get, put, list, delete, check existence). Handles both project and public bucket clients.nexrad_fetcher.py
: Functions responsible for finding and downloading raw NEXRAD data (Level 2 from NOAA, Level 3 from Unidata) from their public S3 buckets.metadata_service.py
: Functions for managing the application's metadata stored in the project's S3 bucket (JSON file lists, product code options, update flags).
processing/
: Contains the core scientific data processing logic:common.py
: Shared helper functions used by different processing steps (e.g., bounding box calculation, saving plots to buffer, file cleanup).level2.py
: Logic specific to reading Level 2 files, processing each radar sweep (tilt), generating plots/metadata using Py-ART/Matplotlib, and preparing results for S3 upload.level3.py
: Logic specific to reading Level 3 files, normalizing filenames, generating plots/metadata, and preparing results for S3 upload.
utils/
: General utility functions (e.g.,list_helpers.py
).config.py
: Centralized configuration loading from environment variables (.env
) and definition of constants (bucket names, paths, sites, etc.).
scripts/
: Contains standalone Python scripts that act as entry points for the data processing workflows. These scripts import and orchestrate calls to functions within thenexrad_backend
services and processing modules.process_level2.py
: Runs the complete workflow for fetching, processing, and updating Level 2 data.process_level3.py
: Runs the complete workflow for fetching, processing, and updating Level 3 data.
server.py
: The main entry point at the project root for starting the Flask API server using Waitress. It uses the app factory fromnexrad_backend.api.app_factory
.pyproject.toml
: Defines project metadata, dependencies, and build system configuration, enabling standard Python packaging and installation workflows.
Data Processing Flow (Triggered Periodically):
+-------------------------------+
| Public S3 (NOAA L2/Unidata L3)| Raw Data Source
+-------------┬-----------------+
│ Finds/Downloads
│ [nexrad_fetcher service]
▼
+-------------------------------+
| scripts/*.py | Orchestration (Scheduled)
| (Downloads to Local Temp) |
+-------------┬-----------------+
│ Processes Files
│ [processing.L2/L3 modules] using PyArt/Matplotlib
▼
+-------------------------------+
| s3_service | Uploads Processed Data & Metadata
| (Handles S3 Put/Delete) | (Also called by metadata_service)
+-------------┬-----------------+
│ Stores Processed Files & Updates Metadata Files
▼
+-------------------------------+
| Project S3 (nexrad-mapbox) | Central Storage
| - plots_level*/ (PNG/JSON) |
| - lists/*.json |
| - codes/options.json |
| - flags/update_flags.json |
+-------------------------------+
API Serving Flow (Handles Frontend Requests):
+-----------------------------+
| Project S3 (nexrad-mapbox) | Central Storage
+-------------┬---------------+
│ Reads Data & Metadata Files
│ (via metadata_service & s3_service)
▼
+-----------------------------+
| Flask API (server.py) | Serves Data via HTTP Endpoints
+-------------┬---------------+
│ HTTP Requests / JSON & PNG Responses
▼
+-----------------------------+
| Frontend (SolidJS App) | Consumes API
+-----------------------------+
Explanation of Flow:
- Processing: The
scripts/process_level*.py
files are run on a schedule. They use thenexrad_fetcher
service to find and download recent raw data from public S3 buckets to temporary local storage. These scripts then use theprocessing
modules (which utilize Py-ART/Matplotlib) to generate PNG plots and JSON metadata. Thes3_service
is used to upload these processed files to your project's S3 bucket. Themetadata_service
(also usings3_service
) updates the JSON file lists, code counts, and update flags within the project S3 bucket. Finally,s3_service
cleans up old processed files from your bucket. - Serving: The
Flask API
(running viaserver.py
) receives HTTP requests from the Frontend. It uses themetadata_service
to get file lists/codes/flags (which reads JSON files from the Project S3 vias3_service
) and uses thes3_service
directly to retrieve specific plot (PNG) or metadata (JSON) files requested by the frontend, sending them back as HTTP responses.
- Automated NEXRAD Data Processing:
- Fetches Level 2 (Reflectivity) and Level 3 (Hydrometeor, Precipitation) data.
- Uses
Py-ART
for scientific radar data interpretation. - Generates transparent PNG plot overlays using
Matplotlib
. - Calculates and saves geographic bounding box JSON metadata for each plot.
- Handles multi-sweep Level 2 data, generating plots/JSON per tilt angle.
- Utilizes
asyncio
andProcessPoolExecutor
for concurrent downloading and processing.
- REST API for Frontend:
- Serves processed PNG images and JSON metadata.
- Provides lists of available files for different products/levels.
- Provides lists of available Level 3 product codes and their file counts.
- Handles CORS for frontend integration.
- AWS S3 Integration:
- Leverages public S3 buckets for raw data input.
- Uses a dedicated S3 bucket for storing processed output (plots, JSON, lists).
- Includes utility for cleaning up old files from the S3 bucket.
- Configuration: Uses environment variables for AWS credentials and other settings.
- Modular Structure: Code is organized into services, processing modules, and API components for better maintainability and testability using a standard
src
layout.
- Language: Python (3.9+ recommended)
- API Framework: Flask
- WSGI Server: Waitress
- AWS SDK: Boto3
- Scientific Computing: Py-ART, NumPy
- Plotting: Matplotlib
- Asynchronous Programming: asyncio, concurrent.futures
- Environment Management: python-dotenv
- Cloud Storage: AWS S3
- Timezone Handling: pytz
- Packaging: Setuptools (via
pyproject.toml
)
Method | Path | Description | Success Response | Error Responses |
---|---|---|---|---|
GET |
/code/ |
Retrieves the codes/options.json file containing Level 3 product code options and counts. |
200 (JSON Body) | 404, 500 |
GET |
/flag/ |
Retrieves the flags/update_flags.json file. |
200 (JSON Body) | 404, 500 |
POST |
/flag/ |
Updates the flags/update_flags.json file with the provided JSON body. |
200 (JSON Body) | 400, 500 |
GET |
/list/<level>/<product>/ |
Retrieves the JSON file list for a specific level and product (e.g., /list/2/reflectivity/ ). |
200 (JSON Body) | 400, 404, 500 |
GET |
/list-all/ |
Retrieves and combines JSON file lists for all primary products (reflectivity, hydrometeor, precipitation). | 200 (JSON Body) | 500 |
GET |
/data/<level>/<path:file_key>/<ext> |
Retrieves a specific data file (e.g., /data/2/..._idx0/png ). ext is png or json . |
200 (PNG/JSON) | 400, 404, 500 |
OPTIONS |
/* |
Handles CORS preflight requests (managed automatically by Flask-CORS). | 200 | - |
The data processing logic is initiated via scripts in the /scripts
directory:
scripts/process_level2.py
: Orchestrates the workflow for Level 2 data:- Finds recent raw files on the public NOAA S3 bucket using the
nexrad_fetcher
service. - Filters out files already processed based on lists managed by the
metadata_service
. - Downloads new files concurrently using
nexrad_fetcher
. - Processes downloaded files concurrently using the
processing.level2
module, which generates/uploads individual sweep plots (PNG) and metadata (JSON) to the project S3 via thes3_service
. - Updates the Level 2 file list and processing flag in the project S3 via
metadata_service
. - Cleans up old processed L2 files from the project S3 via
s3_service
.
- Finds recent raw files on the public NOAA S3 bucket using the
scripts/process_level3.py
: Orchestrates the workflow for Level 3 data (per product type like 'hydrometeor', 'precipitation'):- Fetches product code configuration using
metadata_service
. - Finds recent raw files on the public Unidata S3 bucket for relevant codes using
nexrad_fetcher
. - Filters out files already processed (using normalized keys).
- Downloads new files concurrently.
- Processes downloaded files concurrently using the
processing.level3
module, which generates/uploads plots (PNG) and metadata (JSON) to the project S3. - Updates the Level 3 file list, product code counts (
options.json
), and processing flag for the specific product type viametadata_service
. - Cleans up old processed L3 files from the project S3 via
s3_service
.
- Fetches product code configuration using
These scripts are designed to be run periodically (e.g., every 5-15 minutes) using a scheduler like cron
or a cloud scheduling service to keep the data served by the API up-to-date.
-
Clone the repository:
git clone [https://github.com/your-username/nexrad-mapbox-backend.git](https://github.com/your-username/nexrad-mapbox-backend.git) cd nexrad-mapbox-backend
-
Create a Python Virtual Environment: (Python 3.9+ recommended)
# Using venv python -m venv venv source venv/bin/activate # Linux/macOS # or Venv\Scripts\activate # Windows (cmd) # or Venv\Scripts\Activate.ps1 # Windows (PowerShell) # OR Using Conda (Recommended for easier handling of pygrib/eccodes on Windows) # conda create --name nexrad_env python=3.9 # conda activate nexrad_env # conda install -c conda-forge eccodes pygrib pyart-mch matplotlib numpy pytz # Install key deps via conda
-
Install Dependencies: The project uses
pyproject.toml
. Install the package itself in editable mode along with development dependencies (like Ruff linter/formatter):# Make sure you are in the project root (nexrad-mapbox-backend/) # Ensure pip is up-to-date: python -m pip install --upgrade pip # If using Venv: pip install -e .[dev] # If using Conda (after conda install step above): # Install remaining deps (Flask, Boto3, etc.) AND the local package pip install flask flask-cors boto3 python-dotenv waitress # Add any others not installed via conda pip install -e .[dev] # Installs local package and dev tools from pyproject.toml
(The
-e
flag installs yournexrad_backend
package in editable mode, linking to yoursrc
directory. The[dev]
installs optional dependencies listed underproject.optional-dependencies.dev
inpyproject.toml
). -
Set up Environment Variables:
- Create a
.env
file in the project root (nexrad-mapbox-backend/.env
). - Add your AWS credentials and desired region. Ensure these credentials have S3 read/write/delete permissions for your target bucket (
PROJECT_S3_BUCKET
defined in config, defaults tonexrad-mapbox
).# nexrad-mapbox-backend/.env AWS_ACCESS_KEY_ID=YOUR_AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY AWS_REGION=us-west-1 # Or your preferred region # Optional: Override defaults from config.py if needed # PROJECT_S3_BUCKET=my-custom-bucket-name # RADAR_SITE_L2=KSEA # RADAR_SITE_L3=SEA # PROCESSING_WINDOW_MINUTES=120 # API_PORT=5000
- Security: Add
.env
to your.gitignore
file to avoid committing credentials.
- Create a
-
AWS S3 Bucket Setup:
- Ensure the target S3 bucket (e.g.,
nexrad-mapbox
) exists in your specified AWS region. - The processing scripts create necessary prefixes (
plots_level2/
,lists/
, etc.) if they don't exist.
- Ensure the target S3 bucket (e.g.,
-
Run the API Server:
- Activate your virtual environment (
source venv/bin/activate
orconda activate nexrad_env
). - Run from the project root:
python server.py
- The API will be available at
http://<API_HOST>:<API_PORT>
(defaults tohttp://0.0.0.0:4000
). Access viahttp://localhost:4000
orhttp://127.0.0.1:4000
from your local machine.
- Activate your virtual environment (
-
Run the Data Processing Scripts:
- Activate your virtual environment.
- Run manually from the project root:
python scripts/process_level2.py python scripts/process_level3.py
- Note: These scripts should ideally be run periodically via a scheduler (
cron
, Task Scheduler, cloud service) rather than manually long-term.
- API Server: The API (
server.py
using Waitress) can be deployed to various PaaS/server environments (Render, Heroku, AWS EC2/ECS, etc.).- Ensure the deployment environment has Python and access to the necessary environment variables (AWS credentials, etc.).
- The build process should install dependencies via
pip install .
(readingpyproject.toml
) orpip install -r requirements.txt
(if generated frompyproject.toml
for pinning). - Render.com Start Command Example:
python server.py
- Processing Scripts: The scripts (
scripts/process_level*.py
) need to be executed on a schedule. Suitable options include:cron
jobs on a Linux server.- Scheduled Tasks on Windows Server.
- Cloud-based schedulers triggering container tasks or serverless functions (e.g., AWS EventBridge Scheduler + Lambda/Fargate, Google Cloud Scheduler + Cloud Run/Functions, Render Cron Jobs).
This project is licensed under the MIT License - see the LICENSE file for details.