Metadata-Version: 2.4
Name: quakeion
Version: 0.1.1
Summary: Earthquake catalogs + ionospheric TEC/ROT/ROTI analysis with Kp & Dst storm filtering, zero API keys.
Author-email: Ghulam_Muhammad <gm.angra015@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/Gm015555/quakeion
Project-URL: Issues, https://github.com/Gm015555/quakeion/issues
Keywords: earthquake,ionosphere,TEC,GNSS,IONEX,space-weather,remote-sensing,GIS,seismology
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
Classifier: Topic :: Scientific/Engineering :: GIS
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28
Requires-Dist: numpy>=1.23
Requires-Dist: pandas>=1.5
Requires-Dist: matplotlib>=3.6
Requires-Dist: unlzw3>=0.2
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Provides-Extra: maps
Requires-Dist: cartopy>=0.22; extra == "maps"
Dynamic: license-file

# quakeion

**Earthquake catalogs + ionospheric TEC analysis with zero API keys and zero accounts.**

`quakeion` automates a workflow that researchers in seismo-ionospheric studies normally do by hand: find an earthquake, download Global Ionosphere Maps (GIM), extract Total Electron Content (TEC) over the epicenter, detect statistical anomalies, and plot the result.

**Simplest possible use — name an earthquake, get every figure:**

```python
import quakeion as qi

qi.report("Venezuela 2026")     # ROT + ROTI panels + spatial maps, all saved
qi.report("pakistan", year=2005)
qi.report("japan")              # newest significant quake in Japan
```

Or drive each step yourself:

```python
import quakeion as qi

# 1. Find earthquakes automatically (USGS, no key)
eq = qi.earthquakes(region="pakistan", min_mag=5.5, days=365)

# 2. Fetch TEC over the epicenter, ±15 days around the event
tec = qi.tec(eq.iloc[0], window_days=15)

# 3. Detect TEC anomalies (sliding median ± 1.5·IQR, same-UT-hour baseline)
result = qi.detect_anomalies(tec)

# 4. Publication-ready plot
qi.plot(result, save="tec_anomalies.png")
```

## Install

```
pip install quakeion
pip install quakeion[maps]   # optional: adds cartopy coastlines on spatial maps
```

## Data sources (all open, no registration)

| Data | Source | Coverage |
|---|---|---|
| Earthquake catalog | USGS FDSN event service | global, real-time |
| TEC (Global Ionosphere Maps) | CODE, University of Bern open archive | global, 1995 → ~today |

Downloaded GIM files are cached in `~/.quakeion/cache` so re-runs are instant.

## API

### `qi.report(query, year=None, min_mag=6.0, outdir=".")`
The one-call entry point. Parses a place (and optional year), picks the strongest matching earthquake, and writes four figures: ROT panels, ROTI panels, spatial ROTI map on the event day, and the same map for the previous day as a baseline. Prints the event, the stations chosen, and any geomagnetic storm days found.

### `qi.earthquakes(region, min_mag, days, start, end, lat, lon, radius_km, limit)`
Returns a `pandas.DataFrame` with `time, latitude, longitude, depth_km, magnitude, place, id`.
`region` can be a named region (`"pakistan"`, `"japan"`, `"turkey"`, … see `qi.REGIONS`), a bounding box `(min_lat, max_lat, min_lon, max_lon)`, or use `lat`/`lon`/`radius_km` for a circular search.

### `qi.tec(event, window_days=15, step_minutes=60)`
`event` is a row from `earthquakes()` (e.g. `eq.iloc[0]`), a dict, or simply `(lat, lon, "2024-06-01")`. Downloads the daily GIMs, interpolates TEC (bilinear in space, linear in time) at the epicenter, and returns a time-indexed DataFrame in TECU. Event metadata is kept in `df.attrs`.

### `qi.detect_anomalies(tec_df, baseline_days=15, k=1.5)`
Implements the interquartile-bound method common in the seismo-ionospheric literature: for each epoch, the median and IQR of TEC at the **same UT hour** over the previous `baseline_days` define an expected band `median ± k·IQR`; values outside are flagged. Adds `median, upper, lower, delta, anomaly` columns.

### `qi.plot(df, title=None, save=None)`
TEC series, expected band, flagged anomalies, and the earthquake time marked.

### Spatial ROTI map

```python
qi.roti_map(event)                                  # global, event day
qi.roti_map(event, extent=(40, 110, 5, 55))         # regional zoom
qi.roti_map(event, day="2005-10-07")                # baseline day
```
ROTI computed per GIM grid cell (std of the cell's rate of TEC over the
day), epicenter starred, nearest stations marked. Coastlines appear
automatically if cartopy is installed.

### ROT exceedance workflow — every raw epoch, NO averaging

```python
tec = qi.tec((4.6, -74.1, "2026-06-24"), window_days=15)  # e.g. over BOGT
r   = qi.rot(tec)               # Rate Of TEC, TECU/min, raw epochs
ex  = qi.exceedance(r)          # per-day sigma bounds, sigma_class 0/1/2
qi.plot_exceedance(
    [ex_bogt, ex_cro1, ex_scub],                 # one panel per station
    events=[("2026-06-24 22:04:33", "Mw 7.2"),
            ("2026-06-24 22:05:11", "Mw 7.5")],
    labels=["BOGT | 660 km", "CRO1 | 870 km", "SCUB | 1250 km"],
    save="exceedance.png",
)
```

- `qi.rot(tec_df)` — ROT = ΔTEC/Δt (TECU/min) at every raw epoch; nothing is smoothed or averaged.
- `qi.exceedance(rot_df, k1=1, k2=2)` — per-UTC-day mean and sigma from that day's raw epochs only; each epoch classified as within ±1σ (0), 1–2σ (1, orange), beyond ±2σ (2, red). Counts stored in `attrs`.
- `qi.plot_exceedance(panels, events, labels, storms=...)` — multi-panel figure: colored ROT bars, dashed per-day sigma bounds, vertical foreshock/mainshock lines, boxed station labels, PRE-/POST-SEISMIC phase labels, grey shading for geomagnetic storm days.
- `qi.analyze(region="asia", min_mag=6)` — the one-liner: newest matching quake -> nearest stations -> TEC -> ROT -> exceedance figure, with automatic Kp storm-day shading (`check_storms=False` to disable).
- `qi.kp(start, end)` / `qi.storm_days(kp_df)` — planetary Kp index (GFZ Potsdam, NOAA fallback) and Kp>=5 storm-day detection.
- `qi.dst(start, end)` / `qi.dst_storm_days(dst_df, threshold=-50)` — hourly Dst ring-current index (WDC Kyoto, no account); Dst <= -50 nT marks a moderate storm.
- `qi.analyze(..., storm_index="both")` — default: a day is excluded if **either** Kp>=5 or Dst<=-50 nT flags it. Use `"kp"` or `"dst"` to pick one. So ionospheric anomalies on magnetically disturbed days are not over-interpreted as seismic precursors.

## Notes & caveats

- GIM-based TEC has ~2.5° × 5° spatial and 1–2 h temporal resolution — good for regional anomaly studies, not for small-scale structure. True ROTI from 30-second RINEX data is planned for a future version.
- Ionospheric anomalies also come from geomagnetic storms; serious studies should cross-check Kp/Dst indices before attributing anomalies to seismic activity.
- Very recent days may not have a published GIM yet.

## Roadmap

- [ ] `qi.roti()` — ROTI from raw RINEX (GNSS stations near the epicenter)
- [x] Geomagnetic index (Kp + Dst) fetchers + storm-day shading
- [ ] `qi.flights()` — aircraft trajectory data via OpenSky
- [x] Spatial ROTI map (global/regional, epicenter + stations marked)

## Development

```
git clone https://github.com/Gm015555/quakeion
cd quakeion
pip install -e ".[dev]"
pytest
```

## License

MIT
