GEOS Xray Plot Setup
- /
- Webmaster Notebook/
- GEOS XRay Plot Setup/
- GEOS Xray Plot Setup
UKSMG Desktop – GOES X-Ray Daily Plot
The UKSMG Desktop page displays a GEOS/GOES X-Ray Daily plot in one of its iframe windows. The original data source is: https://www.swpc.noaa.gov/products/goes-x-ray-flux .
In 2025, NOAA stopped providing static images for X-ray data, which caused the original UKSMG Desktop display to break. To resolve this, a Python script was created to retrieve raw NOAA data and regenerate the plot dynamically.
System Setup
Run the following commands as root:
<code>mkdir ~/goes-project cd ~/goes-project</code>
Update package lists
<code>sudo apt update</code>
Install Python and dependencies
<code>sudo apt install -y python3-pip python3-venv python3-dev</code>
Verify pip installation
<code>pip3 --version</code>
Expected output:
<code>pip 23.x from /usr/lib/python3/dist-packages/pip (python 3.x)</code>
Create a virtual environment
<code>mkdir -p ~/venvs python3 -m venv ~/venvs/goes source ~/venvs/goes/bin/activate</code>
Your prompt should change to:
<code>(goes) user@server:~$</code>
Install Python packages
<code>pip install --upgrade pip pip install pandas matplotlib requests</code>
Verify installation
<code>python -c "import pandas, matplotlib, requests; print('OK')"</code>
Expected output:
<code>OK</code>
Python Script
Create the following script:
<code>#!/usr/bin/env python3
import requests
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime, UTC
URL = "https://services.swpc.noaa.gov/json/goes/primary/xrays-1-day.json"
OUTPUT = "/var/www/vhosts/uksmg.org.uk/httpdocs/images/goes_xray_daily.png"
# -----------------------
# Load data
# -----------------------
data = requests.get(URL, timeout=30).json()
df = pd.DataFrame(data)
df = df[df["energy"] == "0.1-0.8nm"].copy()
df["time_tag"] = pd.to_datetime(df["time_tag"])
df["flux"] = pd.to_numeric(df["flux"], errors="coerce")
df = df.dropna()
# -----------------------
# NOAA-style figure
# -----------------------
fig, ax = plt.subplots(figsize=(12, 5), facecolor="white")
ax.set_facecolor("white")
ax.semilogy(
df["time_tag"],
df["flux"],
color="#1f4e79",
linewidth=1.2
)
ax.set_title(
"GOES X-ray Flux (0.1–0.8 nm)",
fontsize=13,
fontweight="bold"
)
ax.set_xlabel("Time (UTC)", fontsize=10)
ax.set_ylabel("Watts m⁻²", fontsize=10)
ax.set_ylim(1e-9, 1e-2)
ax.grid(True, which="both", linestyle="-", linewidth=0.3, alpha=0.25)
ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
plt.xticks(rotation=0)
# Flare thresholds
flare_levels = [
(1e-7, "A"),
(1e-6, "B"),
(1e-5, "C"),
(1e-4, "M"),
(1e-3, "X"),
]
xpos = df["time_tag"].max()
for level, label in flare_levels:
ax.axhline(level, color="grey", linestyle="--", linewidth=0.6, alpha=0.4)
ax.text(
xpos,
level,
f" {label}",
va="center",
ha="left",
fontsize=9,
color="black"
)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
updated = datetime.now(UTC).strftime("%Y-%m-%d %H:%M UTC")
plt.figtext(
0.99,
0.01,
f"Updated: {updated}",
ha="right",
fontsize=8,
color="black"
)
plt.tight_layout()
plt.savefig(
OUTPUT,
dpi=150,
bbox_inches="tight",
facecolor="white"
)
plt.close()
print("Saved:", OUTPUT)
</code>
Run the Script
~/venvs/goes/bin/python /var/www/vhosts/uksmg.org/httpdocs/scripts/goes_xray_plot.py
CRON Job
Enter the following command as a cron job to run every 5 minutes:
/var/www/vhosts/uksmg.org/venvs/goes/bin/python /var/www/vhosts/uksmg.org.uk/httpdocs/scripts/goes_xray_plot.py >> /var/www/vhosts/uksmg.org.uk/goes_xray.log 2>&1

