| name | find-earthquake-farthest-from-pacific-boundary |
| description | Find the earthquake within the Pacific plate (Code == "PA") that is farthest from the Pacific plate boundary lines in PB2002_boundaries.json. Uses an equal-area projection for accurate distance measurement. Filters boundaries where PlateA or PlateB equals "PA". |
Strategy
- Load plate polygons, filter for Pacific plate using
Code == "PA".
- Load boundaries, filter where
PlateA == "PA" or PlateB == "PA".
- Filter earthquakes that fall within the Pacific plate polygon.
- Project everything to an equal-area CRS.
- Compute distance from each earthquake point to the unary_union of Pacific boundaries.
- Find the maximum distance and output the result.
Full Implementation
import geopandas as gpd
import json
import pandas as pd
import numpy as np
from shapely.geometry import Point
import warnings
warnings.filterwarnings("ignore")
plates = gpd.read_file("/root/PB2002_plates.json")
print("Plates columns:", list(plates.columns))
print(plates.head(3).to_string())
boundaries = gpd.read_file("/root/PB2002_boundaries.json")
print("\nBoundaries columns:", list(boundaries.columns))
print(boundaries.head(3).to_string())
plate_code_field = None
for candidate in ["Code", "code", "PlateName", "PLATENAME", "plate", "Plate"]:
if candidate in plates.columns:
plate_code_field = candidate
break
if plate_code_field is None:
print("Available plate columns:", plates.columns.tolist())
raise ValueError("Cannot find plate code column")
print(f"\nUsing plate code field: '{plate_code_field}'")
print("Unique plate codes sample:", plates[plate_code_field].unique()[:20])
pacific_plate = plates[plates[plate_code_field] == "PA"].copy()
print(f"\nPacific plate rows: {len(pacific_plate)}")
print(pacific_plate[[plate_code_field, "geometry"]].to_string())
if len(pacific_plate) == 0:
raise ValueError("No Pacific plate polygon found with Code == 'PA'")
pacific_polygon = pacific_plate.geometry.unary_union
print("\nBoundaries columns:", boundaries.columns.tolist())
print(boundaries.head(5).to_string())
plate_a_col = None
plate_b_col = None
for col in boundaries.columns:
cl = col.lower()
if "platea" in cl or cl == "plate_a":
plate_a_col = col
if "plateb" in cl or cl == "plate_b":
plate_b_col = col
if plate_a_col is None:
print("Looking for plate identifier columns in boundaries...")
for col in boundaries.columns:
sample = boundaries[col].dropna().head(10).tolist()
print(f" {col}: {sample}")
print(f"PlateA col: {plate_a_col}, PlateB col: {plate_b_col}")
if plate_a_col and plate_b_col:
pa_boundaries = boundaries[
(boundaries[plate_a_col] == "PA") | (boundaries[plate_b_col] == "PA")
].copy()
else:
mask = pd.Series([False] * len(boundaries))
for col in boundaries.columns:
if boundaries[col].dtype == object:
mask = mask | boundaries[col].eq("PA")
pa_boundaries = boundaries[mask].copy()
print(f"\nPacific boundaries count: {len(pa_boundaries)}")
if len(pa_boundaries) == 0:
raise ValueError("No Pacific plate boundaries found")
with open("/root/earthquakes_2024.json") as f:
eq_data = json.load(f)
rows = []
for feat in eq_data["features"]:
props = feat["properties"]
coords = feat["geometry"]["coordinates"]
rows.append({
"id": feat["id"],
"place": props.get("place"),
"time_ms": props.get("time"),
"magnitude": props.get("mag"),
"longitude": coords[0],
"latitude": coords[1],
"geometry": Point(coords[0], coords[1])
})
eq_gdf = gpd.GeoDataFrame(rows, geometry="geometry", crs="EPSG:4326")
eq_gdf["time"] = pd.to_datetime(eq_gdf["time_ms"], unit="ms", utc=True).dt.strftime("%Y-%m-%dT%H:%M:%SZ")
print(f"\nTotal earthquakes: {len(eq_gdf)}")
pacific_plate_4326 = pacific_plate.set_crs("EPSG:4326", allow_override=True) if pacific_plate.crs is None else pacific_plate.to_crs("EPSG:4326")
eq_in_pacific = gpd.sjoin(
eq_gdf,
pacific_plate_4326[["geometry"]],
how="inner",
predicate="within"
)
print(f"Earthquakes within Pacific plate (sjoin): {len(eq_in_pacific)}")
if len(eq_in_pacific) == 0:
print("WARNING: 'within' returned 0 — trying manual contains check")
mask = eq_gdf.geometry.apply(lambda pt: pacific_polygon.contains(pt))
eq_in_pacific = eq_gdf[mask].copy()
print(f"Earthquakes within Pacific plate (manual): {len(eq_in_pacific)}")
if len(eq_in_pacific) == 0:
raise ValueError("No earthquakes found within Pacific plate polygon")
if "index_right" in eq_in_pacific.columns:
eq_in_pacific = eq_in_pacific.drop(columns=["index_right"])
TARGET_CRS = "EPSG:3832"
pacific_center_lon = 180.0
pacific_center_lat = 0.0
PROJ_STRING = f"+proj=laea +lat_0={pacific_center_lat} +lon_0={pacific_center_lon} +datum=WGS84 +units=m +no_defs"
eq_proj = eq_in_pacific.to_crs(PROJ_STRING)
pa_boundaries_proj = pa_boundaries.to_crs(PROJ_STRING)
boundary_union = pa_boundaries_proj.geometry.unary_union
print(f"Boundary union type: {boundary_union.geom_type}")
distances = eq_proj.geometry.distance(boundary_union)
eq_proj = eq_proj.copy()
eq_proj["distance_m"] = distances
eq_proj["distance_km"] = distances / 1000.0
print(f"\nDistance stats:")
print(f" Min: {eq_proj['distance_km'].min():.2f} km")
print(f" Max: {eq_proj['distance_km'].max():.2f} km")
print(f" Mean: {eq_proj['distance_km'].mean():.2f} km")
idx_max = eq_proj["distance_km"].idxmax()
farthest = eq_proj.loc[idx_max]
print(f"\nFarthest earthquake from Pacific boundary:")
print(f" ID: {farthest['id']}")
print(f" Place: {farthest['place']}")
print(f" Time: {farthest['time']}")
print(f" Magnitude: {farthest['magnitude']}")
print(f" Lat/Lon: {farthest['latitude']}, {farthest['longitude']}")
print(f" Distance: {farthest['distance_km']:.2f} km")
result = {
"id": farthest["id"],
"place": farthest["place"],
"time": farthest["time"],
"magnitude": float(farthest["magnitude"]),
"latitude": float(farthest["latitude"]),
"longitude": float(farthest["longitude"]),
"distance_km": round(float(farthest["distance_km"]), 2)
}
with open("/root/answer.json", "w") as f:
json.dump(result, f, indent=2)
print("\nResult written to /root/answer.json")
print(json.dumps(result, indent=2))
Key Implementation Notes
- Always use
PB2002_boundaries.json filtered for PA, never the plate polygon's .boundary.
- Plate code is
"PA" — filter plates with Code == "PA" (inspect actual column name first).
- Boundary columns are typically
PlateA/PlateB — filter (PlateA == "PA") | (PlateB == "PA").
- Pacific-centered projection (LAEA at lon_0=180) avoids antimeridian distortion.
- Use
sjoin with predicate="within" for point-in-polygon; fall back to manual .contains() if needed.
- Distance is in meters from
.distance() — divide by 1000 for km.