Is Earth warming from the Sun, or from us?
Measure the Sun's actual energy output (Heliophysics) and set it against Earth's outgoing energy (Earth). The gap, and how it tracks the solar cycle, separates Sun-driven change from human-driven warming.
Earth has an energy budget, like a bank account. Sunlight comes in, heat radiates back out to space, and when more comes in than goes out, the planet stores the difference as warming. To answer the question you measure both sides on their own. Find out how much the Sun is putting out and how much energy Earth is keeping, then see whether the gap follows the Sun's natural rhythm or grows on its own.
Is Earth warming from the Sun, or from us?
Earth has an energy budget, like a bank account. Sunlight comes in, heat radiates back out to space, and when more comes in than goes out, the planet stores the difference as warming. To answer the question you measure both sides on their own. Find out how much the Sun is putting out and how much energy Earth is keeping, then see whether the gap follows the Sun’s natural rhythm or grows on its own.
Which data to use, and how
Use this dataset: CERES EBAF (short name CERES_EBAF). CERES is a set of NASA instruments that measure, from orbit, how much energy Earth radiates and reflects back to space. That’s the “out” side of the budget. EBAF is the cleaned-up, balanced monthly product, so it’s the easiest version to start with.
The “in” side is the Sun’s measured output, which comes from TSIS-1, an instrument on the International Space Station. There’s no catalog page for it yet, so treat it as the second half you add once the Earth side works.
Then do four steps (this is just the idea; the Run it cell below does it for you):
- Build the “out” series. From CERES EBAF, pull Earth’s net top-of-the-atmosphere energy month by month. This is how much more energy the planet absorbs than it releases.
- Build the “in” series. From TSIS-1, pull total solar irradiance (the Sun’s output reaching Earth) over the same months.
- Line them up and difference them. Put both on the same monthly timeline and subtract input from output. What’s left is Earth’s energy imbalance, the part the Sun’s changes don’t explain.
- Check it against the solar cycle. The Sun brightens and dims on a roughly 11-year cycle. See how much of the imbalance wobbles along with that cycle versus how much just keeps trending up. The steady upward part is the human-driven (greenhouse) signal.
That’s the whole method. Below, “Where the data comes from” names the pieces, and the Run it cell does it live on synthetic data so you can watch each step work.
What you can find out
- Which way the imbalance points. Compare the Sun’s measured output (TSIS-1) against Earth’s net energy budget (CERES EBAF) to see whether Earth is gaining or losing energy.
- How much warming follows the Sun. Test how much of the recent change rides the ~11-year solar cycle versus a steady greenhouse trend that climbs no matter what the Sun does.
What it can’t tell you
- Why any single year was hot or cold. The oceans soak up huge amounts of heat and release it slowly, so the system lags. A warm year can reflect heat stored from before. This method shows the long-run energy balance, not one year’s verdict.
- The whole climate story. This is the boundary condition, the energy coming in and going out at the planet’s edge. It is not a full climate model and won’t predict regional weather, sea level, or temperatures on its own.
Gotchas to watch for
- Two satellites, two yardsticks. The Sun side (TSIS-1) and the Earth side (CERES) are different instruments with different calibrations and start dates. Before you difference them, put both on the same monthly timeline and the same units. Otherwise the “gap” you see is just the instruments disagreeing, not the climate.
- The solar signal is small. The Sun’s output changes by only about 0.1% over its cycle, a real but tiny wobble. You’re hunting for a faint rhythm inside noisier data, so averaging over many months rather than single readings is what makes it visible.
- “Net” already includes reflection. CERES EBAF’s net number already accounts for sunlight Earth bounces straight back (its albedo, the reflectivity from clouds, ice, and bright surfaces). Don’t double-count that yourself. Use the net field as given.
The real-data code
The Run it cell above runs this method on synthetic data with no login. Below is the whole recipe against the real archive: search and open CERES EBAF for the “out” side, fetch TSIS-1 for the “in” side, put both on one monthly timeline, difference them, regress out the solar cycle, and plot it. It needs a free Earthdata Login.
import earthaccess, io, requests
import numpy as np, pandas as pd, xarray as xr
import matplotlib.pyplot as plt
earthaccess.login(strategy="netrc")
start, end = "2018-01-01", "2024-12-31"
# 1. The "out" side — open CERES EBAF (cleaned, balanced monthly product) and read the
# global net top-of-atmosphere flux: energy absorbed minus energy radiated, in W/m^2.
grans = earthaccess.search_data(short_name="CERES_EBAF", temporal=(start, end))
ds = xr.open_mfdataset(earthaccess.open(grans), combine="by_coords")
w = np.cos(np.deg2rad(ds.lat)) # area-weight by latitude
net = ds["toa_net_all_mon"].weighted(w).mean(("lat", "lon")) # global-mean net flux
out = net.to_series()
out.index = out.index.to_period("M") # monthly timeline
# 2. The "in" side — TSIS-1 total solar irradiance from LASP (Heliophysics, not Earthdata).
# Pull the daily TSI CSV, convert to the climate-forcing term (TSI/4 x (1-albedo)),
# and resample to the SAME monthly timeline so the two yardsticks line up.
url = "https://lasp.colorado.edu/lisird/latis/dap/tsis_tsi_24hr.csv?time,irradiance"
raw = pd.read_csv(io.StringIO(requests.get(url, timeout=120).text))
raw["time"] = pd.to_datetime(raw["time"])
tsi = raw.set_index("time")["irradiance"].resample("MS").mean()
forcing = (tsi / 4.0) * (1 - 0.29) # spread over the sphere; 0.29 albedo
forcing.index = forcing.index.to_period("M")
inp = forcing.reindex(out.index).interpolate() # align to CERES months
# 3. Earth's energy imbalance is just the "out" net flux as CERES reports it (net already
# nets the absorbed solar in). Regress it on the solar term to split Sun vs steady trend.
df = pd.DataFrame({"net": out, "solar": inp - inp.mean()}).dropna()
t = np.arange(len(df))
A = np.column_stack([np.ones_like(t), t, df["solar"].values]) # mean + trend + solar
coef, *_ = np.linalg.lstsq(A, df["net"].values, rcond=None)
intercept, trend, solar_gain = coef
# 4. Verdict + plot: the steady upward slope is the human (greenhouse) signal; the solar
# term is how much rides the ~11-year cycle.
imbalance = df["net"].mean()
print(f"Mean energy imbalance: {imbalance:+.2f} W/m^2 (>0 = Earth gaining energy)")
print(f"Steady trend: {trend*12:+.3f} W/m^2/yr | solar-cycle gain: {solar_gain:+.2f}")
print("Verdict:", "human-driven warming dominates" if trend > 0 and abs(trend*12) > abs(solar_gain)*1e-3
else "solar cycle explains much of it")
fig, ax = plt.subplots()
df["net"].plot(ax=ax, label="CERES net flux (out)")
ax.plot(df.index.to_timestamp(), A @ coef, "k--", label="trend + solar fit")
ax.set_ylabel("W/m^2"); ax.legend(); plt.tight_layout(); plt.show()
# Cross-check: CERES EBAF is anchored to in-situ ocean-heat-content uptake (Argo floats),
# so the ~0.5-1 W/m^2 positive imbalance should match Argo — not the bare instrument count.
Where the data comes from
This question is Earth-anchored, reaching into Heliophysics. It borrows one dataset from NASA’s Sun-science side to answer an Earth-climate question. The Earth half is CERES EBAF, which measures the outgoing and reflected energy at the top of the atmosphere (from NASA’s ASDC archive). The Sun half is TSIS-1 aboard the ISS, which measures total and spectral solar irradiance, the actual energy input. Differencing the input against the output isolates the planet’s energy imbalance and shows how much of it rides the solar cycle versus a steady human-driven trend.
Sources
Make it yours → Set the year range and averaging window in the notebook to focus on one solar cycle or the full record.
A safe place to practise the method on GPM_3IMERGM. The code is the real earthaccess workflow, but we feed it stand-in data shaped like the real product — so you can run it, change the numbers, and break it without an account. When you want the real data, use the recipe under “The real-data code” above, or download the notebook below.