The 2022 Ferndale Earthquake in Northern California#
On December 20, 2022, a magnitude 6.4 earthquake struck near the town of Ferndale in Humboldt County, along the northern coast of California. The earthquake occurred at approximately 2:34 a.m. PST and was centered offshore, about 15 kilometers southwest of Ferndale, within the seismically active southern Cascadia Subduction Zone region.
The quake originated at a depth of roughly 17 kilometers and resulted from strike-slip faulting within the Gorda Plate, a small tectonic plate that interacts with the Pacific and North American plates in this complex triple junction region. The event was widely felt throughout Northern California, including in Eureka, Arcata, and Redding, and was followed by numerous aftershocks, some of which exceeded magnitude 4.
The earthquake caused widespread power outages, damaged infrastructure, and sadly resulted in two fatalities and multiple injuries. Several homes and buildings in the region suffered structural damage, particularly in older communities with limited seismic retrofitting.
The Ferndale earthquake serves as a reminder of the persistent seismic hazard in the region, especially near the Mendocino Triple Junction, where the Pacific, North American, and Gorda plates meet. It also highlights the importance of earthquake preparedness and resilient infrastructure in vulnerable coastal communities.
Below we make a plot of this earthquake.

The pygmt code to create this image is below but note we didnt include pygmt in our list of packages for geolab so it wonβt run. Or will it?!?
pip install pygmt
Collecting pygmt
Downloading pygmt-0.15.0-py3-none-any.whl.metadata (11 kB)
Requirement already satisfied: numpy>=1.25 in /Users/amt/anaconda3/envs/pytorch/lib/python3.12/site-packages (from pygmt) (1.26.4)
Requirement already satisfied: pandas>=2.0 in /Users/amt/anaconda3/envs/pytorch/lib/python3.12/site-packages (from pygmt) (2.2.3)
Collecting xarray>=2023.04 (from pygmt)
Downloading xarray-2025.3.1-py3-none-any.whl.metadata (12 kB)
Collecting netCDF4 (from pygmt)
Downloading netCDF4-1.7.2-cp312-cp312-macosx_14_0_arm64.whl.metadata (1.8 kB)
Requirement already satisfied: packaging in /Users/amt/anaconda3/envs/pytorch/lib/python3.12/site-packages (from pygmt) (24.2)
Requirement already satisfied: python-dateutil>=2.8.2 in /Users/amt/anaconda3/envs/pytorch/lib/python3.12/site-packages (from pandas>=2.0->pygmt) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /Users/amt/anaconda3/envs/pytorch/lib/python3.12/site-packages (from pandas>=2.0->pygmt) (2024.1)
Requirement already satisfied: tzdata>=2022.7 in /Users/amt/anaconda3/envs/pytorch/lib/python3.12/site-packages (from pandas>=2.0->pygmt) (2025.2)
Collecting cftime (from netCDF4->pygmt)
Downloading cftime-1.6.4.post1-cp312-cp312-macosx_11_0_arm64.whl.metadata (8.7 kB)
Requirement already satisfied: certifi in /Users/amt/anaconda3/envs/pytorch/lib/python3.12/site-packages (from netCDF4->pygmt) (2025.1.31)
Requirement already satisfied: six>=1.5 in /Users/amt/anaconda3/envs/pytorch/lib/python3.12/site-packages (from python-dateutil>=2.8.2->pandas>=2.0->pygmt) (1.17.0)
Downloading pygmt-0.15.0-py3-none-any.whl (296 kB)
Downloading xarray-2025.3.1-py3-none-any.whl (1.3 MB)
ββββββββββββββββββββββββββββββββββββββββ 1.3/1.3 MB 20.8 MB/s eta 0:00:00
?25hDownloading netCDF4-1.7.2-cp312-cp312-macosx_14_0_arm64.whl (2.5 MB)
ββββββββββββββββββββββββββββββββββββββββ 2.5/2.5 MB 18.1 MB/s eta 0:00:00
?25hDownloading cftime-1.6.4.post1-cp312-cp312-macosx_11_0_arm64.whl (209 kB)
Installing collected packages: cftime, netCDF4, xarray, pygmt
Successfully installed cftime-1.6.4.post1 netCDF4-1.7.2 pygmt-0.15.0 xarray-2025.3.1
Note: you may need to restart the kernel to use updated packages.
import pygmt
import pandas as pd
# Load station data
df = pd.read_csv("../data/station2.txt",
delim_whitespace=True,
header=None,
usecols=[0, 1, 2],
names=["name", "lat", "lon"])
# Ferndale earthquake info (USGS event ID: nc73798970)
eq_lat = 40.52500
eq_lon = -124.42300
eq_depth = 17.910 # km
eq_mag = 6.4
# Double-couple focal mechanism (strike, dip, rake)
# Approximate for this event (strike-slip): 150, 90, 0
focal_mech = {"strike": 252, "dip": 89, "rake": 7, "magnitude": 6.4}
# Initialize map
fig = pygmt.Figure()
# Region around northern CA (adjust as needed)
region = [-124.75, -123, 39.25, 41.25]
# Base map
fig.basemap(region=region,
projection="M10i",
frame=["a", "+t2022 Ferndale Earthquake"]
)
fig.coast(shorelines="1/0.5p,black",
water="lightblue",
land="gray95",
borders="a",
resolution="f")
# Plot stations
fig.plot(x=df["lon"],
y=df["lat"],
style="t0.5c",
fill="blue",
pen="black",
label="Stations")
# Add station names
for _, row in df.iterrows():
fig.text(x=row["lon"],
y=row["lat"],
text=row["name"],
font="14p,Helvetica,black",
offset="0.3c/0.6c")
# Read earthquake
cols = ["Date","Time","Lat","Lon","Depth","Mag","Magt","Nst","Gap","Clo","RMS","SRC","Event ID"]
df = pd.read_csv("../data/ncedc.eqs", delim_whitespace=True, skiprows=13, names=cols)
pygmt.makecpt(cmap="viridis", series=[df["Depth"].min(), df["Depth"].max()])
fig.plot(x=df["Lon"],
y=df["Lat"],
style="c0.2c",
fill=df["Depth"],
cmap=True)
fig.colorbar(frame="xaf+lDepth (km)")
# Plot earthquake location
fig.plot(x=[eq_lon],
y=[eq_lat],
style="a1.0c",
fill="red",
pen="black",
label="Event")
# Plot focal mechanism
fig.meca(spec=focal_mech,
scale="2c",
longitude=eq_lon,
latitude=eq_lat,
depth=0,
plot_longitude=eq_lon+0.1,
plot_latitude=eq_lat-0.20,
offset="+p1p,darkblue+s0.25c",
compressionfill="lightorange")
# Plot Faults
fig.plot(data="../data/gem_active_faults.gmt",
pen="1p,darkred",
label="Faults")
# Add legend
pygmt.config(FONT_ANNOT_PRIMARY="25p,Helvetica,black")
fig.legend(position="JTR+o-6c", box=True)
# Show figure
fig.show()
fig.savefig(fname="ferndale_earthquake.png")
---------------------------------------------------------------------------
GMTCLibNotFoundError Traceback (most recent call last)
Cell In[3], line 1
----> 1 import pygmt
2 import pandas as pd
4 # Load station data
File ~/anaconda3/envs/pytorch/lib/python3.12/site-packages/pygmt/__init__.py:24
21 import atexit as _atexit
23 # Import modules to make the high-level GMT Python API
---> 24 from pygmt import datasets
25 from pygmt._show_versions import __commit__, __version__, show_versions
26 from pygmt.accessors import GMTDataArrayAccessor
File ~/anaconda3/envs/pytorch/lib/python3.12/site-packages/pygmt/datasets/__init__.py:7
1 """
2 Functions to load GMT remote data and sample data.
3
4 Data are downloaded from the GMT data server.
5 """
----> 7 from pygmt.datasets.earth_age import load_earth_age
8 from pygmt.datasets.earth_day import load_blue_marble
9 from pygmt.datasets.earth_deflection import load_earth_deflection
File ~/anaconda3/envs/pytorch/lib/python3.12/site-packages/pygmt/datasets/earth_age.py:12
9 from typing import Literal
11 import xarray as xr
---> 12 from pygmt.datasets.load_remote_dataset import _load_remote_dataset
14 __doctest_skip__ = ["load_earth_age"]
17 def load_earth_age(
18 resolution: Literal[
19 "01d", "30m", "20m", "15m", "10m", "06m", "05m", "04m", "03m", "02m", "01m"
(...) 22 registration: Literal["gridline", "pixel"] = "gridline",
23 ) -> xr.DataArray:
File ~/anaconda3/envs/pytorch/lib/python3.12/site-packages/pygmt/datasets/load_remote_dataset.py:10
7 from typing import Any, Literal, NamedTuple
9 import xarray as xr
---> 10 from pygmt.clib import Session
11 from pygmt.exceptions import GMTInvalidInput
12 from pygmt.helpers import build_arg_list, kwargs_to_strings
File ~/anaconda3/envs/pytorch/lib/python3.12/site-packages/pygmt/clib/__init__.py:9
1 """
2 Low-level wrapper for the GMT C API.
3
4 The pygmt.clib.Session class wraps the GMT C shared library (libgmt) with a Pythonic
5 interface. Access to the C library is done through ctypes.
6 """
8 from packaging.version import Version
----> 9 from pygmt.clib.session import Session, __gmt_version__
10 from pygmt.exceptions import GMTVersionError
12 required_gmt_version = "6.4.0"
File ~/anaconda3/envs/pytorch/lib/python3.12/site-packages/pygmt/clib/session.py:110
107 GMT_CONSTANTS = {}
109 # Load the GMT library outside the Session class to avoid repeated loading.
--> 110 _libgmt = load_libgmt()
111 __gmt_version__ = get_gmt_version(_libgmt)
114 class Session:
File ~/anaconda3/envs/pytorch/lib/python3.12/site-packages/pygmt/clib/loading.py:62, in load_libgmt(lib_fullnames)
59 failing_libs.append(libname)
61 if error:
---> 62 raise GMTCLibNotFoundError("\n".join(error_msg))
64 return libgmt
GMTCLibNotFoundError: Error loading GMT shared library at 'libgmt.dylib'.
dlopen(libgmt.dylib, 0x0006): tried: 'libgmt.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OSlibgmt.dylib' (no such file), '/Users/amt/anaconda3/envs/pytorch/lib/python3.12/lib-dynload/../../libgmt.dylib' (no such file), '/Users/amt/anaconda3/envs/pytorch/bin/../lib/libgmt.dylib' (no such file), '/usr/lib/libgmt.dylib' (no such file, not in dyld cache), 'libgmt.dylib' (no such file), '/usr/local/lib/libgmt.dylib' (no such file), '/usr/lib/libgmt.dylib' (no such file, not in dyld cache)