Step 1: Load stored variables¶

Step 2: Libraries¶

Step 3: Load the precipitation data¶

Step 4: Compute yearly mean precipitation¶

Step 5: Fit the linear model¶

Step 6: Plot the annual mean precipitation with a trend line¶

In [1]:
%store -r
In [11]:
# Import libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from pathlib import Path
In [4]:
# Load the data

csv_path = r"C:\Users\kayle\Desktop\earth-analytics\04-vegetation-kward-alt\data\Laveen_precip_2001_2022.csv"
df = pd.read_csv(csv_path)

# In this csv file, the column heads are STATION, NAME, DATE and PRCP

# Make sure your column names match the file
df['DATE'] = pd.to_datetime(df['DATE'])
df['YEAR'] = df['DATE'].dt.year
In [5]:
# Compute the yearly mean PRCP
annual = df.groupby('YEAR')['PRCP'].mean().reset_index()

# Prepare arrays for regression
X = annual['YEAR'].values.reshape(-1, 1)
y = annual['PRCP'].values
In [6]:
# Fit the model 

# Here we will also print the slope, intercept and r2, which will help us 
# interpret the siginificance of any change in precipitation
model = LinearRegression()
model.fit(X, y)

slope = model.coef_[0]
intercept = model.intercept_
r2 = r2_score(y, model.predict(X))

# These provide legible labels so we don't split out just a bunch of numbers
print("=== Laveen, AZ Annual Mean Precipitation Trend ===")
print(f"Slope (per year):   {slope:.4f}")
print(f"Intercept:          {intercept:.4f}")
print(f"R²:                 {r2:.4f}")
=== Laveen, AZ Annual Mean Precipitation Trend ===
Slope (per year):   0.0002
Intercept:          -0.4555
R²:                 0.0581
In [13]:
# Plot the annual mean precipitation with a trend line and Save the plot
fig, ax = plt.subplots(figsize=(10, 5))

ax.scatter(annual['YEAR'], annual['PRCP'], label="Annual Mean Precip")
ax.plot(annual['YEAR'], model.predict(X), linewidth=2, label="Trend Line")

ax.set_title("Laveen, AZ – Annual Mean Precipitation (2001–2022)")
ax.set_xlabel("Year")
ax.set_ylabel("Mean Annual Precipitation (inches)")
ax.legend()
ax.grid(True)

fig.tight_layout()

# Save the plot in the notebook with the other figs
save_path = Path("laveen_annual_mean_precip_trend.png")
fig.savefig(save_path, dpi=300, bbox_inches="tight")

save_path
Out[13]:
WindowsPath('laveen_annual_mean_precip_trend.png')
No description has been provided for this image

Interpreting the Laveen Annual Mean Precipitation Trend (2001–2022)¶

The annual mean precipitation record for Laveen shows year-to-year variability, but is generally dry across the 21-year period as the area doesn't get more than 0.04 inches of rain in any year. This level of dryness is typical of arid and semi-arid climates in the U.S. Southwest.

Despite this, the fitted trend line indicates only a very slight long-term increase in mean precipitation:

Slope: 0.0002 units per year Intercept: –0.4555 R²: 0.058

The slope is so small that, averaged across two decades, it suggests almost no directional change in mean annual precipitation, but at least it is still positive. The low R² value (0.058) also indicates that the linear model explains very little of the overall variability. In other words, most of the pattern is driven by interannual variability rather than a persistent upward or downward trend. We can also take a quite look at the total yearly precipication just to be sure.

In [15]:
# Compute total annual precipitation

annual_total = df.groupby('YEAR')['PRCP'].sum().reset_index()

X = annual_total['YEAR'].values.reshape(-1, 1)
y = annual_total['PRCP'].values

# ---------------------------------------------------
# Fit the regression model to the annual precip
# ---------------------------------------------------
model = LinearRegression()
model.fit(X, y)

slope = model.coef_[0]
intercept = model.intercept_
r2 = r2_score(y, model.predict(X))

print("=== Laveen, AZ Total Annual Precipitation Trend ===")
print(f"Slope (per year):   {slope:.4f}")
print(f"Intercept:          {intercept:.4f}")
print(f"R²:                 {r2:.4f}")

# ---------------------------------------------------
# 4. Plot and save the figure
# ---------------------------------------------------
fig, ax = plt.subplots(figsize=(10, 5))

ax.scatter(annual_total['YEAR'], annual_total['PRCP'], label="Total Annual Precip")
ax.plot(annual_total['YEAR'], model.predict(X), linewidth=2, label="Trend Line")

ax.set_title("Laveen, AZ – Total Annual Precipitation (2001–2022)")
ax.set_xlabel("Year")
ax.set_ylabel("Total Annual Precipitation (inches)")
ax.legend()
ax.grid(True)

fig.tight_layout()

# Save the figure next to the notebook
save_path = Path("laveen_total_annual_precip_trend.png")
fig.savefig(save_path, dpi=300, bbox_inches="tight")

save_path
=== Laveen, AZ Total Annual Precipitation Trend ===
Slope (per year):   -0.2099
Intercept:          435.3146
R²:                 0.0672
Out[15]:
WindowsPath('laveen_total_annual_precip_trend.png')
No description has been provided for this image

Rising yearly mean but declining totals?¶

Our results hint at declining rain frequency but slightly increasing rain intensity. If we revisit our two slopes we have:

  • Mean slope: +0.0002 per year (positive but tiny)
  • Total slope: –0.21 inches/year (meaningful downward trend)

This suggests that in the region where the Gila River Indian Community is that there are fewer rainy days, slightly more rainfall on days when it does occur, but generally there is a loss of rain.

In [16]:
# Check for number of rainy days
df['rainy'] = df['PRCP'] > 0
rainy_days = df.groupby('YEAR')['rainy'].sum()
In [21]:
rainy_days
Out[21]:
YEAR rainy
0 2001 59
1 2002 29
2 2003 56
3 2004 70
4 2005 53
5 2006 42
6 2007 52
7 2008 72
8 2009 40
9 2010 105
10 2011 71
11 2012 78
12 2013 71
13 2014 40
14 2015 68
15 2016 49
16 2017 38
17 2018 28
18 2019 45
19 2020 16
20 2021 42
21 2022 45
In [18]:
# Look at the intensity
intensity = df[df['PRCP'] > 0].groupby('YEAR')['PRCP'].mean()
In [22]:
intensity
Out[22]:
YEAR PRCP
0 2001 0.235254
1 2002 0.211379
2 2003 0.234107
3 2004 0.227286
4 2005 0.321132
5 2006 0.253810
6 2007 0.203077
7 2008 0.294028
8 2009 0.235500
9 2010 0.241143
10 2011 0.202676
11 2012 0.177179
12 2013 0.240141
13 2014 0.589750
14 2015 0.187500
15 2016 0.204490
16 2017 0.291053
17 2018 0.344286
18 2019 0.145556
19 2020 0.368750
20 2021 0.215238
21 2022 0.251111
In [19]:
# Plot the rainy days per year

rainy_days = df.groupby('YEAR')['rainy'].sum().reset_index()

fig, ax = plt.subplots(figsize=(10,5))
ax.bar(rainy_days['YEAR'], rainy_days['rainy'], color='skyblue')

ax.set_title("Laveen, AZ – Number of Rainy Days per Year (2001–2022)")
ax.set_xlabel("Year")
ax.set_ylabel("Count of Rainy Days (>0.0 inches)")
plt.tight_layout()

fig.savefig("laveen_rainy_days_per_year.png", dpi=300, bbox_inches="tight")
plt.show()
No description has been provided for this image
In [20]:
# And then plot intensity
intensity = df[df['PRCP'] > 0].groupby('YEAR')['PRCP'].mean().reset_index()

fig, ax = plt.subplots(figsize=(10,5))
ax.plot(intensity['YEAR'], intensity['PRCP'], marker='o')

ax.set_title("Laveen, AZ – Mean Rainfall Intensity on Rainy Days (2001–2022)")
ax.set_xlabel("Year")
ax.set_ylabel("Mean Precipitation on Rainy Days (inches)")
plt.grid(True)
plt.tight_layout()

fig.savefig("laveen_rain_intensity_per_rainy_day.png", dpi=300, bbox_inches="tight")
plt.show()
No description has been provided for this image

Interpretation of Rainy-Day Frequency and Rainfall Intensity (Laveen, AZ: 2001–2022)¶

The precipitation record for Laveen (which abuts and overlaps the Gila boundary) from 2001–2022 reveals an important pattern: the frequency of rainy days has declined, while the intensity of rainfall on days that do receive precipitation has remained variable and occasionally increased, though without a strong upward trend. These two shifts together help explain why the mean daily precipitation shows a very small positive slope, while total annual precipitation trends downward more strongly.

  1. Rainy-day frequency has declined sharply over time

Over the 22-year period, the number of days with measurable precipitation exhibits a somewhat downward pattern:

  • Early 2000s: frequent rainy years (e.g., 59 rainy days in 2001, 70 in 2004, 72 in 2008, 105 in 2010).
  • Mid-to-late 2010s and early 2020s: substantially fewer rainy days, including extremely dry years (28 rainy days in 2018, 16 in 2020).
  1. Rainfall intensity on rainy days is highly variable but not strongly increasing

The mean precipitation per rainy day (intensity) fluctuates considerably from year to year. Typical rainy-day intensities cluster around 0.20–0.30 inches. Some years show notably high intensities (0.59 in 2014, 0.37 in 2020, 0.34 in 2018), indicating substantial winter storms. Several years in the 2010s show much lower intensities (0.17–0.20 inches).

Overall, the intensity trend is flat to slightly increasing, but the variability is too large to indicate a clear direction.

  1. Together, these patterns explain the mean vs. total precipitation trends

Mean daily precipitation includes all 365 days, many of which have zero rainfall. A slight rise in event intensity—even with fewer rainy days—can nudge the mean upward.

Total annual precipitation is driven almost entirely by the number of rainy days. With rainy-day counts falling from around 60–100 per year early on to 16–45 per year recently, totals drop sharply even if intensity remains stable or rises occasionally. This produces the stronger negative slope in total precipitation.

  1. Summary

In short:

  • Rainy days: clearly decreasing → drives down annual totals
  • Rainfall intensity: variable, occasionally high, but no strong trend
  • Mean precipitation: slightly positive because intensity on rainy days can rise even while rainy days decrease
  • Total precipitation: stronger negative trend because fewer events mean fewer opportunities for accumulation