├── img ├── test ├── map.png ├── map-2.png ├── violin.png ├── depth-mag.png ├── mag-depth.png ├── daily-counts.png ├── epicenters.png ├── quake-counts.png ├── regression.png └── mag-distribute.png ├── docker-compose.yml ├── scripts ├── run_analysis.sh ├── build_report.sh └── fetch_quakes.sh ├── cronjob.txt ├── Makefile ├── Dockerfile ├── .github └── workflows │ └── R-CMD-check.yaml ├── .gitignore ├── LICENSE ├── earthquake_report.Rmd ├── Earthquake.R └── README.md /img/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/map.png -------------------------------------------------------------------------------- /img/map-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/map-2.png -------------------------------------------------------------------------------- /img/violin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/violin.png -------------------------------------------------------------------------------- /img/depth-mag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/depth-mag.png -------------------------------------------------------------------------------- /img/mag-depth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/mag-depth.png -------------------------------------------------------------------------------- /img/daily-counts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/daily-counts.png -------------------------------------------------------------------------------- /img/epicenters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/epicenters.png -------------------------------------------------------------------------------- /img/quake-counts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/quake-counts.png -------------------------------------------------------------------------------- /img/regression.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/regression.png -------------------------------------------------------------------------------- /img/mag-distribute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Earthquake-R-Analysis/HEAD/img/mag-distribute.png -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | seismic: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | volumes: 8 | - .:/home/rstudio/earthquake 9 | environment: 10 | - DATA_DIR=/home/rstudio/earthquake/data 11 | command: ["bash", "-c", "scripts/build_report.sh"] 12 | -------------------------------------------------------------------------------- /scripts/run_analysis.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Runs the full earthquake analysis/script 3 | 4 | # Optional: load environment variables 5 | if [[ -f .env ]]; then 6 | export $(grep -v '^#' .env | xargs) 7 | fi 8 | 9 | echo "[$(date)] Starting analysis..." 10 | Rscript earthquake_viz_complete.R 11 | echo "[$(date)] Analysis complete." 12 | -------------------------------------------------------------------------------- /cronjob.txt: -------------------------------------------------------------------------------- 1 | # ┌───────────── minute (0 - 59) 2 | # │ ┌───────────── hour (0 - 23) 3 | # │ │ ┌───────────── day of month (1 - 31) 4 | # │ │ │ ┌───────────── month (1 - 12) 5 | # │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday=0) 6 | # │ │ │ │ │ 7 | # │ │ │ │ │ 8 | 0 2 * * * bash /path/to/project/scripts/build_report.sh >> /path/to/project/logs/cron.log 2>&1 9 | -------------------------------------------------------------------------------- /scripts/build_report.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Fetch data, run analysis, then render the R Markdown report 3 | 4 | set -euo pipefail 5 | 6 | echo "===== Build Report =====" 7 | ./scripts/fetch_quakes.sh 8 | ./scripts/run_analysis.sh 9 | 10 | echo "Rendering RMarkdown..." 11 | Rscript -e "rmarkdown::render('earthquake_report.Rmd', output_file='report.html')" 12 | echo "Report built: report.html" 13 | -------------------------------------------------------------------------------- /scripts/fetch_quakes.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Fetch the past 30 days M≥2.5 feed and save locally 3 | 4 | DATA_DIR="${DATA_DIR:-./data}" 5 | URL="https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.csv" 6 | OUT_FILE="$DATA_DIR/2.5_month.csv" 7 | 8 | mkdir -p "$DATA_DIR" 9 | echo "[$(date)] Downloading earthquake feed..." 10 | curl -sSL "$URL" -o "$OUT_FILE" 11 | echo "Saved to $OUT_FILE" 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean report 2 | 3 | R_SCRIPT := earthquake_viz_complete.R 4 | RMD_REPORT := earthquake_report.Rmd 5 | HTML_REPORT := earthquake_report.html 6 | 7 | all: report 8 | 9 | report: $(HTML_REPORT) 10 | 11 | $(HTML_REPORT): $(RMD_REPORT) 12 | Rscript -e "rmarkdown::render('$<', output_file = '$@')" 13 | 14 | run-script: 15 | Rscript $(R_SCRIPT) 16 | 17 | clean: 18 | rm -f *.html *.png *.Rproj.user 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official R base image 2 | FROM r-base:4.3.2 3 | 4 | # Install system dependencies for maps/ggmap 5 | RUN apt-get update && apt-get install -y \ 6 | libssl-dev libcurl4-openssl-dev libxml2-dev 7 | 8 | # Install R packages in one layer 9 | RUN R -e "install.packages(c('ggplot2','maps','ggmap','dplyr','lubridate','scales','viridis','tidyr','forcats','rmarkdown'), repos='https://cloud.r-project.org/')" 10 | 11 | # Copy project into container 12 | WORKDIR /home/rstudio/earthquake 13 | COPY . . 14 | 15 | # Default command: render report 16 | CMD ["Rscript", "-e", "rmarkdown::render('earthquake_report.Rmd', output_file='report.html')"] 17 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | name: R-CMD-check 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | R-CMD-check: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | - name: Set up R 16 | uses: r-lib/actions/setup-r@v2 17 | 18 | - name: Install dependencies 19 | run: | 20 | Rscript -e 'install.packages(c("ggplot2","maps","ggmap","dplyr","lubridate","scales","viridis","tidyr","forcats","rmarkdown"), repos="https://cloud.r-project.org/")' 21 | 22 | - name: Run script 23 | run: Rscript earthquake_viz_complete.R 24 | 25 | - name: Render report 26 | run: Rscript -e 'rmarkdown::render("earthquake_report.Rmd")' 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | .RDataTmp 8 | 9 | # User-specific files 10 | .Ruserdata 11 | 12 | # Example code in package build process 13 | *-Ex.R 14 | 15 | # Output files from R CMD build 16 | /*.tar.gz 17 | 18 | # Output files from R CMD check 19 | /*.Rcheck/ 20 | 21 | # RStudio files 22 | .Rproj.user/ 23 | 24 | # produced vignettes 25 | vignettes/*.html 26 | vignettes/*.pdf 27 | 28 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 29 | .httr-oauth 30 | 31 | # knitr and R markdown default cache directories 32 | *_cache/ 33 | /cache/ 34 | 35 | # Temporary files created by R markdown 36 | *.utf8.md 37 | *.knit.md 38 | 39 | # R Environment Variables 40 | .Renviron 41 | 42 | # pkgdown site 43 | docs/ 44 | 45 | # translation temp files 46 | po/*~ 47 | 48 | # RStudio Connect folder 49 | rsconnect/ 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Son (David) Nguyen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /earthquake_report.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "30-Day Earthquake Analysis" 3 | author: "David Nguyen" 4 | date: "`r Sys.Date()`" 5 | output: 6 | html_document: 7 | toc: true 8 | toc_depth: 3 9 | code_folding: hide 10 | theme: united 11 | --- 12 | 13 | ```{r setup, include=FALSE} 14 | knitr::opts_chunk$set( 15 | echo = TRUE, 16 | warning = FALSE, 17 | message = FALSE, 18 | fig.width = 8, 19 | fig.height = 5 20 | ) 21 | # Install & load packages 22 | pkgs <- c("ggplot2","maps","ggmap","dplyr","lubridate","scales","viridis","tidyr","forcats") 23 | for(p in pkgs) if(!requireNamespace(p, quietly=TRUE)) install.packages(p) 24 | lapply(pkgs, library, character.only=TRUE) 25 | ```` 26 | 27 | # 1. Data Loading & Preparation 28 | 29 | ```{r load-data} 30 | url <- "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.csv" 31 | quakes <- read.csv(url, stringsAsFactors=FALSE) %>% 32 | mutate( 33 | time = as.POSIXct(time, format="%Y-%m-%dT%H:%M:%S", tz="UTC"), 34 | date = as.Date(time), 35 | hour = hour(time), 36 | weekday = wday(time, label=TRUE, abbr=TRUE), 37 | mag_cat = cut(mag, breaks=c(2.5,4,5,6,Inf), 38 | labels=c("2.5–4","4–5","5–6","6+")), 39 | place_simple = fct_lump(factor(place), n=10) 40 | ) 41 | world_map <- borders("world", colour="gray50", fill="gray80") 42 | ``` 43 | 44 | # 2. Epicenter Map: Size & Color by Magnitude 45 | 46 | ```{r p1} 47 | ggplot() + world_map + 48 | geom_point(data=quakes, aes(longitude, latitude, size=mag, colour=mag), alpha=0.6) + 49 | scale_size_continuous(name="Magnitude") + 50 | scale_color_viridis(name="Magnitude", option="plasma") + 51 | ggtitle("Epicenters: M ≥ 2.5 (Past 30 Days)") + 52 | theme_minimal() 53 | ``` 54 | 55 | # 3. Epicenter Map: Color by Depth 56 | 57 | ```{r p2} 58 | ggplot() + world_map + 59 | geom_point(data=quakes, aes(longitude, latitude, colour=depth), alpha=0.6, size=1.5) + 60 | scale_color_viridis(name="Depth (km)", option="magma") + 61 | ggtitle("Epicenters Colored by Depth") + 62 | theme_minimal() 63 | ``` 64 | 65 | # 4. Histogram of Magnitudes 66 | 67 | ```{r p3} 68 | ggplot(quakes, aes(mag)) + 69 | geom_histogram(binwidth=0.2, fill="steelblue", colour="white") + 70 | scale_x_continuous(breaks=pretty_breaks()) + 71 | labs(title="Magnitude Distribution", x="Magnitude", y="Count") + 72 | theme_minimal() 73 | ``` 74 | 75 | # 5. Density Plot of Magnitudes 76 | 77 | ```{r p4} 78 | ggplot(quakes, aes(mag)) + 79 | geom_density(fill="steelblue", alpha=0.7) + 80 | labs(title="Magnitude Density", x="Magnitude", y="Density") + 81 | theme_minimal() 82 | ``` 83 | 84 | # 6. Histogram of Depths 85 | 86 | ```{r p5} 87 | ggplot(quakes, aes(depth)) + 88 | geom_histogram(binwidth=10, fill="orchid", colour="white") + 89 | labs(title="Depth Distribution", x="Depth (km)", y="Count") + 90 | theme_minimal() 91 | ``` 92 | 93 | # 7. Boxplot: Depth by Magnitude Category 94 | 95 | ```{r p6} 96 | ggplot(quakes, aes(mag_cat, depth, fill=mag_cat)) + 97 | geom_boxplot() + 98 | scale_fill_viridis(discrete=TRUE, option="cividis", name="Mag. Cat.") + 99 | labs(title="Depth by Magnitude Category", x="Magnitude Category", y="Depth (km)") + 100 | theme_minimal() 101 | ``` 102 | 103 | # 8. Scatter Plot: Magnitude vs. Depth (LOESS) 104 | 105 | ```{r p7} 106 | ggplot(quakes, aes(depth, mag)) + 107 | geom_point(alpha=0.5) + 108 | geom_smooth(method="loess", se=FALSE, colour="darkred") + 109 | labs(title="Magnitude vs. Depth", x="Depth (km)", y="Magnitude") + 110 | theme_minimal() 111 | ``` 112 | 113 | # 9. Time-Series: Daily Counts 114 | 115 | ```{r p8} 116 | daily_counts <- quakes %>% count(date) 117 | ggplot(daily_counts, aes(date, n)) + 118 | geom_line(size=1) + geom_point(size=2) + 119 | scale_x_date(date_labels="%b %d", date_breaks="5 days") + 120 | labs(title="Daily Earthquake Counts", x="Date", y="Count") + 121 | theme_minimal() 122 | ``` 123 | 124 | # 10. Heatmap: Counts by Weekday & Hour 125 | 126 | ```{r p9} 127 | heat_data <- quakes %>% 128 | count(weekday, hour) %>% 129 | complete(weekday, hour, fill=list(n=0)) 130 | ggplot(heat_data, aes(hour, weekday, fill=n)) + 131 | geom_tile(color="white") + 132 | scale_fill_viridis(name="Count", option="plasma") + 133 | labs(title="Quake Counts by Weekday & Hour (UTC)", x="Hour", y="Weekday") + 134 | theme_minimal() 135 | ``` 136 | 137 | # 11. Cumulative Earthquake Count Over Time 138 | 139 | ```{r p10} 140 | cum_data <- quakes %>% arrange(time) %>% mutate(cum = row_number()) 141 | ggplot(cum_data, aes(time, cum)) + 142 | geom_line() + 143 | labs(title="Cumulative Earthquake Count Over Time", 144 | x="Time (UTC)", y="Cumulative Count") + 145 | theme_minimal() 146 | ``` 147 | 148 | # 12. Top 10 Reported Locations 149 | 150 | ```{r p11} 151 | top_places <- quakes %>% count(place_simple) %>% arrange(desc(n)) 152 | ggplot(top_places, aes(reorder(place_simple, n), n)) + 153 | geom_col(fill="darkslateblue") + 154 | coord_flip() + 155 | labs(title="Top 10 Reported Locations", x="", y="Count") + 156 | theme_minimal() 157 | ``` 158 | 159 | # 13. Violin Plot: Magnitude by Weekday 160 | 161 | ```{r p12} 162 | ggplot(quakes, aes(weekday, mag, fill=weekday)) + 163 | geom_violin() + 164 | scale_fill_viridis(discrete=TRUE, option="turbo", name="Weekday") + 165 | labs(title="Magnitude Distribution by Weekday", x="Weekday", y="Magnitude") + 166 | theme_minimal() 167 | ``` 168 | 169 | # 14. Faceted Map by Magnitude Category 170 | 171 | ```{r p13} 172 | ggplot() + world_map + 173 | geom_point(data=quakes, aes(longitude, latitude), alpha=0.6, size=1) + 174 | facet_wrap(~ mag_cat) + 175 | labs(title="Epicenters Faceted by Magnitude Category") + 176 | theme_minimal() 177 | ``` 178 | 179 | # 15. Regression Analysis: Magnitude \~ Depth 180 | 181 | ```{r p14} 182 | model_depth_mag <- lm(mag ~ depth, data = quakes) 183 | cat("\n===== Linear Regression: mag ~ depth =====\n") 184 | print(summary(model_depth_mag)) 185 | 186 | ggplot(quakes, aes(depth, mag)) + 187 | geom_point(alpha=0.4) + 188 | geom_smooth(method="lm", se=TRUE, colour="blue") + 189 | labs( 190 | title = "Linear Regression: Magnitude vs. Depth", 191 | subtitle = paste0( 192 | "R² = ", signif(summary(model_depth_mag)$r.squared, 3), 193 | " | p-value = ", signif(summary(model_depth_mag)$coefficients[2,4], 3) 194 | ), 195 | x = "Depth (km)", 196 | y = "Magnitude" 197 | ) + 198 | theme_minimal() 199 | ``` 200 | -------------------------------------------------------------------------------- /Earthquake.R: -------------------------------------------------------------------------------- 1 | # ================================================================================= 2 | # Earthquake.R 3 | # 4 | # Fetches recent earthquakes (M≥2.5 over the past 30 days) and displays: 5 | # 1) World map of epicenters (size→mag, color→mag) 6 | # 2) World map of epicenters colored by depth 7 | # 3) Histogram of magnitudes 8 | # 4) Density plot of magnitudes 9 | # 5) Histogram of depths 10 | # 6) Boxplot of depth by magnitude category 11 | # 7) Scatter plot: magnitude vs. depth with smoothing 12 | # 8) Time-series: daily counts 13 | # 9) Heatmap: counts by weekday-hour 14 | # 10) Cumulative quake count over time 15 | # 11) Top 10 “places” by quake count (bar chart) 16 | # 12) Violin plot: magnitude by weekday 17 | # 13) Faceted world map by magnitude category 18 | # 14) Linear regression: magnitude predicted by depth 19 | # ================================================================================= 20 | 21 | # 0. Install & load packages 22 | pkgs <- c("ggplot2","maps","ggmap","dplyr","lubridate","scales","viridis","tidyr","forcats") 23 | for(p in pkgs) if(!requireNamespace(p,quietly=TRUE)) install.packages(p) 24 | lapply(pkgs, library, character.only=TRUE) 25 | 26 | # 1. Fetch & prep data 27 | url <- "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.csv" 28 | quakes <- read.csv(url, stringsAsFactors=FALSE) %>% 29 | mutate( 30 | time = as.POSIXct(time, format="%Y-%m-%dT%H:%M:%S", tz="UTC"), 31 | date = as.Date(time), 32 | hour = hour(time), 33 | weekday = wday(time, label=TRUE, abbr=TRUE), 34 | mag_cat = cut(mag, breaks=c(2.5,4,5,6,Inf), 35 | labels=c("2.5–4","4–5","5–6","6+")), 36 | place_simple = fct_lump(factor(place), n=10) # top 10 places 37 | ) 38 | 39 | world_map <- borders("world", colour="gray50", fill="gray80") 40 | 41 | # 2. Map: size & color → magnitude 42 | p1 <- ggplot() + world_map + 43 | geom_point(data=quakes, aes(longitude, latitude, size=mag, colour=mag), alpha=0.6) + 44 | scale_size_continuous(name="Magnitude") + 45 | scale_color_viridis(name="Magnitude", option="plasma") + 46 | ggtitle("Epicenters: M ≥ 2.5 (Past 30 Days)") + theme_minimal() 47 | print(p1) 48 | 49 | # 3. Map: color → depth 50 | p2 <- ggplot() + world_map + 51 | geom_point(data=quakes, aes(longitude, latitude, colour=depth), alpha=0.6, size=1.5) + 52 | scale_color_viridis(name="Depth (km)", option="magma") + 53 | ggtitle("Epicenters Colored by Depth") + theme_minimal() 54 | print(p2) 55 | 56 | # 4. Histogram: magnitudes 57 | p3 <- ggplot(quakes, aes(mag)) + 58 | geom_histogram(binwidth=0.2, fill="steelblue", colour="white") + 59 | scale_x_continuous(breaks=pretty_breaks()) + 60 | labs(title="Magnitude Distribution", x="Magnitude", y="Count") + 61 | theme_minimal() 62 | print(p3) 63 | 64 | # 5. Density plot: magnitudes (fixed) 65 | # 5. Density plot of magnitudes (solid fill) 66 | p4 <- ggplot(quakes, aes(x = mag)) + 67 | geom_density(fill = "steelblue", alpha = 0.7) + 68 | labs( 69 | title = "Magnitude Density", 70 | x = "Magnitude", 71 | y = "Density" 72 | ) + 73 | theme_minimal() 74 | print(p4) 75 | 76 | 77 | # 6. Histogram: depths 78 | p5 <- ggplot(quakes, aes(depth)) + 79 | geom_histogram(binwidth=10, fill="orchid", colour="white") + 80 | labs(title="Depth Distribution", x="Depth (km)", y="Count") + 81 | theme_minimal() 82 | print(p5) 83 | 84 | # 7. Boxplot: depth by magnitude category 85 | p6 <- ggplot(quakes, aes(mag_cat, depth, fill=mag_cat)) + 86 | geom_boxplot() + 87 | scale_fill_viridis(discrete=TRUE, option="cividis", name="Mag. Cat.") + 88 | labs(title="Depth by Magnitude Category", x="Magnitude Category", y="Depth (km)") + 89 | theme_minimal() 90 | print(p6) 91 | 92 | # 8. Scatter: magnitude vs. depth 93 | p7 <- ggplot(quakes, aes(depth, mag)) + 94 | geom_point(alpha=0.5) + 95 | geom_smooth(method="loess", se=FALSE, colour="darkred") + 96 | labs(title="Magnitude vs. Depth", x="Depth (km)", y="Magnitude") + 97 | theme_minimal() 98 | print(p7) 99 | 100 | # 9. Time-series: daily counts 101 | daily_counts <- quakes %>% count(date) 102 | p8 <- ggplot(daily_counts, aes(date, n)) + 103 | geom_line(size=1) + geom_point(size=2) + 104 | scale_x_date(date_labels="%b %d", date_breaks="5 days") + 105 | labs(title="Daily Earthquake Counts", x="Date", y="Count") + 106 | theme_minimal() 107 | print(p8) 108 | 109 | # 10. Heatmap: weekday vs. hour 110 | heat_data <- quakes %>% 111 | count(weekday, hour) %>% 112 | complete(weekday, hour, fill=list(n=0)) 113 | p9 <- ggplot(heat_data, aes(hour, weekday, fill=n)) + 114 | geom_tile(color="white") + 115 | scale_fill_viridis(name="Count", option="plasma") + 116 | labs(title="Quake Counts by Weekday & Hour (UTC)", x="Hour", y="Weekday") + 117 | theme_minimal() 118 | print(p9) 119 | 120 | # 11. Cumulative quake count 121 | cum_data <- quakes %>% 122 | arrange(time) %>% 123 | mutate(cum = row_number()) 124 | p10 <- ggplot(cum_data, aes(time, cum)) + 125 | geom_line() + 126 | labs(title="Cumulative Earthquake Count Over Time", x="Time (UTC)", y="Cumulative Count") + 127 | theme_minimal() 128 | print(p10) 129 | 130 | # 12. Top 10 places by quake count 131 | top_places <- quakes %>% count(place_simple) %>% arrange(desc(n)) 132 | p11 <- ggplot(top_places, aes(reorder(place_simple, n), n)) + 133 | geom_col(fill="darkslateblue") + 134 | coord_flip() + 135 | labs(title="Top 10 Reported Locations", x="", y="Count") + 136 | theme_minimal() 137 | print(p11) 138 | 139 | # 13. Violin: magnitude by weekday 140 | p12 <- ggplot(quakes, aes(weekday, mag, fill=weekday)) + 141 | geom_violin() + 142 | scale_fill_viridis(discrete=TRUE, option="turbo", name="Weekday") + 143 | labs(title="Magnitude Distribution by Weekday", x="Weekday", y="Magnitude") + 144 | theme_minimal() 145 | print(p12) 146 | 147 | # 14. Faceted map: by magnitude category 148 | p13 <- ggplot() + world_map + 149 | geom_point(data=quakes, aes(longitude, latitude), alpha=0.6, size=1) + 150 | facet_wrap(~ mag_cat) + 151 | labs(title="Epicenters Faceted by Magnitude Category") + 152 | theme_minimal() 153 | print(p13) 154 | 155 | # 15. Regression: magnitude predicted by depth 156 | 157 | # 15a. Fit linear model 158 | model_depth_mag <- lm(mag ~ depth, data = quakes) 159 | 160 | # 15b. Print model summary to console 161 | cat("\n===== Linear Regression: mag ~ depth =====\n") 162 | print(summary(model_depth_mag)) 163 | 164 | # 15c. Plot scatter with regression line 165 | p15 <- ggplot(quakes, aes(x = depth, y = mag)) + 166 | geom_point(alpha = 0.4) + 167 | geom_smooth(method = "lm", se = TRUE, colour = "blue") + 168 | labs( 169 | title = "Linear Regression: Magnitude vs. Depth", 170 | subtitle = paste0("R² = ", 171 | signif(summary(model_depth_mag)$r.squared, 3), 172 | ", p-value = ", 173 | signif(summary(model_depth_mag)$coefficients[2,4], 3)), 174 | x = "Depth (km)", 175 | y = "Magnitude" 176 | ) + 177 | theme_minimal() 178 | print(p15) 179 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Earthquake Visualization & Analysis 2 | 3 | A comprehensive R script that fetches global earthquake data (M ≥ 2.5 over the past 30 days) from the USGS and generates a suite of 15 exploratory and analytical plots, including mapping, distributional summaries, time-series, heatmaps, and a regression analysis. 4 | 5 | ## Table of Contents 6 | 7 | 1. [Project Overview](#project-overview) 8 | 2. [Features & Plots](#features--plots) 9 | 3. [Prerequisites](#prerequisites) 10 | 4. [Installation](#installation) 11 | 5. [Usage](#usage) 12 | 6. [Script Breakdown](#script-breakdown) 13 | 7. [Interpreting the Outputs](#interpreting-the-outputs) 14 | 8. [Extending & Customizing](#extending--customizing) 15 | 9. [Data Source & Citations](#data-source--citations) 16 | 10. [License](#license) 17 | 18 | ## Project Overview 19 | 20 | This project provides a single, self-contained R script (`Earthquake.R`) that: 21 | 22 | * **Automatically installs** required packages if missing 23 | * **Downloads** 30 days of earthquake events (M ≥ 2.5) from USGS 24 | * **Cleans & enriches** the dataset (timestamps, categories, top locations) 25 | * **Renders 15 visualizations** to explore spatial, temporal, and statistical patterns 26 | * **Performs** a simple linear regression of magnitude on depth, printing model metrics 27 | 28 | All plots display in sequence when you run the script in R (or RStudio). Ideal for researchers, data analysts, or enthusiasts who want a quick, reproducible overview of recent seismic activity. 29 | 30 | ## Features & Plots 31 | 32 | 1. **Epicenter Map** 33 | 34 | * Size and color scaled by magnitude 35 | 2. **Depth‐Colored Map** 36 | 37 | * Points shaded by earthquake depth 38 | 3. **Magnitude Histogram** 39 | 4. **Magnitude Density Plot** 40 | 5. **Depth Histogram** 41 | 6. **Depth by Magnitude Category** (Boxplot) 42 | 7. **Magnitude vs. Depth** (LOESS smoothing) 43 | 8. **Daily Quake Counts** (Time-series) 44 | 9. **Weekly Hourly Heatmap** 45 | 10. **Cumulative Quake Count** 46 | 11. **Top 10 Reported Locations** (Bar chart) 47 | 12. **Magnitude by Weekday** (Violin plot) 48 | 13. **Faceted Epicenter Map** (By magnitude category) 49 | 14. *(Repeated placeholder for consistency – see #13)* 50 | 15. **Regression Analysis** 51 | 52 | * Linear model of `mag ~ depth` 53 | * Prints summary (coefficients, R², p-values) 54 | * Scatter plot with regression line & annotation 55 | 56 |
57 |
58 |
61 |
62 |
65 |
66 |
69 |
70 |
73 |
74 |
77 |
78 |
81 |
82 |
85 |
86 |
89 |
90 |
93 |
94 |