From bae2f586db239ce54e5485fc5a149d97688ba6a8 Mon Sep 17 00:00:00 2001 From: Josh Brinks Date: Wed, 10 Jan 2024 15:25:07 -0500 Subject: [PATCH] wsim lesson 1 updates --- docs/wsim-gldas-acquisition.html | 642 ++++++++++++++++++++++++------- wsim-gldas-acquisition.qmd | 28 +- 2 files changed, 510 insertions(+), 160 deletions(-) diff --git a/docs/wsim-gldas-acquisition.html b/docs/wsim-gldas-acquisition.html index 7cb732f..4eebd0a 100644 --- a/docs/wsim-gldas-acquisition.html +++ b/docs/wsim-gldas-acquisition.html @@ -2,7 +2,7 @@ - + @@ -23,7 +23,7 @@ } pre > code.sourceCode { white-space: pre; position: relative; } -pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span { line-height: 1.25; } pre > code.sourceCode > span:empty { height: 1.2em; } .sourceCode { overflow: visible; } code.sourceCode > span { color: inherit; text-decoration: inherit; } @@ -145,6 +145,17 @@ } } + function dashboardOffset() { + const dashboardNavEl = window.document.getElementById( + "quarto-dashboard-header" + ); + if (dashboardNavEl !== null) { + return dashboardNavEl.clientHeight; + } else { + return 0; + } + } + function updateDocumentOffsetWithoutAnimation() { updateDocumentOffset(false); } @@ -152,7 +163,7 @@ function updateDocumentOffset(animated) { // set body offset const topOffset = headerOffset(); - const bodyOffset = topOffset + footerOffset(); + const bodyOffset = topOffset + footerOffset() + dashboardOffset(); const bodyEl = window.document.body; bodyEl.setAttribute("data-bs-offset", topOffset); bodyEl.style.paddingTop = topOffset + "px"; @@ -265,9 +276,9 @@ // Observe size changed for the header const headerEl = window.document.querySelector("header.fixed-top"); if (headerEl && window.ResizeObserver) { - const observer = new window.ResizeObserver( - updateDocumentOffsetWithoutAnimation - ); + const observer = new window.ResizeObserver(() => { + setTimeout(updateDocumentOffsetWithoutAnimation, 0); + }); observer.observe(headerEl, { attributes: true, childList: true, @@ -293,7 +304,7 @@ // Fixup any sharing links that require urls // Append url to any sharing urls const sharingLinks = window.document.querySelectorAll( - "a.sidebar-tools-main-item" + "a.sidebar-tools-main-item, a.quarto-navigation-tool, a.quarto-navbar-tools, a.quarto-navbar-tools-item" ); for (let i = 0; i < sharingLinks.length; i++) { const sharingLink = sharingLinks[i]; @@ -343,8 +354,8 @@ * Licensed MIT © Zeno Rocha */ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1 - - - + - + @@ -4476,7 +4654,7 @@
-
+ +

TO DO

    @@ -4556,7 +4736,7 @@

    Reading the Data

    # proxy = TRUE will limit memory useage but does 
     # not always work with certain downstream processing functions
     
    -wsim_gldas_anoms <- stars::read_stars("composite_anom_1mo.nc", proxy = FALSE)
    +wsim_gldas_anoms <- stars::read_stars("composite_anom_12mo.nc", proxy = FALSE)
    deficit, deficit_cause, surplus, surplus_cause, both, 
    @@ -4564,23 +4744,23 @@

    Reading the Data

    stars object with 3 dimensions and 5 attributes
     attribute(s), summary of first 1e+05 cells:
    -               Min.     1st Qu.      Median         Mean     3rd Qu.       Max.
    -deficit        -100  -1.8314584  -0.2373874  -1.26453645  -0.2373874   1.896493
    -deficit_cause     1 129.0000000 129.0000000 112.90956000 129.0000000 129.000000
    -surplus        -100  -0.9671488  -0.7329655  -0.95631468  -0.6206152   2.384447
    -surplus_cause     1 129.0000000 129.0000000 127.37130000 129.0000000 129.000000
    -both              0   0.0000000   0.0000000   0.03784493   0.0000000   2.384447
    -                NA's
    -deficit        87340
    -deficit_cause      0
    -surplus        98724
    -surplus_cause      0
    -both           98724
    +                      Min.    1st Qu.      Median        Mean    3rd Qu.
    +deficit        -100.000000  -2.366971  -1.9098018  -2.0387177  -1.171102
    +deficit_cause     1.000000 129.000000 129.0000000 121.5036000 129.000000
    +surplus          -4.310967  -1.091849  -0.3321133  -0.3779968   0.224241
    +surplus_cause     1.000000 129.000000 129.0000000 121.4569100 129.000000
    +both              0.000000   0.000000   0.0000000   0.8073860   1.447755
    +                     Max.  NA's
    +deficit          1.977621 94083
    +deficit_cause  129.000000     0
    +surplus          3.547665 94088
    +surplus_cause  129.000000     0
    +both           100.000000 94088
     dimension(s):
          from   to offset delta  refsys                    values x/y
     x       1 1440   -180  0.25  WGS 84                      NULL [x]
     y       1  600     90 -0.25  WGS 84                      NULL [y]
    -time    1  804     NA    NA POSIXct 1948-01-01,...,2014-12-01    
    +time 1 793 NA NA POSIXct 1948-12-01,...,2014-12-01

    The print command gives some basic information. The outputs tells us we have 5 attributes (deficit, deficit_cause, surplus, surplus_cause, both) and 3 dimensions. The first 2 dimensions are the spatial extents (x/y–longitude/latitude) and time is the 3rd dimension.

    @@ -4588,24 +4768,24 @@

    Reading the Data

Attribute Selection

-

We can start paring this down by subsetting for just the combined surplus/deficit anomaly (both).

+

We can start paring this down by subsetting for just deficits (drought).

names(wsim_gldas_anoms)
[1] "deficit"       "deficit_cause" "surplus"       "surplus_cause"
 [5] "both"         
-
wsim_gldas_anoms <- wsim_gldas_anoms['both']
+
wsim_gldas_anoms <- wsim_gldas_anoms['deficit']

Time Selection

-

Specifying a temporal range of interest will free up more space. We’ll grab every month for 2000-2014. This can be accomplished by generating a sequence for every month between January 2000 and December 2014, and then passing that vector of dates to filter.

+

Specifying a temporal range of interest will free up more space. We’ll grab every year for 2000-2014. This can be accomplished by generating a sequence for every year between December 2000 and December 2014, and then passing that vector of dates to filter.

# generate a vector of dates for subsetting
-keeps<-seq(lubridate::ymd("2000-01-01"),
+keeps<-seq(lubridate::ymd("2000-12-01"),
            lubridate::ymd("2014-12-01"), 
-           by = "month")
+           by = "year")
 # filter using that vector
 wsim_gldas_anoms <- dplyr::filter(wsim_gldas_anoms, time %in% keeps)
 
@@ -4613,25 +4793,29 @@ 

Time Selection

stars object with 3 dimensions and 1 attribute
 attribute(s), summary of first 1e+05 cells:
-      Min. 1st Qu. Median     Mean  3rd Qu. Max.  NA's
-both     0       0      0 5.415477 1.631542  100 98724
+              Min.   1st Qu.    Median      Mean    3rd Qu.      Max.  NA's
+deficit  -3.140659 -1.491055 -1.092252 -1.037756 -0.5627083 0.8403344 94083
 dimension(s):
      from   to offset delta  refsys                    values x/y
 x       1 1440   -180  0.25  WGS 84                      NULL [x]
 y       1  600     90 -0.25  WGS 84                      NULL [y]
-time    1  180     NA    NA POSIXct 2000-01-01,...,2014-12-01    
+time 1 15 NA NA POSIXct 2000-12-01,...,2014-12-01
-

Now we’re down to a single attribute (“both”) with 180 time-steps. We can take a look at the first 6 months by passing the object through slice and then into plot.

+

Now we’re down to a single attribute (“both”) with 15 time-steps. We can take a look at the first 6 years by passing the object through slice and then into plot.

wsim_gldas_anoms |>
   dplyr::slice(index = 1:6, along = "time") |>
-  plot(key.pos = 1)
+ plot(key.pos = 1, breaks = c(0, -5, -10, -20, -30, -50), key.lab = "Deficit")
downsample set to 1
-

+
+
+

+
+

Although we’ve pared it down to a single attribute with a restricted time period of interest, we can take it a step further and reduce the spatial extent to a country or state of interest.

@@ -4685,7 +4869,11 @@

Spatial Selection

plot(sf::st_geometry(usa))
-

+
+
+

+
+

This looks good, but it includes all United States territories. For simplicity, we can get it down to only the contiguous United States.

@@ -4702,7 +4890,11 @@

Spatial Selection

plot(sf::st_geometry(usa))
-

+
+
+

+
+

We can take this a step further and select a target state.

@@ -4711,7 +4903,11 @@

Spatial Selection

plot(sf::st_geometry(texas))
-

+
+
+

+
+

From here we can crop the WSIM GLDAS raster stack by indexing it with the stored boundary of Texas

@@ -4722,11 +4918,11 @@

Spatial Selection

and y do not overlap -

For a final visual check we’ll take the last time-step in the WSIM-GLDAS dataset (180/December, 2014) and plot it with an overlay of the Texas boundary.

+

For a final visual check we’ll take the last time-step in the WSIM-GLDAS dataset (15/December, 2014) and plot it with an overlay of the Texas boundary.

wsim_gldas_anoms_tex |>
-  dplyr::slice(index = 180, along = "time") |>
-  plot(reset = FALSE)
+  dplyr::slice(index = 15, along = "time") |>
+  plot(reset = FALSE, breaks = c(0,-1,-2,-3,-4,-5))
 
 plot(sf::st_geometry(texas),
      add = TRUE,
@@ -4734,7 +4930,11 @@ 

Spatial Selection

fill = NA, border = 'purple')
-

+
+
+

+
+

The subsetted dataset may be written to disk, and saved for future modules.

@@ -4826,10 +5026,9 @@

Spatial Selection

// clear code selection e.clearSelection(); }); - function tippyHover(el, contentFn) { + function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) { const config = { allowHTML: true, - content: contentFn, maxWidth: 500, delay: 100, arrow: false, @@ -4839,8 +5038,17 @@

Spatial Selection

interactive: true, interactiveBorder: 10, theme: 'quarto', - placement: 'bottom-start' + placement: 'bottom-start', }; + if (contentFn) { + config.content = contentFn; + } + if (onTriggerFn) { + config.onTrigger = onTriggerFn; + } + if (onUntriggerFn) { + config.onUntrigger = onUntriggerFn; + } window.tippy(el, config); } const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); @@ -4854,6 +5062,120 @@

Spatial Selection

const note = window.document.getElementById(id); return note.innerHTML; }); + } + const xrefs = window.document.querySelectorAll('a.quarto-xref'); + const processXRef = (id, note) => { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + if (id === null || id.startsWith('sec-')) { + // Special case sections, only their first couple elements + const container = document.createElement("div"); + if (note.children && note.children.length > 2) { + container.appendChild(note.children[0].cloneNode(true)); + for (let i = 1; i < note.children.length; i++) { + const child = note.children[i]; + if (child.tagName === "P" && child.innerText === "") { + continue; + } else { + container.appendChild(child.cloneNode(true)); + break; + } + } + if (window.Quarto?.typesetMath) { + window.Quarto.typesetMath(container); + } + return container.innerHTML + } else { + if (window.Quarto?.typesetMath) { + window.Quarto.typesetMath(note); + } + return note.innerHTML; + } + } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + if (window.Quarto?.typesetMath) { + window.Quarto.typesetMath(note); + } + return note.innerHTML; + } + } + for (var i=0; i res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); + } + } else { + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.querySelector('main.content'); + if (note !== null) { + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); + } + }, function(instance) { + }); } let selectedAnnoteEl; const selectorForAnnotation = ( cell, annotation) => { @@ -4896,6 +5218,7 @@

Spatial Selection

} div.style.top = top - 2 + "px"; div.style.height = height + 4 + "px"; + div.style.left = 0; let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); if (gutterDiv === null) { gutterDiv = window.document.createElement("div"); @@ -4921,6 +5244,32 @@

Spatial Selection

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -4984,4 +5333,5 @@

Spatial Selection

+ \ No newline at end of file diff --git a/wsim-gldas-acquisition.qmd b/wsim-gldas-acquisition.qmd index dfbdabe..7f01f8f 100644 --- a/wsim-gldas-acquisition.qmd +++ b/wsim-gldas-acquisition.qmd @@ -30,7 +30,7 @@ Once you've completed the download and placed the .nc into your working director # proxy = TRUE will limit memory useage but does # not always work with certain downstream processing functions -wsim_gldas_anoms <- stars::read_stars("composite_anom_1mo.nc", proxy = FALSE) +wsim_gldas_anoms <- stars::read_stars("composite_anom_12mo.nc", proxy = FALSE) print(wsim_gldas_anoms) ``` @@ -41,35 +41,35 @@ This means the total number of individual raster layers in this NetCDF is 4020 ( ## Attribute Selection -We can start paring this down by subsetting for just the combined surplus/deficit anomaly (both). +We can start paring this down by subsetting for just deficits (drought). ```{r} names(wsim_gldas_anoms) -wsim_gldas_anoms <- wsim_gldas_anoms['both'] +wsim_gldas_anoms <- wsim_gldas_anoms['deficit'] ``` ## Time Selection -Specifying a temporal range of interest will free up more space. We'll grab every month for 2000-2014. This can be accomplished by generating a sequence for every month between January 2000 and December 2014, and then passing that vector of dates to `filter`. +Specifying a temporal range of interest will free up more space. We'll grab every year for 2000-2014. This can be accomplished by generating a sequence for every year between December 2000 and December 2014, and then passing that vector of dates to `filter`. ```{r} # generate a vector of dates for subsetting -keeps<-seq(lubridate::ymd("2000-01-01"), +keeps<-seq(lubridate::ymd("2000-12-01"), lubridate::ymd("2014-12-01"), - by = "month") + by = "year") # filter using that vector wsim_gldas_anoms <- dplyr::filter(wsim_gldas_anoms, time %in% keeps) print(wsim_gldas_anoms) ``` -Now we're down to a single attribute ("both") with 180 time-steps. We can take a look at the first 6 months by passing the object through `slice` and then into `plot`. +Now we're down to a single attribute ("both") with 15 time-steps. We can take a look at the first 6 years by passing the object through `slice` and then into `plot`. -```{r} +```{r warning=FALSE} wsim_gldas_anoms |> dplyr::slice(index = 1:6, along = "time") |> - plot(key.pos = 1) + plot(key.pos = 1, breaks = c(0, -5, -10, -20, -30, -50), key.lab = "Deficit") ``` Although we've pared it down to a single attribute with a restricted time period of interest, we can take it a step further and reduce the spatial extent to a country or state of interest. @@ -137,13 +137,13 @@ From here we can crop the WSIM GLDAS raster stack by indexing it with the stored wsim_gldas_anoms_tex <- wsim_gldas_anoms[texas] ``` -For a final visual check we'll take the last time-step in the WSIM-GLDAS dataset (180/December, 2014) and plot it with an overlay of the Texas boundary. +For a final visual check we'll take the last time-step in the WSIM-GLDAS dataset (15/December, 2014) and plot it with an overlay of the Texas boundary. -```{r} +```{r warning = FALSE} wsim_gldas_anoms_tex |> - dplyr::slice(index = 180, along = "time") |> - plot(reset = FALSE) + dplyr::slice(index = 15, along = "time") |> + plot(reset = FALSE, breaks = c(0,-1,-2,-3,-4,-5)) plot(sf::st_geometry(texas), add = TRUE, @@ -155,7 +155,7 @@ plot(sf::st_geometry(texas), The subsetted dataset may be written to disk, and saved for future modules. ```{r} -stars::write_stars(wsim_gldas_anoms_tex, "wsim_gldas_tex.nc") +stars::write_mdim(wsim_gldas_anoms_tex, "wsim_gldas_tex.nc") ``` The size of the pre-processed dataset is 1.6 MB compared to the original dataset of 1.7 GB. This is much more manageable in cloud environments, workshops, and git platforms. \ No newline at end of file