Overview

This notebook will demonstrate two ways of dealing with larger volumes of data by caching retrieved into a local SQLite database.

A functional definition of “large data” might include:

Saving Cal-Adapt Data to SQLite Database

To manage large downloads and avoid downloading data twice, caladaptR provides ca_getvals_db(). ca_getvals_db() is very similar to ca_getvals_tbl(), but saves the data into a SQLite database file on your computer as it comes in. Before making an API request, it checks to see if the data have already been downloaded, and if so skips it. If you get disconnected during a download, you can run the command again and it’ll just pick up where it left off. ca_getvals_db() returns a ‘remote tibble’, which functions very similar to a regular ‘in-memory’ tibble however it points to the SQLite database file on disk.

For additional info on working with SQLite databases, see the Article on making Large Queries.

Example: Download Daily Data for Congressional Disticts

In this example we’ll download daily temperature data for 16 Congressional Districts in the LA region.


Setup

Load caladaptR and the other package we’re going to need. (If you haven’t installed these yet, see this setup script).

library(caladaptr)
library(units)
library(ggplot2)
library(dplyr)
library(lubridate)
library(sf)
library(tidyr)
library(tmap)
library(conflicted)
conflict_prefer("filter", "dplyr", quiet = TRUE)
conflict_prefer("count", "dplyr", quiet = TRUE)
conflict_prefer("select", "dplyr", quiet = TRUE)


Import the Congressional Districts Boundaries

The LA Congressional district boundaries are saved in the ‘data’ folder as a geopackage:

cdist_la_fn <- "./data/cdistricts_la.gpkg"
file.exists(cdist_la_fn)

cdist_la_sf <- st_read(cdist_la_fn)

tmap_mode("view")
tm_shape(cdist_la_sf) + tm_borders()

Pro Tip:

  • to use a sf object the location for an API Request, it must be in geographic coordinates (EPSG 4326)


Create the API Request

Here we use ca_loc_sf() as the location function for an API request for 30-years of modeled daily temperature data (minimum and maximum) for 4 GCMs and 2 RCPs:

cdist_la_cap <- ca_loc_sf(loc = cdist_la_sf, idfld = "geoid") %>% 
  ca_gcm(gcms[1:4]) %>%                                 
  ca_scenario(c("rcp45", "rcp85")) %>%
  ca_period("day") %>%
  ca_years(start = 2070, end = 2099) %>%
  ca_cvar(c("tasmin", "tasmax")) %>% 
  ca_options(spatial_ag = "mean")

cdist_la_cap


Do the standard plotting and preflight checks:

plot(cdist_la_cap, locagrid = TRUE)
cdist_la_cap %>% ca_preflight()


Fetch Data

To copy downloaded data into a database, use ca_getvals_db() instead of ca_getvals_tbl(). ca_getvals_db() has two arguments which are mandatory:

db_fn - the file name of a SQLite database (will be created if it doesn’t exist)

db_tbl - the name of a table inside the database where the values should be saved

my_database_fn <- "./data/cdist_la_temp_data.sqlite"

cdist_la_rtbl <- cdist_la_cap %>% 
  ca_getvals_db(db_fn = my_database_fn, 
                db_tbl = "temp_data",
                quiet = FALSE)


Inspect the results:

cdist_la_rtbl %>% head()


The number of rows we retrieved:

cdist_la_rtbl %>% count() %>% pull(n)


Wrangling a Remote Tibble

Many of the base R operations that work with in-memory tibbles may or many not work with remote tibbles. For example as we saw above cdist_la_rtbl %>% count() works, but:

dim(cdist_la_rtbl)
nrow(cdist_la_rtbl)


In general, the best way to work with remote tibbles is with

  1. dplyr functions, or
  2. SQL statements passed using the DBI package

Simple filtering, sorting, grouping and simple numeric summaries generally work fine with dplyr verbs:

cdist_la_rtbl %>% 
  filter(geoid == "0632") %>% 
  group_by(scenario, gcm, cvar) %>% 
  summarize(mean_temp = mean(val, na.rm = TRUE))


Pro Tip:

  • You can ‘convert’ a Remote Tibble to a regular in-memory Tibble by tacking on collect() at the end of a dplyr expression.


If your wrangling workflow involves a lot steps that are difficult or impossible to do with remote tibbles, a good strategy is to do your filtering and grouping with dplyr statements on the remote tibble, and then convert the results to a regular tibble with collect().

Below we convert the grouped summary table into a tibble so we can use pivot_wider() (which doesn’t work on remote tibbles):

temp_long_tbl <- cdist_la_rtbl %>% 
  filter(geoid == "0632") %>% 
  group_by(scenario, gcm, cvar) %>% 
  summarize(mean_temp = mean(val, na.rm = TRUE)) %>% 
  collect()

class(temp_long_tbl)

temp_wide_tbl <- temp_long_tbl %>% 
  pivot_wider(names_from = cvar, values_from = mean_temp) %>% 
  mutate(tas_range = tasmax - tasmin)

temp_wide_tbl %>% head()


Challenge

Create a histogram of the mean daily temperatures for one Congressional District and one emissions scenario, grouping the data by GCM. Does the distribution of mean average temperature look the same across GCMs?

## Your answer here


LS0tDQp0aXRsZTogIkxhcmdlIFF1ZXJpZXMiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIGNzczogaHR0cHM6Ly91Y2Fuci1pZ2lzLmdpdGh1Yi5pby9jYWxhZGFwdHItcmVzL2Fzc2V0cy9uYl9jc3MwMS5jc3MNCiAgICBpbmNsdWRlczoNCiAgICAgIGFmdGVyX2JvZHk6IGh0dHBzOi8vdWNhbnItaWdpcy5naXRodWIuaW8vY2FsYWRhcHRyLXJlcy9hc3NldHMvbmJfZm9vdGVyMDEuaHRtbA0KLS0tDQoNCiMgT3ZlcnZpZXcNCg0KVGhpcyBub3RlYm9vayB3aWxsIGRlbW9uc3RyYXRlIHR3byB3YXlzIG9mIGRlYWxpbmcgd2l0aCBsYXJnZXIgdm9sdW1lcyBvZiBkYXRhIGJ5IGNhY2hpbmcgcmV0cmlldmVkIGludG8gYSBsb2NhbCBTUUxpdGUgZGF0YWJhc2UuICANCg0KQSBmdW5jdGlvbmFsIGRlZmluaXRpb24gb2YgImxhcmdlIGRhdGEiIG1pZ2h0IGluY2x1ZGU6DQoNCi0gYW55IHZvbHVtZSBvZiBkYXRhIHRoYXQgeW91IHdvdWxkbid0IHdhbnQgdG8gZG93bmxvYWQgdHdpY2UgIA0KLSBhbnkgdm9sdW1lIG9mIGRhdGEgdGhhdCBtaWdodCBib2cgZG93biAob3Igd29yc2UsIGNyYXNoKSB0aGUgQ2FsLUFkYXB0IHNlcnZlciwgYW5kIGFubm95IHRoZSBzeXN0ZW0gYWRtaW5pc3RyYXRvcnMgIA0KDQojIyBTYXZpbmcgQ2FsLUFkYXB0IERhdGEgdG8gU1FMaXRlIERhdGFiYXNlDQoNClRvIG1hbmFnZSBsYXJnZSBkb3dubG9hZHMgYW5kIGF2b2lkIGRvd25sb2FkaW5nIGRhdGEgdHdpY2UsIGNhbGFkYXB0UiBwcm92aWRlcyBgY2FfZ2V0dmFsc19kYigpYC4gYGNhX2dldHZhbHNfZGIoKWAgaXMgdmVyeSBzaW1pbGFyIHRvIGBjYV9nZXR2YWxzX3RibCgpYCwgYnV0IHNhdmVzIHRoZSBkYXRhIGludG8gYSBTUUxpdGUgZGF0YWJhc2UgZmlsZSBvbiB5b3VyIGNvbXB1dGVyIGFzIGl0IGNvbWVzIGluLiBCZWZvcmUgbWFraW5nIGFuIEFQSSByZXF1ZXN0LCBpdCBjaGVja3MgdG8gc2VlIGlmIHRoZSBkYXRhIGhhdmUgYWxyZWFkeSBiZWVuIGRvd25sb2FkZWQsIGFuZCBpZiBzbyBza2lwcyBpdC4gSWYgeW91IGdldCBkaXNjb25uZWN0ZWQgZHVyaW5nIGEgZG93bmxvYWQsIHlvdSBjYW4gcnVuIHRoZSBjb21tYW5kIGFnYWluIGFuZCBpdCdsbCBqdXN0IHBpY2sgdXAgd2hlcmUgaXQgbGVmdCBvZmYuIGBjYV9nZXR2YWxzX2RiKClgIHJldHVybnMgYSAncmVtb3RlIHRpYmJsZScsIHdoaWNoIGZ1bmN0aW9ucyB2ZXJ5IHNpbWlsYXIgdG8gYSByZWd1bGFyICdpbi1tZW1vcnknIHRpYmJsZSBob3dldmVyIGl0IHBvaW50cyB0byB0aGUgU1FMaXRlIGRhdGFiYXNlIGZpbGUgb24gZGlzay4NCg0KRm9yIGFkZGl0aW9uYWwgaW5mbyBvbiB3b3JraW5nIHdpdGggU1FMaXRlIGRhdGFiYXNlcywgc2VlIHRoZSBBcnRpY2xlIG9uIG1ha2luZyBbTGFyZ2UgUXVlcmllc10oaHR0cHM6Ly91Y2Fuci1pZ2lzLmdpdGh1Yi5pby9jYWxhZGFwdHIvYXJ0aWNsZXMvbGFyZ2UtcXVlcmllcy5odG1sKS4NCg0KIyBFeGFtcGxlOiBEb3dubG9hZCBEYWlseSBEYXRhIGZvciBDb25ncmVzc2lvbmFsIERpc3RpY3RzDQoNCkluIHRoaXMgZXhhbXBsZSB3ZSdsbCBkb3dubG9hZCBkYWlseSB0ZW1wZXJhdHVyZSBkYXRhIGZvciAxNiBDb25ncmVzc2lvbmFsIERpc3RyaWN0cyBpbiB0aGUgTEEgcmVnaW9uLiANCg0KXA0KDQojIyBTZXR1cA0KDQpMb2FkIGNhbGFkYXB0UiBhbmQgdGhlIG90aGVyIHBhY2thZ2Ugd2UncmUgZ29pbmcgdG8gbmVlZC4gKElmIHlvdSBoYXZlbid0IGluc3RhbGxlZCB0aGVzZSB5ZXQsIHNlZSB0aGlzIFtzZXR1cCBzY3JpcHRdKGh0dHBzOi8vZ2l0aHViLmNvbS91Y2Fuci1pZ2lzL2NhbGFkYXB0ci1yZXMvYmxvYi9tYWluL2RvY3Mvd29ya3Nob3BzL2NhX2ludHJvX29jdDIxL3NjcmlwdHMvY2FsYWRhcHRyX3NldHVwLlIpKS4gDQoNCmBgYHtyIGNodW5rMDEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hvbGQnfQ0KbGlicmFyeShjYWxhZGFwdHIpDQpsaWJyYXJ5KHVuaXRzKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShzZikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHRtYXApDQpsaWJyYXJ5KGNvbmZsaWN0ZWQpDQpjb25mbGljdF9wcmVmZXIoImZpbHRlciIsICJkcGx5ciIsIHF1aWV0ID0gVFJVRSkNCmNvbmZsaWN0X3ByZWZlcigiY291bnQiLCAiZHBseXIiLCBxdWlldCA9IFRSVUUpDQpjb25mbGljdF9wcmVmZXIoInNlbGVjdCIsICJkcGx5ciIsIHF1aWV0ID0gVFJVRSkNCmBgYA0KDQpcDQoNCiMjIEltcG9ydCB0aGUgQ29uZ3Jlc3Npb25hbCBEaXN0cmljdHMgQm91bmRhcmllcw0KDQpUaGUgTEEgQ29uZ3Jlc3Npb25hbCBkaXN0cmljdCBib3VuZGFyaWVzIGFyZSBzYXZlZCBpbiB0aGUgJ2RhdGEnIGZvbGRlciBhcyBhIGdlb3BhY2thZ2U6DQoNCmBgYHtyIGNodW5rMDJ9DQpjZGlzdF9sYV9mbiA8LSAiLi9kYXRhL2NkaXN0cmljdHNfbGEuZ3BrZyINCmZpbGUuZXhpc3RzKGNkaXN0X2xhX2ZuKQ0KDQpjZGlzdF9sYV9zZiA8LSBzdF9yZWFkKGNkaXN0X2xhX2ZuKQ0KDQp0bWFwX21vZGUoInZpZXciKQ0KdG1fc2hhcGUoY2Rpc3RfbGFfc2YpICsgdG1fYm9yZGVycygpDQpgYGANCg0KKipQcm8gVGlwOioqDQoNCi0gdG8gdXNlIGEgc2Ygb2JqZWN0IHRoZSBsb2NhdGlvbiBmb3IgYW4gQVBJIFJlcXVlc3QsIGl0IG11c3QgYmUgaW4gZ2VvZ3JhcGhpYyBjb29yZGluYXRlcyAoRVBTRyA0MzI2KQ0KDQpcDQoNCiMjIENyZWF0ZSB0aGUgQVBJIFJlcXVlc3QNCg0KSGVyZSB3ZSB1c2UgYGNhX2xvY19zZigpYCBhcyB0aGUgbG9jYXRpb24gZnVuY3Rpb24gZm9yIGFuIEFQSSByZXF1ZXN0IGZvciAzMC15ZWFycyBvZiBtb2RlbGVkIGRhaWx5IHRlbXBlcmF0dXJlIGRhdGEgKG1pbmltdW0gYW5kIG1heGltdW0pIGZvciA0IEdDTXMgYW5kIDIgUkNQczoNCg0KYGBge3IgY2h1bmswM30NCmNkaXN0X2xhX2NhcCA8LSBjYV9sb2Nfc2YobG9jID0gY2Rpc3RfbGFfc2YsIGlkZmxkID0gImdlb2lkIikgJT4lIA0KICBjYV9nY20oZ2Ntc1sxOjRdKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgY2Ffc2NlbmFyaW8oYygicmNwNDUiLCAicmNwODUiKSkgJT4lDQogIGNhX3BlcmlvZCgiZGF5IikgJT4lDQogIGNhX3llYXJzKHN0YXJ0ID0gMjA3MCwgZW5kID0gMjA5OSkgJT4lDQogIGNhX2N2YXIoYygidGFzbWluIiwgInRhc21heCIpKSAlPiUgDQogIGNhX29wdGlvbnMoc3BhdGlhbF9hZyA9ICJtZWFuIikNCg0KY2Rpc3RfbGFfY2FwDQpgYGANCg0KXA0KDQpEbyB0aGUgc3RhbmRhcmQgcGxvdHRpbmcgYW5kIHByZWZsaWdodCBjaGVja3M6DQoNCmBgYHtyIGNodW5rMDQsIGNhY2hlID0gRkFMU0V9DQpwbG90KGNkaXN0X2xhX2NhcCwgbG9jYWdyaWQgPSBUUlVFKQ0KYGBgDQoNCg0KYGBge3IgY2h1bmswNX0NCmNkaXN0X2xhX2NhcCAlPiUgY2FfcHJlZmxpZ2h0KCkNCmBgYA0KDQpcDQoNCiMjIEZldGNoIERhdGENCg0KVG8gY29weSBkb3dubG9hZGVkIGRhdGEgaW50byBhIGRhdGFiYXNlLCB1c2UgYGNhX2dldHZhbHNfZGIoKWAgaW5zdGVhZCBvZiBgY2FfZ2V0dmFsc190YmwoKWAuIGBjYV9nZXR2YWxzX2RiKClgIGhhcyB0d28gYXJndW1lbnRzIHdoaWNoIGFyZSBtYW5kYXRvcnk6DQoNCmBkYl9mbmAgLSB0aGUgZmlsZSBuYW1lIG9mIGEgU1FMaXRlIGRhdGFiYXNlICh3aWxsIGJlIGNyZWF0ZWQgaWYgaXQgZG9lc24ndCBleGlzdCkNCg0KYGRiX3RibGAgLSB0aGUgbmFtZSBvZiBhIHRhYmxlIGluc2lkZSB0aGUgZGF0YWJhc2Ugd2hlcmUgdGhlIHZhbHVlcyBzaG91bGQgYmUgc2F2ZWQNCg0KYGBge3IgY2h1bmswNn0NCm15X2RhdGFiYXNlX2ZuIDwtICIuL2RhdGEvY2Rpc3RfbGFfdGVtcF9kYXRhLnNxbGl0ZSINCg0KY2Rpc3RfbGFfcnRibCA8LSBjZGlzdF9sYV9jYXAgJT4lIA0KICBjYV9nZXR2YWxzX2RiKGRiX2ZuID0gbXlfZGF0YWJhc2VfZm4sIA0KICAgICAgICAgICAgICAgIGRiX3RibCA9ICJ0ZW1wX2RhdGEiLA0KICAgICAgICAgICAgICAgIHF1aWV0ID0gRkFMU0UpDQpgYGANCg0KXA0KDQpJbnNwZWN0IHRoZSByZXN1bHRzOg0KDQpgYGB7ciBjaHVuazA3fQ0KY2Rpc3RfbGFfcnRibCAlPiUgaGVhZCgpDQpgYGANCg0KXA0KDQpUaGUgbnVtYmVyIG9mIHJvd3Mgd2UgcmV0cmlldmVkOg0KDQpgYGB7ciBjaHVuazA4fQ0KY2Rpc3RfbGFfcnRibCAlPiUgY291bnQoKSAlPiUgcHVsbChuKQ0KYGBgDQoNClwNCg0KIyMgV3JhbmdsaW5nIGEgUmVtb3RlIFRpYmJsZQ0KDQpNYW55IG9mIHRoZSBiYXNlIFIgb3BlcmF0aW9ucyB0aGF0IHdvcmsgd2l0aCBpbi1tZW1vcnkgdGliYmxlcyBtYXkgb3IgbWFueSBub3Qgd29yayB3aXRoIHJlbW90ZSB0aWJibGVzLiBGb3IgZXhhbXBsZSBhcyB3ZSBzYXcgYWJvdmUgYGNkaXN0X2xhX3J0YmwgJT4lIGNvdW50KClgIHdvcmtzLCBidXQ6DQoNCmBgYHtyIGNodW5rMDl9DQpkaW0oY2Rpc3RfbGFfcnRibCkNCm5yb3coY2Rpc3RfbGFfcnRibCkNCmBgYA0KDQpcDQoNCkluIGdlbmVyYWwsIHRoZSBiZXN0IHdheSB0byB3b3JrIHdpdGggcmVtb3RlIHRpYmJsZXMgaXMgd2l0aCANCg0KaSkgZHBseXIgZnVuY3Rpb25zLCBvciAgIA0KaWkpIFNRTCBzdGF0ZW1lbnRzIHBhc3NlZCB1c2luZyB0aGUgYERCSWAgcGFja2FnZSANCg0KU2ltcGxlIGZpbHRlcmluZywgc29ydGluZywgZ3JvdXBpbmcgYW5kIHNpbXBsZSBudW1lcmljIHN1bW1hcmllcyBnZW5lcmFsbHkgd29yayBmaW5lIHdpdGggZHBseXIgdmVyYnM6DQoNCmBgYHtyIGNodW5rMTB9DQpjZGlzdF9sYV9ydGJsICU+JSANCiAgZmlsdGVyKGdlb2lkID09ICIwNjMyIikgJT4lIA0KICBncm91cF9ieShzY2VuYXJpbywgZ2NtLCBjdmFyKSAlPiUgDQogIHN1bW1hcml6ZShtZWFuX3RlbXAgPSBtZWFuKHZhbCwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQpcDQoNCioqUHJvIFRpcDoqKg0KDQotIFlvdSBjYW4gJ2NvbnZlcnQnIGEgUmVtb3RlIFRpYmJsZSB0byBhIHJlZ3VsYXIgaW4tbWVtb3J5IFRpYmJsZSBieSB0YWNraW5nIG9uIGBjb2xsZWN0KClgIGF0IHRoZSBlbmQgb2YgYSBkcGx5ciBleHByZXNzaW9uLg0KDQpcDQoNCklmIHlvdXIgd3JhbmdsaW5nIHdvcmtmbG93IGludm9sdmVzIGEgbG90IHN0ZXBzIHRoYXQgYXJlIGRpZmZpY3VsdCBvciBpbXBvc3NpYmxlIHRvIGRvIHdpdGggcmVtb3RlIHRpYmJsZXMsIGEgZ29vZCBzdHJhdGVneSBpcyB0byBkbyB5b3VyIGZpbHRlcmluZyBhbmQgZ3JvdXBpbmcgd2l0aCBkcGx5ciBzdGF0ZW1lbnRzIG9uIHRoZSByZW1vdGUgdGliYmxlLCBhbmQgdGhlbiBjb252ZXJ0IHRoZSByZXN1bHRzIHRvIGEgcmVndWxhciB0aWJibGUgd2l0aCBgY29sbGVjdCgpYC4NCg0KQmVsb3cgd2UgY29udmVydCB0aGUgZ3JvdXBlZCBzdW1tYXJ5IHRhYmxlIGludG8gYSB0aWJibGUgc28gd2UgY2FuIHVzZSBgcGl2b3Rfd2lkZXIoKWAgKHdoaWNoIGRvZXNuJ3Qgd29yayBvbiByZW1vdGUgdGliYmxlcyk6DQoNCmBgYHtyIGNodW5rMTF9DQp0ZW1wX2xvbmdfdGJsIDwtIGNkaXN0X2xhX3J0YmwgJT4lIA0KICBmaWx0ZXIoZ2VvaWQgPT0gIjA2MzIiKSAlPiUgDQogIGdyb3VwX2J5KHNjZW5hcmlvLCBnY20sIGN2YXIpICU+JSANCiAgc3VtbWFyaXplKG1lYW5fdGVtcCA9IG1lYW4odmFsLCBuYS5ybSA9IFRSVUUpKSAlPiUgDQogIGNvbGxlY3QoKQ0KDQpjbGFzcyh0ZW1wX2xvbmdfdGJsKQ0KDQp0ZW1wX3dpZGVfdGJsIDwtIHRlbXBfbG9uZ190YmwgJT4lIA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY3ZhciwgdmFsdWVzX2Zyb20gPSBtZWFuX3RlbXApICU+JSANCiAgbXV0YXRlKHRhc19yYW5nZSA9IHRhc21heCAtIHRhc21pbikNCg0KdGVtcF93aWRlX3RibCAlPiUgaGVhZCgpDQpgYGANCg0KXA0KDQojIyMgQ2hhbGxlbmdlDQoNCkNyZWF0ZSBhIGhpc3RvZ3JhbSBvZiB0aGUgbWVhbiBkYWlseSB0ZW1wZXJhdHVyZXMgZm9yIG9uZSBDb25ncmVzc2lvbmFsIERpc3RyaWN0IGFuZCBvbmUgZW1pc3Npb25zIHNjZW5hcmlvLCBncm91cGluZyB0aGUgZGF0YSBieSBHQ00uIERvZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBtZWFuIGF2ZXJhZ2UgdGVtcGVyYXR1cmUgbG9vayB0aGUgc2FtZSBhY3Jvc3MgR0NNcz8gDQoNCmBgYHtyIGNodW5rMTJ9DQojIyBZb3VyIGFuc3dlciBoZXJlDQoNCmBgYA0KDQpcDQoNCg0K