Heatwave/Temperature Analysis Using API call from nasapower package

Author

Ukpai Chinedu Kalu

API and LIBRARY NEEDED

# Install if not yet installed
library(nasapower)
library(dplyr)
library(flextable)
library(lubridate)
library(ggplot2)
library(patchwork)

DATA PREP

# Coordinates for Nsukka, Enugu State
lat <- 6.8562
lon <- 7.3958

# Download daily temperature data (1981 - present)
temp_data <- get_power(
  community = "AG",
  lonlat = c(lon, lat),
  pars = c("T2M_MAX", "T2M_MIN", "T2M"), # max, min, avg temp
  dates = c("1981-01-01", "2023-12-31"),
  temporal_api = "DAILY"
)

# View data
head(temp_data)
────────────────────────────────────────────────────────────────────────────────
── NASA/POWER Source Native Resolution Daily Data  ─────────────────────────────
Dates (month/day/year): 01/01/1981 through 12/31/2023 in LST
Location: latitude 6.8562 longitude 7.3958
elevation from MERRA-2: Average for 0.5 x 0.625 degree lat/lon region = 220.37
meters
The value for missing source data that cannot be computed or is outside of the
sources availability range: NA
parameter(s):
────────────────────────────────────────────────────────────────────────────────
Parameters:
T2M_MAX MERRA-2 Temperature at 2 Meters Maximum (C) ; T2M_MIN MERRA-2
Temperature at 2 Meters Minimum (C) ; T2M MERRA-2 Temperature at 2 Meters (C)
────────────────────────────────────────────────────────────────────────────────
# A tibble: 6 × 10
    LON   LAT  YEAR    MM    DD   DOY YYYYMMDD   T2M_MAX T2M_MIN   T2M
  <dbl> <dbl> <dbl> <int> <int> <int> <date>       <dbl>   <dbl> <dbl>
1  7.40  6.86  1981     1     1     1 1981-01-01    30.3    18.7  24.5
2  7.40  6.86  1981     1     2     2 1981-01-02    29.8    18.3  23.7
3  7.40  6.86  1981     1     3     3 1981-01-03    27.8    17.2  22.0
4  7.40  6.86  1981     1     4     4 1981-01-04    26.2    16.0  20.6
5  7.40  6.86  1981     1     5     5 1981-01-05    27.7    14.7  20.2
6  7.40  6.86  1981     1     6     6 1981-01-06    27      14.3  20.2
# Convert to data frame
temp_df <- as.data.frame(temp_data)

# Quick plot
plot(temp_df$T2M ~ as.Date(temp_df$YYYYMMDD),
     type="l", col="red",
     main="Daily Average Temperature in Nsukka",
     xlab="Date", ylab="Temperature (°C)")

Clean the Data Frame

The raw NASA POWER output has many metadata columns you may not need.

keep only the date + temperature variables:

  Year DayOfYear       Date Temp_Avg Temp_Min Temp_Max
1 1981         1 1981-01-01    24.48    18.66    30.31
2 1981         2 1981-01-02    23.67    18.31    29.79
3 1981         3 1981-01-03    21.99    17.20    27.83
4 1981         4 1981-01-04    20.56    15.96    26.23
5 1981         5 1981-01-05    20.19    14.73    27.70
6 1981         6 1981-01-06    20.23    14.32    27.00

Export to CSV

write.csv(temp_pub, "Nsukka_Temperature.csv", row.names = FALSE)

Export a Formatted Table (for direct use in papers)

# Take a sample (first 10 rows) for publication table
temp_sample <- head(temp_pub, 10)

# Create a nice table
flextable(temp_sample)

Year

DayOfYear

Date

Temp_Avg

Temp_Min

Temp_Max

1,981

1

1981-01-01

24.48

18.66

30.31

1,981

2

1981-01-02

23.67

18.31

29.79

1,981

3

1981-01-03

21.99

17.20

27.83

1,981

4

1981-01-04

20.56

15.96

26.23

1,981

5

1981-01-05

20.19

14.73

27.70

1,981

6

1981-01-06

20.23

14.32

27.00

1,981

7

1981-01-07

20.93

16.27

26.74

1,981

8

1981-01-08

22.58

15.90

28.81

1,981

9

1981-01-09

23.80

19.81

28.59

1,981

10

1981-01-10

22.63

19.19

27.74

Summarize Monthly Data

temp_pub <- temp_pub %>%
  mutate(Year = year(Date),
         Month = month(Date, label = TRUE, abbr = TRUE))

# Monthly summary (average, min, max)
monthly_summary <- temp_pub %>%
  group_by(Year, Month) %>%
  summarise(
    Avg_Temp = mean(Temp_Avg, na.rm = TRUE),
    Min_Temp = mean(Temp_Min, na.rm = TRUE),
    Max_Temp = mean(Temp_Max, na.rm = TRUE),
    .groups = "drop"
  )

head(monthly_summary)
# A tibble: 6 × 5
   Year Month Avg_Temp Min_Temp Max_Temp
  <dbl> <ord>    <dbl>    <dbl>    <dbl>
1  1981 Jan       23.0     17.8     28.7
2  1981 Feb       24.8     19.2     30.6
3  1981 Mar       25.7     22.1     30.3
4  1981 Apr       26.2     22.9     30.4
5  1981 May       25.1     22.4     28.7
6  1981 Jun       25.1     22.3     28.6

Summarize Annual Data

annual_summary <- temp_pub %>%
  group_by(Year) %>%
  summarise(
    Avg_Temp = mean(Temp_Avg, na.rm = TRUE),
    Min_Temp = mean(Temp_Min, na.rm = TRUE),
    Max_Temp = mean(Temp_Max, na.rm = TRUE),
    .groups = "drop"
  )

annual_summary
# A tibble: 43 × 4
    Year Avg_Temp Min_Temp Max_Temp
   <dbl>    <dbl>    <dbl>    <dbl>
 1  1981     24.4     20.8     28.7
 2  1982     24.1     20.7     28.2
 3  1983     24.1     20.4     28.6
 4  1984     24.1     20.5     28.3
 5  1985     24.3     20.6     28.6
 6  1986     24.4     20.7     28.9
 7  1987     25.3     21.5     29.9
 8  1988     25.0     21.5     29.2
 9  1989     24.0     20.3     28.6
10  1990     25.0     21.3     29.4
# ℹ 33 more rows
# Table for publication
flextable(annual_summary)

Year

Avg_Temp

Min_Temp

Max_Temp

1,981

24.38088

20.78995

28.68885

1,982

24.10444

20.66164

28.22151

1,983

24.12964

20.42222

28.56992

1,984

24.06683

20.46921

28.33046

1,985

24.27277

20.61077

28.57008

1,986

24.38956

20.74386

28.90723

1,987

25.34729

21.50449

29.93518

1,988

24.99992

21.47877

29.24385

1,989

24.03600

20.26211

28.58995

1,990

25.01753

21.34027

29.37460

1,991

25.02838

21.38556

29.65074

1,992

24.69552

20.73801

29.60566

1,993

24.49304

20.93671

28.80874

1,994

24.34532

20.85721

28.59559

1,995

24.49345

21.07156

28.60507

1,996

24.63801

21.13672

28.91022

1,997

24.55573

20.93655

28.88792

1,998

25.18290

21.45329

29.63227

1,999

25.35512

21.60786

30.07625

2,000

25.22246

21.15281

30.22063

2,001

24.52101

20.74058

28.93636

2,002

24.72268

21.02151

29.13978

2,003

25.07090

21.54175

29.35066

2,004

25.04683

21.57754

29.40202

2,005

25.49663

21.90373

30.01463

2,006

25.37066

21.82151

29.75307

2,007

24.71611

21.16504

29.05458

2,008

24.70322

21.06533

28.91702

2,009

25.21293

21.77290

29.31405

2,010

25.26841

21.80014

29.40274

2,011

24.66312

21.08605

28.81085

2,012

24.74197

21.36866

28.81112

2,013

24.99301

21.69751

29.05912

2,014

25.31403

21.80195

29.67184

2,015

25.60704

21.77477

30.48912

2,016

26.00563

22.10738

30.79948

2,017

25.75044

22.08981

30.23030

2,018

25.43512

21.71060

29.88904

2,019

25.70079

22.01123

30.05416

2,020

25.52481

21.57145

30.23128

2,021

25.65934

21.89830

30.30633

2,022

25.16452

21.24192

30.08556

2,023

26.14282

22.21178

30.97605

Export Tables for Publication

# Export monthly summary
write.csv(monthly_summary, "Nsukka_Temperature_Monthly.csv", row.names = FALSE)

# Export annual summary
write.csv(annual_summary, "Nsukka_Temperature_Annual.csv", row.names = FALSE)

Define Extreme Temperature

For heatwave detection, we usually need a threshold.
Common definitions are:

  • Percentile-based: days above the 90th or 95th percentile of Tmax.

  • Absolute threshold: e.g., Tmax > 35 °C for several days.

  • We are using the 95th percentile of Tmax for this study.

# 1. Define heatwave threshold (95th percentile of Tmax)
threshold <- quantile(temp_pub$Temp_Max, 0.95, na.rm = TRUE)

# Flag extreme days
temp_pub <- temp_pub %>%
  mutate(Extreme = Temp_Max >= threshold,
         Year = year(Date),
         Month = month(Date, label = TRUE, abbr = TRUE))

# --- 2. Monthly Summary ---
heatwave_monthly <- temp_pub %>%
  filter(Extreme) %>%
  group_by(Year, Month) %>%
  summarise(Extreme_Days = n(), .groups = "drop")

# --- 3. Heatmap of Extreme-Day Counts ---
ggplot(heatwave_monthly, aes(x = Year, y = Month, fill = Extreme_Days)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "yellow", high = "red") +
  labs(title = "Heatwave Occurrence in Nsukka",
       x = "Year", y = "Month",
       fill = "Extreme Days") +
  theme_minimal()

# --- 4. Consecutive Heatwave Events (>= 3 days) ---
temp_pub <- temp_pub %>%
  arrange(Date) %>%
  mutate(Heatwave_Group = cumsum(!Extreme))  # group consecutive days

heatwave_events <- temp_pub %>%
  filter(Extreme) %>%
  group_by(Heatwave_Group) %>%
  summarise(
    Start = min(Date),
    End = max(Date),
    Duration = n(),
    Max_Temp = max(Temp_Max, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  filter(Duration >= 3)  # only keep 3+ day heatwaves

heatwave_events
# A tibble: 83 × 5
   Heatwave_Group Start      End        Duration Max_Temp
            <int> <date>     <date>        <int>    <dbl>
 1            803 1983-03-17 1983-03-20        4     34.2
 2           2233 1987-03-02 1987-03-06        5     34.6
 3           2260 1987-04-07 1987-04-11        5     34.4
 4           2269 1987-04-22 1987-04-24        3     34.9
 5           2270 1987-04-26 1987-04-30        5     34.6
 6           2562 1988-02-19 1988-02-22        4     34.2
 7           2564 1988-02-25 1988-02-28        4     34.5
 8           3618 1991-01-29 1991-02-06        9     33.9
 9           3623 1991-02-14 1991-02-16        3     34.1
10           3952 1992-01-23 1992-02-03       12     35.5
# ℹ 73 more rows
# --- 5. Max Temperature by Month ---
max_months <- temp_pub %>%
  group_by(Year, Month) %>%
  summarise(Max_Temp = max(Temp_Max, na.rm = TRUE), .groups = "drop")

ggplot(max_months, aes(x = Year, y = Month, fill = Max_Temp)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "lightblue", high = "darkred") +
  labs(title = "Extreme Maximum Monthly Temperatures - Nsukka",
       x = "Year", y = "Month",
       fill = "Max Temp (°C)") +
  theme_minimal()

Heatwave Map (Calendar Heatmap Style)

Heatmap of months vs years showing frequency of extreme days.

ggplot(heatwave_monthly, aes(x = Year, y = Month, fill = Extreme_Days)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "yellow", high = "red") +
  labs(title = "Heatwave Occurrence in Nsukka",
       x = "Year", y = "Month",
       fill = "Extreme Days") +
  theme_minimal()

Highlight Maximum Heatwave Months

Months with the absolute highest Tmax values;

max_months <- temp_pub %>%
  group_by(Year, Month = month(Date, label = TRUE, abbr = TRUE)) %>%
  summarise(Max_Temp = max(Temp_Max, na.rm = TRUE), .groups = "drop")

ggplot(max_months, aes(x = Year, y = Month, fill = Max_Temp)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "lightblue", high = "darkred") +
  labs(title = "Months of Extreme Maximum Temperatures (Nsukka)",
       x = "Year", y = "Month",
       fill = "Max Temp (°C)") +
  theme_minimal()

Export to CSV

write.csv(heatwave_events, "Nsukka_Heatwave_Events.csv", row.names = FALSE)

Create Publication-Ready Table

Formatted table for your paper (APA/journal style):

flextable(heatwave_events) %>%
  set_caption("Table: Detected Heatwave Events in Nsukka") %>%
  autofit()

Heatwave_Group

Start

End

Duration

Max_Temp

803

1983-03-17

1983-03-20

4

34.24

2,233

1987-03-02

1987-03-06

5

34.60

2,260

1987-04-07

1987-04-11

5

34.45

2,269

1987-04-22

1987-04-24

3

34.87

2,270

1987-04-26

1987-04-30

5

34.62

2,562

1988-02-19

1988-02-22

4

34.17

2,564

1988-02-25

1988-02-28

4

34.49

3,618

1991-01-29

1991-02-06

9

33.88

3,623

1991-02-14

1991-02-16

3

34.06

3,952

1992-01-23

1992-02-03

12

35.53

3,953

1992-02-05

1992-02-23

19

36.97

3,955

1992-02-26

1992-03-08

12

38.16

3,957

1992-03-13

1992-03-15

3

35.13

6,103

1998-02-04

1998-02-08

5

34.20

6,133

1998-03-15

1998-03-17

3

33.89

6,137

1998-03-23

1998-03-27

5

34.87

6,138

1998-03-29

1998-03-31

3

35.97

6,491

1999-03-24

1999-03-26

3

34.25

6,750

1999-12-18

1999-12-23

6

34.22

6,756

1999-12-31

2000-01-02

3

34.33

6,762

2000-01-11

2000-01-18

8

36.53

6,763

2000-01-20

2000-01-24

5

35.53

6,764

2000-01-26

2000-01-31

6

36.44

6,766

2000-02-03

2000-02-05

3

34.30

6,769

2000-02-11

2000-03-25

44

37.57

6,771

2000-03-28

2000-04-01

5

37.23

6,784

2000-04-25

2000-05-08

14

36.42

6,785

2000-05-10

2000-05-13

4

37.19

7,438

2002-03-03

2002-03-06

4

34.19

8,163

2004-03-13

2004-03-15

3

33.66

8,165

2004-03-19

2004-03-22

4

34.17

8,478

2005-02-01

2005-02-04

4

34.39

8,821

2006-01-19

2006-01-22

4

33.77

8,833

2006-02-06

2006-02-10

5

35.15

8,886

2006-04-10

2006-04-12

3

34.88

9,220

2007-03-17

2007-03-20

4

34.33

10,312

2010-03-28

2010-03-30

3

34.23

12,063

2015-01-20

2015-01-24

5

35.46

12,067

2015-01-30

2015-02-05

7

35.66

12,084

2015-02-28

2015-03-08

9

35.29

12,087

2015-03-12

2015-03-15

4

34.25

12,115

2015-04-14

2015-04-19

6

34.91

12,332

2015-11-28

2015-11-30

3

33.91

12,358

2015-12-27

2015-12-30

4

33.88

12,361

2016-01-03

2016-01-24

22

36.09

12,365

2016-01-29

2016-03-07

39

37.87

12,368

2016-03-14

2016-03-17

4

35.01

12,376

2016-03-28

2016-03-30

3

34.87

12,388

2016-04-14

2016-04-17

4

34.48

12,655

2017-01-16

2017-01-22

7

34.80

12,663

2017-02-03

2017-02-07

5

34.68

12,664

2017-02-09

2017-02-14

6

35.24

12,669

2017-02-20

2017-03-03

12

36.16

12,679

2017-03-16

2017-03-20

5

35.13

12,991

2018-02-02

2018-02-08

7

36.14

12,995

2018-02-14

2018-02-17

4

35.45

13,682

2020-02-05

2020-02-09

5

34.81

13,685

2020-02-14

2020-02-17

4

34.63

13,686

2020-02-19

2020-02-25

7

36.15

13,687

2020-02-27

2020-03-01

4

36.11

13,690

2020-03-07

2020-03-09

3

36.73

13,694

2020-03-14

2020-03-17

4

34.75

13,719

2020-04-13

2020-04-15

3

33.16

13,974

2020-12-29

2020-12-31

3

33.91

13,979

2021-01-08

2021-01-13

6

34.11

13,980

2021-01-15

2021-01-19

5

33.99

13,985

2021-01-25

2021-01-27

3

34.20

13,986

2021-01-29

2021-02-01

4

34.06

13,989

2021-02-09

2021-02-12

4

35.34

13,993

2021-02-20

2021-02-22

3

33.90

13,998

2021-02-28

2021-03-07

8

36.32

14,017

2021-03-27

2021-04-05

10

35.10

14,325

2022-02-08

2022-02-10

3

34.52

14,328

2022-02-17

2022-02-19

3

35.27

14,329

2022-02-21

2022-02-25

5

35.42

14,351

2022-03-25

2022-03-31

7

35.63

14,639

2023-01-18

2023-01-26

9

35.44

14,645

2023-02-02

2023-02-12

11

35.18

14,651

2023-02-19

2023-02-26

8

34.91

14,913

2023-11-30

2023-12-02

3

34.84

14,914

2023-12-04

2023-12-07

4

34.57

14,915

2023-12-09

2023-12-11

3

34.39

14,917

2023-12-14

2023-12-31

18

35.74

Summarize Longest Heatwave Per Year

# Extract year from start date of each heatwave
heatwave_events <- heatwave_events %>%
  mutate(Year = year(Start))

# For each year, find the longest heatwave
longest_heatwave_yearly <- heatwave_events %>%
  group_by(Year) %>%
  summarise(
    Start = Start[which.max(Duration)],
    End = End[which.max(Duration)],
    Duration = max(Duration, na.rm = TRUE),
    Max_Temp = max(Max_Temp, na.rm = TRUE),
    .groups = "drop"
  )

longest_heatwave_yearly
# A tibble: 22 × 5
    Year Start      End        Duration Max_Temp
   <dbl> <date>     <date>        <int>    <dbl>
 1  1983 1983-03-17 1983-03-20        4     34.2
 2  1987 1987-03-02 1987-03-06        5     34.9
 3  1988 1988-02-19 1988-02-22        4     34.5
 4  1991 1991-01-29 1991-02-06        9     34.1
 5  1992 1992-02-05 1992-02-23       19     38.2
 6  1998 1998-02-04 1998-02-08        5     36.0
 7  1999 1999-12-18 1999-12-23        6     34.3
 8  2000 2000-02-11 2000-03-25       44     37.6
 9  2002 2002-03-03 2002-03-06        4     34.2
10  2004 2004-03-19 2004-03-22        4     34.2
# ℹ 12 more rows

Export for Publication

# CSV
write.csv(longest_heatwave_yearly, "Nsukka_Longest_Heatwaves_Per_Year.csv", row.names = FALSE)

Create a Nice Table

flextable(longest_heatwave_yearly) %>%
  set_caption("Table: Longest Heatwave Events per Year in Nsukka") %>%
  autofit()

Year

Start

End

Duration

Max_Temp

1,983

1983-03-17

1983-03-20

4

34.24

1,987

1987-03-02

1987-03-06

5

34.87

1,988

1988-02-19

1988-02-22

4

34.49

1,991

1991-01-29

1991-02-06

9

34.06

1,992

1992-02-05

1992-02-23

19

38.16

1,998

1998-02-04

1998-02-08

5

35.97

1,999

1999-12-18

1999-12-23

6

34.33

2,000

2000-02-11

2000-03-25

44

37.57

2,002

2002-03-03

2002-03-06

4

34.19

2,004

2004-03-19

2004-03-22

4

34.17

2,005

2005-02-01

2005-02-04

4

34.39

2,006

2006-02-06

2006-02-10

5

35.15

2,007

2007-03-17

2007-03-20

4

34.33

2,010

2010-03-28

2010-03-30

3

34.23

2,015

2015-02-28

2015-03-08

9

35.66

2,016

2016-01-29

2016-03-07

39

37.87

2,017

2017-02-20

2017-03-03

12

36.16

2,018

2018-02-02

2018-02-08

7

36.14

2,020

2020-02-19

2020-02-25

7

36.73

2,021

2021-03-27

2021-04-05

10

36.32

2,022

2022-03-25

2022-03-31

7

35.63

2,023

2023-12-14

2023-12-31

18

35.74

Plot Longest Heatwave Duration Per Year

ggplot(longest_heatwave_yearly, aes(x = Year, y = Duration)) +
  geom_line(color = "red", size = 1) +
  geom_point(color = "darkred", size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "blue", linetype = "dashed") +
  labs(title = "Trend of Longest Heatwave Duration in Nsukka",
       x = "Year", y = "Duration (days)") +
  theme_minimal()
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
`geom_smooth()` using formula = 'y ~ x'

Plot Maximum Temperature of Longest Heatwave Per Year

ggplot(longest_heatwave_yearly, aes(x = Year, y = Max_Temp)) +
  geom_line(color = "orange", size = 1) +
  geom_point(color = "darkorange", size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "blue", linetype = "dashed") +
  labs(title = "Trend of Maximum Temperature During Longest Heatwave (Nsukka)",
       x = "Year", y = "Max Temperature (°C)") +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

(Optional) Statistical Test for Trend

# Duration trend
model_duration <- lm(Duration ~ Year, data = longest_heatwave_yearly)
summary(model_duration)

Call:
lm(formula = Duration ~ Year, data = longest_heatwave_yearly)

Residuals:
   Min     1Q Median     3Q    Max 
-7.974 -5.510 -3.838 -0.510 34.321 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept) -249.2255   392.3717  -0.635    0.533
Year           0.1295     0.1956   0.662    0.516

Residual standard error: 11.12 on 20 degrees of freedom
Multiple R-squared:  0.02142,   Adjusted R-squared:  -0.0275 
F-statistic: 0.4379 on 1 and 20 DF,  p-value: 0.5157
# Max temp trend
model_temp <- lm(Max_Temp ~ Year, data = longest_heatwave_yearly)
summary(model_temp)

Call:
lm(formula = Max_Temp ~ Year, data = longest_heatwave_yearly)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.3964 -0.9060 -0.3399  0.3014  3.1676 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept) -35.16752   43.62530  -0.806    0.430
Year          0.03522    0.02175   1.619    0.121

Residual standard error: 1.236 on 20 degrees of freedom
Multiple R-squared:  0.1159,    Adjusted R-squared:  0.0717 
F-statistic: 2.622 on 1 and 20 DF,  p-value: 0.121

Create the Two Plots a combined figure with side-by-side plots (Duration vs Max Temp) that will be neat and publication-ready.

# Plot 1: Duration Trend
p1 <- ggplot(longest_heatwave_yearly, aes(x = Year, y = Duration)) +
  geom_line(color = "red", size = 1) +
  geom_point(color = "darkred", size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "blue", linetype = "dashed") +
  labs(title = "Trend of Longest Heatwave Duration",
       x = "Year", y = "Duration (days)") +
  theme_minimal()

# Plot 2: Max Temp Trend
p2 <- ggplot(longest_heatwave_yearly, aes(x = Year, y = Max_Temp)) +
  geom_line(color = "orange", size = 1) +
  geom_point(color = "darkorange", size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "blue", linetype = "dashed") +
  labs(title = "Trend of Maximum Temperature During Longest Heatwave",
       x = "Year", y = "Max Temp (°C)") +
  theme_minimal()


# Step 3: Combine into One Figure
 
# Side-by-side
combined_plot <- p1 + p2

# Show plot
combined_plot
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

# stacked (one above the other)
combined_plot <- p1 / p2
combined_plot
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

Save for Publication

ggsave("Nsukka_Heatwave_Trends.png", combined_plot, width = 12, height = 6, dpi = 300)
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
ggsave("Nsukka_Heatwave_Trends.pdf", combined_plot, width = 12, height = 6)
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

Annotate the hottest year and longest duration so plots are eye-catching and publication-ready.

Highlight:

  • The year with the longest heatwave duration

  • The year with the highest max temperature

Identify Extremes

# Longest duration
longest_event <- longest_heatwave_yearly[which.max(longest_heatwave_yearly$Duration), ]

# Hottest event
hottest_event <- longest_heatwave_yearly[which.max(longest_heatwave_yearly$Max_Temp), ]

Annotated Plots

# Plot 1: Duration Trend with annotation
p1 <- ggplot(longest_heatwave_yearly, aes(x = Year, y = Duration)) +
  geom_line(color = "red", size = 1) +
  geom_point(color = "darkred", size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "blue", linetype = "dashed") +
  geom_point(data = longest_event, aes(x = Year, y = Duration),
             color = "black", size = 3, shape = 21, fill = "yellow") +
  geom_text(data = longest_event, aes(x = Year, y = Duration,
             label = paste0("Longest: ", Duration, " days (", Year, ")")),
             vjust = -1, hjust = 0.5, color = "black", size = 4) +
  labs(title = "Trend of Longest Heatwave Duration",
       x = "Year", y = "Duration (days)") +
  theme_minimal()

# Plot 2: Max Temp Trend with annotation
p2 <- ggplot(longest_heatwave_yearly, aes(x = Year, y = Max_Temp)) +
  geom_line(color = "orange", size = 1) +
  geom_point(color = "darkorange", size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "blue", linetype = "dashed") +
  geom_point(data = hottest_event, aes(x = Year, y = Max_Temp),
             color = "black", size = 3, shape = 21, fill = "yellow") +
  geom_text(data = hottest_event, aes(x = Year, y = Max_Temp,
             label = paste0("Hottest: ", Max_Temp, "°C (", Year, ")")),
             vjust = -1, hjust = 0.5, color = "black", size = 4) +
  labs(title = "Trend of Maximum Temperature During Longest Heatwave",
       x = "Year", y = "Max Temp (°C)") +
  theme_minimal()

Combine & Save

# Side by side
combined_plot <- p1 + p2

# Save high-res
ggsave("Nsukka_Heatwave_Trends_Annotated.png", combined_plot, width = 12, height = 6, dpi = 300)
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
ggsave("Nsukka_Heatwave_Trends_Annotated.pdf", combined_plot, width = 12, height = 6)
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

Count Heatwave Events Per Year

# Count heatwave events per year
heatwave_frequency <- heatwave_events %>%
  mutate(Year = year(Start)) %>%
  group_by(Year) %>%
  summarise(Num_Events = n(),
            Avg_Duration = mean(Duration, na.rm = TRUE),
            Max_Duration = max(Duration, na.rm = TRUE),
            .groups = "drop")

heatwave_frequency
# A tibble: 22 × 4
    Year Num_Events Avg_Duration Max_Duration
   <dbl>      <int>        <dbl>        <int>
 1  1983          1          4              4
 2  1987          4          4.5            5
 3  1988          2          4              4
 4  1991          2          6              9
 5  1992          4         11.5           19
 6  1998          4          4              5
 7  1999          3          4              6
 8  2000          8         11.1           44
 9  2002          1          4              4
10  2004          2          3.5            4
# ℹ 12 more rows

Plot Frequency Over Time

ggplot(heatwave_frequency, aes(x = Year, y = Num_Events)) +
  geom_line(color = "firebrick", size = 1) +
  geom_point(color = "darkred", size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "blue", linetype = "dashed") +
  labs(title = "Trend of Heatwave Frequency in Nsukka",
       x = "Year", y = "Number of Heatwave Events") +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

Statistical Trend Test

model_freq <- lm(Num_Events ~ Year, data = heatwave_frequency)
summary(model_freq)

Call:
lm(formula = Num_Events ~ Year, data = heatwave_frequency)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.1930 -1.5485 -0.1039  1.5514  4.7701 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)  
(Intercept) -189.38729   78.85706  -2.402   0.0262 *
Year           0.09631    0.03932   2.450   0.0236 *
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 2.235 on 20 degrees of freedom
Multiple R-squared:  0.2308,    Adjusted R-squared:  0.1923 
F-statistic:     6 on 1 and 20 DF,  p-value: 0.02364

Export for Publication

# Export frequency table
write.csv(heatwave_frequency, "Nsukka_Heatwave_Frequency.csv", row.names = FALSE)