├── .gitignore ├── 01-intro.Rmd ├── 02-R_basics.Rmd ├── 03-geoprocessing.Rmd ├── 04-maps.Rmd ├── 05-summary.Rmd ├── 06-references.Rmd ├── FOSS4G2019_Geoprocessing_with_R_workshop.Rproj ├── LICENCE.md ├── Makefile ├── README.md ├── _bookdown.yml ├── _bookdown_files ├── FOSS4G2019_Geoprocessing_with_R_workshop_cache │ └── html │ │ ├── __packages │ │ ├── nice-fig_15ac5ab5c056a4bc7340a640d858d055.RData │ │ ├── nice-fig_15ac5ab5c056a4bc7340a640d858d055.rdb │ │ ├── nice-fig_15ac5ab5c056a4bc7340a640d858d055.rdx │ │ ├── nice-tab_9fe9d6117b6a923f16c068132c74ab5d.RData │ │ ├── nice-tab_9fe9d6117b6a923f16c068132c74ab5d.rdb │ │ ├── nice-tab_9fe9d6117b6a923f16c068132c74ab5d.rdx │ │ ├── session_info_7b3623ed836e7d0cfb4572abed2aa607.RData │ │ ├── session_info_7b3623ed836e7d0cfb4572abed2aa607.rdb │ │ ├── session_info_7b3623ed836e7d0cfb4572abed2aa607.rdx │ │ ├── unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.RData │ │ ├── unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.rdb │ │ └── unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.rdx └── FOSS4G2019_Geoprocessing_with_R_workshop_files │ └── figure-html │ ├── ggplot-1.png │ ├── nice-fig-1.png │ ├── quick_plot-1.png │ ├── scale_vidiris-1.png │ ├── theme-1.png │ ├── tmap_decorations-1.png │ ├── tmap_polygons-1.png │ ├── tmap_sidemaps-1.png │ └── unnamed-chunk-1-1.png ├── _output.yml ├── book.bib ├── docs ├── .nojekyll ├── FOSS4G2019_Geoprocessing_with_R_workshop_files │ └── figure-html │ │ ├── ggplot-1.png │ │ ├── ggplot_multiple_layer-1.png │ │ ├── quick_plot-1.png │ │ ├── scale_vidiris-1.png │ │ ├── theme-1.png │ │ ├── tmap_decorations-1.png │ │ ├── tmap_polygons-1.png │ │ ├── tmap_sidemaps-1.png │ │ └── with_cartography-1.png ├── final-words.html ├── geoprocessing-in-r.html ├── images │ ├── 01_tidyverse_data_science.png │ ├── QGIS_r_intro_5.png │ ├── Rlogo.png │ ├── cartography_example.png │ ├── caution.png │ ├── data.table.png │ ├── important.png │ ├── note.png │ ├── r_qgis_puzzle.png │ ├── sf_logo.gif │ ├── tip.png │ ├── venn-clip-1.png │ └── warning.png ├── index.html ├── intro.html ├── libs │ ├── Proj4Leaflet-1.0.1 │ │ ├── proj4-compressed.js │ │ └── proj4leaflet.js │ ├── gitbook-2.6.7 │ │ ├── css │ │ │ ├── fontawesome │ │ │ │ └── fontawesome-webfont.ttf │ │ │ ├── plugin-bookdown.css │ │ │ ├── plugin-fontsettings.css │ │ │ ├── plugin-highlight.css │ │ │ ├── plugin-search.css │ │ │ ├── plugin-table.css │ │ │ └── style.css │ │ └── js │ │ │ ├── app.min.js │ │ │ ├── jquery.highlight.js │ │ │ ├── lunr.js │ │ │ ├── plugin-bookdown.js │ │ │ ├── plugin-fontsettings.js │ │ │ ├── plugin-search.js │ │ │ └── plugin-sharing.js │ ├── htmlwidgets-1.3 │ │ └── htmlwidgets.js │ ├── jquery-2.2.3 │ │ └── jquery.min.js │ ├── leaflet-1.3.1 │ │ ├── images │ │ │ ├── layers-2x.png │ │ │ ├── layers.png │ │ │ ├── marker-icon-2x.png │ │ │ ├── marker-icon.png │ │ │ └── marker-shadow.png │ │ ├── leaflet.css │ │ └── leaflet.js │ ├── leaflet-binding-2.0.2 │ │ └── leaflet.js │ ├── leaflet-providers-1.1.17 │ │ └── leaflet-providers.js │ ├── leaflet-providers-plugin-2.0.2 │ │ └── leaflet-providers-plugin.js │ ├── leafletfix-1.0.0 │ │ └── leafletfix.css │ └── rstudio_leaflet-1.3.1 │ │ └── rstudio_leaflet.css ├── maps-are-plots.html ├── r-basics.html ├── references.html ├── search_index.json └── style.css ├── foss4g_R_workshop.gpkg ├── images ├── 01_tidyverse_data_science.png ├── QGIS_r_intro_5.png ├── Rlogo.png ├── cartography_example.png ├── caution.png ├── data.table.png ├── important.png ├── note.png ├── r_qgis_puzzle.png ├── sf_logo.gif ├── tidyverse.png ├── tip.png ├── venn-clip-1.png └── warning.png ├── index.Rmd ├── packages.bib ├── preamble.tex └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | <<<<<<< HEAD 2 | .Rproj.user 3 | .Rhistory 4 | .RData 5 | .Ruserdata 6 | ======= 7 | # History files 8 | .Rhistory 9 | .Rapp.history 10 | 11 | # Session Data files 12 | .RData 13 | 14 | # Example code in package build process 15 | *-Ex.R 16 | 17 | # Output files from R CMD build 18 | /*.tar.gz 19 | 20 | # Output files from R CMD check 21 | /*.Rcheck/ 22 | 23 | # RStudio files 24 | .Rproj.user/ 25 | 26 | # produced vignettes 27 | vignettes/*.html 28 | vignettes/*.pdf 29 | 30 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 31 | .httr-oauth 32 | 33 | # knitr and R markdown default cache directories 34 | /*_cache/ 35 | /cache/ 36 | 37 | # Temporary files created by R markdown 38 | *.utf8.md 39 | *.knit.md 40 | 41 | # Shiny token, see https://shiny.rstudio.com/articles/shinyapps.html 42 | rsconnect/ 43 | >>>>>>> a6bbcd9fb6df1b71d036bc9ad3e0a09dc2f2955e 44 | -------------------------------------------------------------------------------- /01-intro.Rmd: -------------------------------------------------------------------------------- 1 | # Introduction {#intro} 2 | 3 | R is a programming language dedicated to statistics and data analysis. 4 | 5 | ![R logo](images/Rlogo.png) 6 | 7 | ## Why R ? 8 | 9 | * R is tailor made for data science 10 | * Great for reproductibility (scripts, project) 11 | * Do everything from the analysis to the reporting in one tool (thanks to [Rmarkdown](https://bookdown.org/yihui/rmarkdown/)) 12 | 13 | ### R in GIS 14 | Can we do GIS in R ? Yes ! 15 | 16 | And we can do R in GIS too ! 17 | 18 | #### R spatial 19 | 20 | There is several tools for handling spatial data in R. 21 | Historically, there was {sp}, {rgdal}, {rgeos} as core packages for geospatial data handling and dedicated packages for more advanced processing. 22 | 23 | The {sf} package released a couple years ago is a modernisation of thoses packages. It connects directly to GDAL, GEOS and PROJ libraries and implements the [Simple Features Access](https://en.wikipedia.org/wiki/Simple_Features) into R. It is compatible with the [Tidyverse](https://www.tidyverse.org/) collection of R packages (more on that later). 24 | 25 | ![{sf} logo](images/sf_logo.gif) 26 | 27 | See [r-spatial.github.io/sf](https://r-spatial.github.io/sf/) for more informations about {sf}. 28 | 29 | 30 | #### R in QGIS 31 | 32 | Since Sextante first release, you can use R scripts in QGIS Processing toolbox ! 33 | 34 | ![R script in QGIS](images/QGIS_r_intro_5.png) 35 |

Use R scripts in Processing.

36 | 37 | See the [R intro in the official documentation](https://docs.qgis.org/3.4/en/docs/training_manual/processing/r_intro.html) 38 | 39 | #### RQGIS 40 | [RQGIS](https://jannes-m.github.io/RQGIS/index.html) is R package that provides access to QGIS functionnality within the R environnement. 41 | 42 | ![RQGIS](images/r_qgis_puzzle.png) 43 | 44 | ### RSAGA 45 | 46 | There is also the [RSAGA](https://github.com/r-spatial/RSAGA) package to access SAGA processing tools within R. 47 | 48 | ### GRASS 49 | 50 | You can use R in GRASS or GRASS in R too : see the [GRASS wiki](https://grasswiki.osgeo.org/wiki/R_statistics#How_to_use) 51 | 52 | So there is a lot of connexions between R and the GIS world. In the R data science context, it becomes **geodata science** and adds tools to understand and visualize the dataset. 53 | 54 | 55 | ## Base R, Tidyverse and data.table 56 | 57 | 58 | Base R is a set of functions shipped when you install R. Some of those functions were written by different people, not always developers, so even it is powerful it is not homogenous in the syntax or not always efficient (**avoid writing for loops in R**). 59 | 60 | > As a language, R is like French; it has an elegant core, but every rule comes with a set of ad-hoc exceptions that directly contradict it. 61 | http://r.cs.purdue.edu/pub/ecoop12.pdf 62 | 63 | This critisism lead people to create packages to mitigate those issues. 64 | 65 | The Tidyverse is a set of homogenous packages, providing a coherent syntax around verbs (*filter*, *select*, etc) and the possibility to pipe operations. 66 | 67 | ![Tidyverse packages](images/01_tidyverse_data_science.png) 68 |

Data processing with R tidyverse - Ginolhac and al. 2017.

69 | 70 | It aims to provide readibility and understanding rather than performance (althought it sometimes provides both). 71 | 72 | The Tidyverse is modular as you can load each packages separatly. We'll use mostly the {dplyr} package in this workshop. 73 | 74 | data.table in the other end was created to be more efficient and can easily [compete with Python Pandas for example](https://h2oai.github.io/db-benchmark/). 75 | data.table can handle very large datasets. Its syntax is close to Python Pandas but less readible by non programmers. 76 | 77 | ![data.table logo](images/data.table.png) 78 | 79 | It is not closed worlds. You can mix all of these in your script like [Suzan Baert](https://suzan.rbind.io/) explained at [SatRday Paris 2019](https://youtu.be/vSU3o3c0-7U?t=1923). 80 | 81 | You can even mix R with Python if you need to with the Rpackage [reticulate](https://rstudio.github.io/reticulate/) or [rpy2](https://rpy2.readthedocs.io). 82 | 83 | This document is based on geodata handling with {sf} and {dplyr} (from the Tidyverse toolset). 84 | 85 | This can be followed on Rstudio or Jupyter R notebook. -------------------------------------------------------------------------------- /02-R_basics.Rmd: -------------------------------------------------------------------------------- 1 | # R basics 2 | 3 | How to manipulate data in R ? How to install and load a package ? Let's see.. 4 | 5 | ## Getting some help 6 | 7 | ## Where am I ? 8 | 9 | To get the current directory, use `getwd()` : 10 | 11 | ```{r getwd} 12 | getwd() 13 | ``` 14 | 15 | If you need to change the directory, there is `setwd()` 16 | 17 | ```{r setwd, eval=FALSE} 18 | setwd("path/to/my/directory") 19 | ``` 20 | 21 | 22 | If you use Rstudio, I can only recommand to work with a [project workflow](https://www.tidyverse.org/articles/2017/12/workflow-vs-script/) to avoid path issues on another computer. 23 | 24 | ## Make calculations 25 | 26 | ```{r calculations} 27 | 1+1 28 | 29 | 3 * 4 30 | 31 | 7/3 32 | 33 | 7%%3 # rest of the division 34 | 35 | ``` 36 | ## Arthmetic functions 37 | R provides a lot of arithmetic functions by default : 38 | 39 | ```{r arithmetic_functions} 40 | sqrt(4.0) 41 | abs(-625) 42 | log10(12900) 43 | ``` 44 | 45 | ## Assign values to a variable 46 | 47 | ```{r fruits} 48 | fruits <- c("apples", "pears", "lemons") 49 | fruits 50 | ``` 51 | 52 | 53 | ```{r quantities} 54 | quantities <- c(3, 2, 1) 55 | print(quantities) 56 | ``` 57 | 58 | ```{block2, type='rmdcaution'} 59 | Indices in R start at 1 ! 60 | ``` 61 | 62 | ```{r show_indices} 63 | print(fruits[1]) 64 | print(fruits[0]) # returns nothing 65 | ``` 66 | 67 | ## For loop and print 68 | ### Simple for loop 69 | ```{r print} 70 | for (fruit in fruits) { 71 | print(fruit) 72 | } 73 | ``` 74 | 75 | ### For loop with indices 76 | 77 | ```{r loop_indices} 78 | for (x in seq(length(fruits))) { 79 | print(paste0("I have ", quantities[x]," ", fruits[x],".")) 80 | } 81 | ``` 82 | 83 | ```{block2, type='rmdwarning'} 84 | For loops in R are possible but not memory efficient. 85 | So if you need to walk through a large amount of data, please consider using functions instead. 86 | ``` 87 | ## Data types 88 | 89 | ### Vectors 90 | `fruits` and `quantities` are character and numeric vectors. 91 | 92 | ```{r, vectors} 93 | class(fruits) 94 | class(quantities) 95 | ``` 96 | 97 | Vectors are the most basic R data object. There is six types of atomic vectors: logical, integer, double, complex, character and raw. You can't mix types in vectors. 98 | 99 | ### Dataframes 100 | 101 | Another frequently encountered data type is the **dataframe**. It is a collection data organized by rows and columns. Columns that can be of different types. Rows don't have to unique but having [tidy data](https://cran.r-project.org/web/packages/tidyr/vignettes/tidy-data.html) is known as a good pratice : 102 | 103 | 104 | > 1. Each variable forms a column. 105 | 1. Each observation forms a row. 106 | 1. Each type of observational unit forms a table. 107 | 108 | Good thing is, in GIS, we tend to have tidy data, right ? 109 | 110 | How to create a data frame from our vectors ? 111 | 112 | #### With `cbind.data.frame()` 113 | 114 | 115 | ```{r build_dataframe} 116 | df1 <- cbind.data.frame(fruits, quantities) # column binding 117 | print(df1) 118 | class(df1) 119 | ``` 120 | 121 | 122 | ```{r build_dataframe2} 123 | df2 <- as_data_frame(fruits) # column binding 124 | colnames(df2) <- "fruits" # change column name 125 | print(df2) 126 | class(df2) 127 | ``` 128 | ```{block2, type='rmdnote'} 129 | Tibbles (`tbl` // `tbl_df`) are dataframes on steroids from the tidyverse. 130 | ``` 131 | 132 | ### Add columns to a dataframe 133 | ```{r, add_column_to_df} 134 | 135 | df3 <- cbind(df2, # entry dataframe 136 | quantities, # column with quantities 137 | price = c(4,7,9) # new colum with price 138 | ) 139 | df3 140 | ``` 141 | 142 | 143 | 144 | ### Other datatypes 145 | 146 | * Matrices 147 | * Lists (`list()`) : collection of objects of different kind 148 | 149 | ```{block2, type='rmdcaution'} 150 | List in R are not like lists in Python. 151 | ``` 152 | 153 | ## Filtering / Subsetting 154 | 155 | In R, you can subset your data by value or variable. There is several way to do it, here is some of them. 156 | 157 | 158 | ### Select variables 159 | 160 | ```{r, get_colnames} 161 | names(df3) 162 | ``` 163 | 164 | ```{r select_indices} 165 | df3[, 2:3] 166 | df3[, c("fruits","price")] 167 | df3 %>% # pipe symbol 168 | select(fruits, quantities) # select from dplyr 169 | ``` 170 | 171 | ### Filter values 172 | 173 | ```{r filtering_data} 174 | df3[df3["price"] > 5,] # don't forget the column comma 175 | 176 | df3 %>% 177 | filter(quantities >= 2) 178 | ``` 179 | ### Mixing selection and filtering 180 | 181 | ```{r mix_select_filter} 182 | 183 | df3[df3["price"] > 5, 1] # select the prices > 5 184 | 185 | df3 %>% 186 | filter(price > 5) %>% # filter first 187 | select(fruits) # select second 188 | ``` 189 | 190 | 191 | ## Joins 192 | 193 | Let's create a new dataframe to join 194 | 195 | ```{r df4} 196 | df4 <- cbind.data.frame(fruits = fruits, buyer = c("Sophie", "Marc", "Nathan")) 197 | df4 198 | ``` 199 | 200 | ### Merge 201 | 202 | ```{r merger_left} 203 | merged_df <- merge(x = df3, y = df4, by = "fruits", all = TRUE) # OUTER JOIN 204 | merged_df 205 | ``` 206 | 207 | 208 | See that [answer on StackOverflow](https://stackoverflow.com/questions/1299871/how-to-join-merge-data-frames-inner-outer-left-right) for more details on left, right, inner and outer joins with `merge()`. 209 | 210 | ### Dplyr 211 | 212 | ```{r dplyr_join} 213 | merged_df <- df3 %>% 214 | full_join(df4) ## or full_join(df4, by = "fruits") 215 | 216 | merged_df 217 | ``` 218 | 219 | See the [documentation of {dplyr}](https://dplyr.tidyverse.org/reference/join.html) for more information on joins. 220 | 221 | ## Going further 222 | 223 | If you want to go further in the learning of the R language and the Tidyverse tools, there is a lot of resources online. You might want to start by those : 224 | 225 | * Base R : [R manuals](https://colinfay.me/r-manuals/) 226 | * Tidyverse : [R for Data Science (free ebook)](https://r4ds.had.co.nz) 227 | 228 | 229 | -------------------------------------------------------------------------------- /03-geoprocessing.Rmd: -------------------------------------------------------------------------------- 1 | # Geoprocessing in R 2 | 3 | For this part, we will use mostly {sf} capabilities. Most spatial functions (if not all) start with the `st_` (*for spatial type*) prefix like in [PostGIS](https://postgis.net/docs/manual-2.5/reference.html). 4 | 5 | We will focus on vector data from the {spData} package. 6 | 7 | ```{r libraries} 8 | library(dplyr) 9 | library(sf) 10 | library(spData) 11 | library(here) 12 | ``` 13 | 14 | 15 | ## Read / write 16 | {sf} provides the `st_read` and `st_write` functions to access geospatial files. They can operate with any [vector driver provided by GDAL](https://gdal.org/drivers/vector/index.html). 17 | 18 | We will use the data from the {spData}^[More details on the datasets here : [https://cran.r-project.org/web/packages/spData/spData.pdf](https://cran.r-project.org/web/packages/spData/spData.pdf)] package. Let's see what it contains : 19 | 20 | ```{r spData_files} 21 | list.files(system.file("shapes", package = "spData")) 22 | ``` 23 | 24 | We will work on cycle hires in London so let's get that data. 25 | 26 | ### Cycle hire dataset 27 | 28 | ```{r load_hire_data} 29 | cycle_hire <- st_read(system.file("shapes/cycle_hire.geojson", package="spData")) 30 | ``` 31 | 32 | Here we can see a couple of functions : 33 | 34 | * `st_read()` is the reading function from {sf} 35 | * `system.file()` is a function that allow us to look for data in packages, independently of the operating system. 36 | 37 | By default, {sf} provides informations when loading the dataset. We can see it contains 742 features and 5 fields. It is points with lat/lon coordinates (we can see it through dataset SRID : 4326). {sf} also provides the bounding box and if possible the proj4string. 38 | 39 | Here is the description of the dataset we can find in the documentation: 40 | 41 | ```{block2, type='rmdnote'} 42 | **cycle_hire dataset** 43 | 44 | ~Description:~ Points representing cycle hire points accross London. 45 | 46 | ~Format:~ 47 | 48 | * **id** Id of the hire point 49 | * **name** Name of the point 50 | * **area** Area they are in 51 | * **nbikes** The number of bikes currently parked there 52 | * **nempty** The number of empty places 53 | * *geometry* sfc_POINT 54 | 55 | ~Source~: [cyclehireapp.com/cyclehirelive/cyclehire.csv](cyclehireapp.com/cyclehirelive/cyclehire.csv) 56 | ``` 57 | 58 | 59 | We can see that there is the bike parked, the count of empty slots but not the total amount of bike slots. Let's create a new `slots` column for this. 60 | 61 | ```{r create_bike_slots} 62 | cycle_hire <- cycle_hire %>% 63 | mutate(slots = nbikes + nempty) 64 | ``` 65 | 66 | Let's load polygon data, in this case London's boroughs stored in the *lnd* dataset. 67 | 68 | ### Boroughs of London 69 | 70 | This dataset is contained in a R data format so the loading is different. 71 | 72 | ```{r loading_lnd} 73 | data(lnd) # load the dataset in memory 74 | lnd # call the dataset to visualise the 10 first features 75 | ``` 76 | 77 | We can see this dataset contains 33 features and 7 fields, in lat/lon coordinates too. 78 | 79 | ```{block2, type='rmdnote'} 80 | **ldn dataset** 81 | 82 | The boroughs of London 83 | 84 | Description : Polygons representing large administrative zones in London 85 | 86 | Format: 87 | 88 | * **NAME** Borough name 89 | * **GSS_CODE** Official code 90 | * **HECTARES** How many hectares 91 | * **NONLD_AREA** Area outside London 92 | * **ONS_INNER** Office for national statistics code 93 | * **SUB_2009** Empty column 94 | * **SUB_2006** Empty column 95 | * *geometry* sfc_MULTIPOLYGON 96 | 97 | Source : [https://github.com/Robinlovelace/Creating-maps-in-R](https://github.com/Robinlovelace/Creating-maps-in-R) 98 | ``` 99 | 100 | In order to ease spatial calculations, let's reproject them. 101 | 102 | ## Reprojection {#reprojection} 103 | 104 | The [Ordnance Survey National Grid](https://en.wikipedia.org/wiki/Ordnance_Survey_National_Grid) is the official one for Great Britain. Its SRID is **EPSG:27700**. 105 | 106 | ```{r data_reprojection} 107 | cycle_hire_27700 <- cycle_hire %>% 108 | st_transform(crs = st_crs(27700)) 109 | 110 | london_27700 <- lnd %>% 111 | st_transform(crs = st_crs(27700)) 112 | ``` 113 | 114 | TO reproject, we used 2 functions: 115 | - `st_transform()` for the reprojection 116 | - `st_crs()` to get CRS definition from EPSG code 117 | 118 | We also use the pipe operator : `%>%`, it is useful to pipe data to another function. This is provided by the [{magrittr} package](https://cran.r-project.org/web/packages/magrittr/index.html) through {dplyr} and {sf}. 119 | 120 | Now, we can create a quick map to visualize our data. We can use the `plot()` function to do this. This function is part of base R. 121 | 122 | ```{r quick_plot} 123 | plot(london_27700$geometry) # we just want to plot the geometry column 124 | plot(cycle_hire_27700$geometry, 125 | col = "red", # color 126 | cex = 0.5, # size of symbol 127 | add = TRUE) # important parameter to create multilayer plots 128 | ``` 129 | 130 | 131 | ## Joins 132 | We can use two ways to link those datasets together, by attributes, they share their area name (`area` and `NAME`) or spatially. For the sake of the exercice, let's do both. 133 | 134 | ### Join by attributes 135 | 136 | Let's join them with a inner join to see how many have corresponding 137 | 138 | ```{r inner_attribute_join} 139 | cycle_hire_27700 %>% inner_join( 140 | london_27700 %>% 141 | st_drop_geometry(), # we don't need the geometry here 142 | by = c( "area" = "NAME") 143 | 144 | ) 145 | ``` 146 | 147 | 148 | We can see that only 33 features matched. That's poor, let's try this spatially. 149 | 150 | ### Spatial join 151 | 152 | For this, we will try to provide a `GSS_CODE` for all cycle hire points. We will regroup the data afterwards. 153 | 154 | For this, we will select only the `GSS_CODE` column from `london_27700` with the `select` function from {dplyr}, the geometry will follow. 155 | 156 | ```{r spatial_join} 157 | cycle_hire_27700 <- cycle_hire_27700 %>% st_join(london_27700 %>% select(GSS_CODE)) 158 | ``` 159 | 160 | Now if we look at our dataset, there is a `GSS_CODE` column. 161 | 162 | ```{r names_cycle_hire} 163 | names(cycle_hire_27700) 164 | ``` 165 | 166 | How many points doesn't have a GSS_code ? 167 | 168 | ```{r controle_nas} 169 | cycle_hire_27700 %>% filter(is.na(GSS_CODE)) 170 | ``` 171 | 172 | Only one, that's more better than before ! I don't know well enough London to fix this. But that is not blocking. 173 | 174 | Now to paraphrase Anita Graser : [[@graserAggregate]](https://anitagraser.com/2017/06/08/aggregate-all-the-things-qgis-expression-edition/) 175 | 176 | ## Aggregation 177 | ### Count 178 | 179 | ```{r aggregation_count} 180 | cycle_hire_by_area <- cycle_hire_27700 %>% 181 | filter(!is.na(GSS_CODE)) %>% # remove NAs 182 | st_drop_geometry() %>% # let's put geometry aside 183 | group_by(GSS_CODE) %>% # group data by GSS_CODE 184 | tally(name = "count", sort= TRUE) # Aggregate 185 | cycle_hire_by_area 186 | ``` 187 | 188 | 189 | ### Sum 190 | 191 | ```{r aggregation_sum} 192 | cycle_hire_by_area_sum <- cycle_hire_27700 %>% 193 | filter(!is.na(GSS_CODE)) %>% # remove NAs 194 | st_drop_geometry() %>% # let's put geometry aside 195 | group_by(GSS_CODE) %>% # group data by GSS_CODE 196 | summarise(sum = sum(nbikes), count = n()) # Aggregate 197 | cycle_hire_by_area_sum 198 | ``` 199 | 200 | We could have use the base function `aggregate()` which works with {sf} objects. 201 | 202 | ```{r aggregate_alternative} 203 | aggregate(cycle_hire_27700["nbikes"], by = list(cycle_hire_27700$"GSS_CODE"), 204 | FUN = sum, na.rm = TRUE) 205 | ``` 206 | 207 | If we want to represents our data with proportionnal symbols, we might want to have centroids. {sf} provides two functions in order to do that: 208 | 209 | * `st_centroid()` 210 | * `st_point_on_surface()` 211 | 212 | `st_point_on_surface()` provides a point randomly **in** the entry shape. That can be useful for irregular shapes where the centroid might be outside the shape. 213 | 214 | ## Centroids 215 | 216 | ```{r centroids} 217 | boroughs_centroids <- london_27700 %>% 218 | select(NAME, GSS_CODE) %>% # only keep useful columns 219 | st_centroid() 220 | 221 | ``` 222 | You can also do buffers and other geometrical operations like [`st_union()`](https://r-spatial.github.io/sf/reference/geos_combine.html) to merge geometries 223 | 224 | ![Spatial equivalents of logical operators [@lovelace_geocomputation_2019]](images/venn-clip-1.png) 225 | 226 | 227 | ## Geometric binary predicates 228 | 229 | {sf} provides numerous geometric binary predicates that can be used with the intersection function. 230 | 231 | * st_intersects() 232 | * st_disjoint() 233 | * st_touches() 234 | * st_crosses() 235 | * st_within() 236 | * st_contains() 237 | * st_contains_properly() 238 | * st_overlaps() 239 | * st_equals() 240 | * st_covers() 241 | * st_covered_by() 242 | * st_equals_exact() 243 | * st_is_within_distance() 244 | 245 | You can use it alone or with ̀st_join()`. 246 | 247 | For example, if we want to the cycle hires contained in the borough of Wandsworth, we will do like this. 248 | 249 | ```{r find_E09000032} 250 | london_27700 %>% 251 | filter(NAME == "Wandsworth") %>% 252 | st_contains(cycle_hire_27700) 253 | ``` 254 | 255 | That will return a list of cycle hire points id. 256 | 257 | In contrary, if we want to find in which borough the hire point with id 614 is we need to do this : 258 | 259 | ```{r borough_of_614} 260 | cycle_hire_27700 %>% filter(id == "614") %>% 261 | st_within(london_27700) # borough at index 22 262 | ``` 263 | 264 | To get the borough data, there is some more work to do. 265 | 266 | ```{r get_borough22} 267 | london_27700[unlist(cycle_hire_27700 %>% filter(id == "614") %>% st_within(london_27700)),] 268 | ``` 269 | 270 | ## Saving results 271 | 272 | 273 | In the first part, we saw that we can read data but we can also write it ! 274 | 275 | ### Writing data 276 | 277 | To write data, we will use the `st_write()` function. 278 | It takes the data source name (*dsn*) as mandatory argument, {sf} will try to find the good driver from the extension (here it is *gpkg* for GeoPackage). 279 | 280 | ```{block2, type='rmdwarning'} 281 | *st_write()* can't save non geospatial data. So we need to join the data from cycle_hire_by_area_sum to 282 | the boroughs first. 283 | ``` 284 | 285 | As we want to save it to GeoPackage^[Because [GeoPackage are cool !](http://switchfromshapefile.org/#geopackage)], we also need to provide a layer name : *london_boroughs_27700*. Repeat for all data you want to save. 286 | 287 | ```{r write_geodata} 288 | 289 | london_27700 %>% left_join(cycle_hire_by_area_sum) %>% 290 | st_write( 291 | dsn = here("foss4g_R_workshop.gpkg"), 292 | layer = "london_boroughs_27700", 293 | layer_options = "OVERWRITE=true") 294 | 295 | boroughs_centroids %>% 296 | left_join(cycle_hire_by_area_sum) %>% 297 | st_write( 298 | dsn = here("foss4g_R_workshop.gpkg"), 299 | layer = "boroughs_centroids_27700", 300 | layer_options = "OVERWRITE=true") 301 | 302 | 303 | cycle_hire_27700 %>% 304 | left_join(cycle_hire_by_area_sum) %>% 305 | st_write( 306 | dsn = here("foss4g_R_workshop.gpkg"), 307 | layer = "cycle_hire_27700", 308 | layer_options = "OVERWRITE=true") 309 | ``` 310 | 311 | ```{block2, type='rmdnote'} 312 | We used the `here()` function as it preserve the project file hierarchy. It works better in Rstudio but it is still useful with Jupyter notebooks. 313 | 314 | The data set where joined by their GSS_CODE. You can specify the "by" statement, but for the sake of readability, it is not show here. 315 | 316 | The `layer_options = "OVERWRITE=true"` ensure you can write on existing layer, it is optionnal. 317 | ``` 318 | 319 | 320 | ```{r here} 321 | print(here()) # print the project directory 322 | list.files(here()) # list the files in the project directory 323 | ``` 324 | 325 | 326 | ### Check data 327 | 328 | {sf} provides a `st_layers()` function that is useful to see the content of a dataset. 329 | 330 | ```{r check_gpkg} 331 | st_layers(dsn = here("foss4g_R_workshop.gpkg")) 332 | ``` 333 | 334 | Now that we have data, let's do some maps on it in the next chapter ! 335 | 336 | 337 | 338 | 339 | -------------------------------------------------------------------------------- /04-maps.Rmd: -------------------------------------------------------------------------------- 1 | # Maps are plots ! 2 | We need to visualise our data. Visualizing geospatial data often means maps and maps are plots ! (In R) 3 | You can use plotting tools like `plot` or `ggplot2`, they all accept spatial dataframes. There is also packages to help mapping like {tmap} and {cartography}. 4 | 5 | So let's see how we do plots in R ! First we need data. 6 | 7 | ## Prepare the work 8 | ### Libraries 9 | 10 | ```{r loading_libraries} 11 | library(sf) 12 | library(here) 13 | library(dplyr) 14 | library(ggplot2) 15 | library(tmap) 16 | ``` 17 | 18 | ### Data 19 | 20 | Let's see what data we stored previously. 21 | 22 | ```{r read_database} 23 | st_layers(here("foss4g_R_workshop.gpkg")) 24 | ``` 25 | 26 | We can see our 3 datasets. We can loaded them into memory. 27 | 28 | ```{r load_data} 29 | cycle_hire_27700 <- st_read( 30 | dsn = here("foss4g_R_workshop.gpkg"), 31 | layer = "cycle_hire_27700") 32 | 33 | london_boroughs_27700 <- st_read( 34 | dsn = here("foss4g_R_workshop.gpkg"), 35 | layer = "london_boroughs_27700") 36 | 37 | boroughs_centroids_27700<- st_read( 38 | dsn = here("foss4g_R_workshop.gpkg"), 39 | layer = "boroughs_centroids_27700") 40 | ``` 41 | 42 | 43 | 44 | ## The `plot()` way 45 | 46 | You can plot any spatial dataframe. It simply works but the syntax is no easy. We did one example in \@ref(reprojection). There is several examples online if you want to go further. 47 | 48 | ## Using {ggplot} 49 | 50 | Since we are using a lot of {tidyverse} compatible package, it is logical to use {ggplot2} which is part of this toolset. The basic philosophy of ggplot is layers, first you create an empty plot with the data then you add a geometry (`geom_*()`) and some aesthetics (`aes()`) for that geometry. You can add multiple layers and add more informations (labels, titles). All those elements are linked by a `+` symbol. It is built on [A Layered Grammar of Graphics [@WickamGrammar]](https://www.tandfonline.com/doi/abs/10.1198/jcgs.2009.07098). 51 | 52 | ```{r ggplot} 53 | london_boroughs_27700 %>% # pipe data to 54 | ggplot() + # a ggplot function 55 | geom_sf( # precise that it will be a spatial geometry 56 | aes( # provide some aesthetics 57 | geometry = geom, # the geometry column (usually auto detected) 58 | fill = count) # we want the polygon color to change following the count 59 | ) -> g # store it in g 60 | 61 | g # display g 62 | ``` 63 | 64 | We can customize our map by adding thing to it. For example a viridis color scale ([friendly to common forms of colorblindness](https://bids.github.io/colormap/)). 65 | 66 | ```{r scale_vidiris} 67 | g <- g + 68 | scale_fill_viridis_c( 69 | guide = guide_legend(title = "Hires") # legend title 70 | ) 71 | g 72 | ``` 73 | 74 | We can set a theme and add titles 75 | 76 | ```{r theme} 77 | g <- g + 78 | theme_bw() + 79 | ggtitle("Cycle hire points", subtitle = "in London's boroughs") 80 | g 81 | ``` 82 | 83 | 84 | ```{r ggplot_multiple_layer} 85 | ggplot() + geom_sf(data = london_boroughs_27700) + # add boroughs shape to the map 86 | geom_sf(data = boroughs_centroids_27700, # add the boroughs centroids> 87 | aes(size = boroughs_centroids_27700$count), # fix size of points (by area) 88 | color = 'red', alpha = 1/5)+ # set points colour and transparency 89 | ggtitle("Cycle hire points", subtitle = "in London's boroughs") + # set the map title 90 | theme(legend.position = 'left') + # Legend position 91 | scale_size_area(name = 'Hires',max_size=10) # 0 value means 0 area + legend title 92 | ``` 93 | 94 | Well, the legend is not convincing me.Although it should work like in the [OSGeoLive R Quickstart](http://live.osgeo.org/en/quickstart/R_quickstart.html). 95 | 96 | And if we want to had decorations (scale bar, north arrow), we need to use a another package: [{ggspatial}](https://cran.r-project.org/web/packages/ggspatial/vignettes/ggspatial.html). 97 | 98 | Now, let's use proper packages for cartography. First {tmap} who was created before {ggplot} was able to do maps with {sf} objects. Then {cartography} who is a based on `plot()` from base R. 99 | 100 | ## Using {tmap} 101 | 102 | {tmap} was created to help people mapping when {ggplot2} was not able to plot {sf} objects^[That arrived in 2018 with the 3.0 release : https://www.tidyverse.org/articles/2018/07/ggplot2-3-0-0/] 103 | 104 | ```{r tmap_polygons} 105 | library(tmap) 106 | 107 | tm_shape(london_boroughs_27700) + 108 | tm_polygons("count") 109 | ``` 110 | 111 | We can see that there is a color scale for the quantity of hire points. 112 | 113 | One cool thing with {tmap}, it is that you can use 2 modes: "plot" and "view". The "view" mode is an interactive one ! Try to go over or click on polygons ! 114 | 115 | 116 | ```{r tmap_interactive} 117 | tmap_mode("view") 118 | 119 | tm_shape(london_boroughs_27700) + 120 | tm_polygons("count") 121 | ``` 122 | 123 | 124 | You can do more complex thing of course, like side by side maps or calculations. 125 | 126 | ```{r tmap_sidemaps} 127 | tmap_mode("plot") 128 | 129 | tm1 <- tm_shape(london_boroughs_27700) + tm_polygons("count", convert2density = TRUE) 130 | tm2 <- tm_shape(london_boroughs_27700) + tm_bubbles(size = "count") 131 | 132 | tmap_arrange(tm1, tm2) 133 | ``` 134 | 135 | Let's represent 2 layers in the same time : 136 | 137 | ```{r multiple_layer} 138 | tmap_mode("view") 139 | tm_basemap("Stamen.Watercolor") + 140 | tm_shape(london_boroughs_27700) + tm_polygons("count", convert2density = TRUE) + tm_bubbles(size = "count", col = "red") + 141 | tm_tiles("Stamen.TonerLabels") 142 | ``` 143 | 144 | Now we can add decorations. 145 | 146 | ```{r tmap_decorations} 147 | tmap_mode("plot") 148 | 149 | tm_shape(london_boroughs_27700) + 150 | tm_polygons("count", convert2density = TRUE) + 151 | tm_bubbles(size = "count", col = "red") + 152 | tm_scale_bar(position=c("left", "bottom")) + 153 | tm_compass(size = 2, position=c("right", "top")) 154 | ``` 155 | 156 | You can place elements more precisely by giving them position coordinates. 157 | 158 | ## With {cartography} 159 | 160 | If you want to do maps in R, please take a look at [{cartography}](http://riatelab.github.io/cartography/docs/). It is thought for doing maps and is made by geographers. The package [vignette](https://cran.r-project.org/package=cartography/vignettes/cartography.html) is very well made and provides 11 examples to cover a lot of use cases. 161 | 162 | This is one example: 163 | 164 | ![[Example from {cartography} vignette](https://cran.r-project.org/web/packages/cartography/vignettes/cartography.html)](images/cartography_example.png) 165 | 166 | ```{r with_cartography} 167 | library(cartography) 168 | 169 | # Plot the boroughs 170 | plot(st_geometry(london_boroughs_27700), col="darkseagreen3", border="darkseagreen4", 171 | bg = "lightblue1", lwd = 0.5) 172 | # Plot symbols with choropleth coloration 173 | propSymbolsChoroLayer( 174 | x = london_boroughs_27700, 175 | var = "sum", 176 | inches = 0.1, 177 | border = "grey50", 178 | lwd = 1, 179 | legend.var.pos = "topright", 180 | legend.var.title.txt = "Total bike hires", 181 | var2 = "count", 182 | method = "equal", 183 | nclass = 4, 184 | col = carto.pal(pal1 = "sand.pal", n1 = 4), 185 | legend.var2.values.rnd = -2, 186 | legend.var2.pos = "left", 187 | legend.var2.title.txt = "Number of hire points" 188 | ) 189 | # layout 190 | layoutLayer(title="Bike hires in London boroughs", 191 | author = "Nicolas Roelandt, FOSS4G 2019", 192 | sources = "Sources: spData R package, 2019", 193 | scale = 5, tabtitle = TRUE, frame = FALSE) 194 | # north arrow 195 | north(pos = "topleft") 196 | ``` 197 | 198 | 199 | This is a more complex object but we can detail it. 200 | First we create a plot of the background, the boroughs of London in green with a light blue background. 201 | 202 | Then we add a `propSymbolsChoroLayer()` who is a choroplet layer with proportionnal symbols (you can have more simple items, see the documentation). SO we need to specify 2 variables on for the symbol size (here we choose `sum`) and one for the color of the symbols. For each variable we provides some complementary parameters (color palette, classification method, title of the legend, etc.). 203 | 204 | {cartography} also provides a layout function for the map where you can insert more information : author name, date, sources, map title, position and type of the scale bar, etc.). 205 | 206 | Last but not least you can add a north arrow with the `north()` function. 207 | 208 | ```{block2, type='rmdwarning'} 209 | The size of the proportionnal circle in the legend are not at the right size. This problem appears with pdf output but for png output it disappears. 210 | ``` 211 | 212 | 213 | ```{block2, type='rmdnotes'} 214 | The easiest way to use {cartography} is to find what you want to do in the vignette, copy paste the code then adapt to your data and personalize ! 215 | ``` 216 | 217 | -------------------------------------------------------------------------------- /05-summary.Rmd: -------------------------------------------------------------------------------- 1 | # Final Words 2 | 3 | This is just a glimpse what it is possible to do with R for geospatial data analysis. There is more to discover ! You can do spatial analysis and geostatistics like spatial autocorrelation, kriging, etc. If you want to know more about it, please see [Spatial Data Science with R website](https://rspatial.org/analysis/index.html). 4 | 5 | We hope the material does help you get started with R, making it accessible for non staticians or non geographer people (the author is neither of that). R can be use alone as a full GIS, providing tools for data preparation, analysis, mapping and reporting. It can be also use in combination with other GIS tools like GRASS, SAGA or QGIS. 6 | 7 | This document has been made using the **bookdown** package [@R-bookdown] and has been inspired by [Maël Theulière bookdown tutorial "Les données spatiales avec R" (in French)](https://maeltheuliere.github.io/rspatial/index.html) and [Geocomputation with R (Lovelace, Nowosad, Muenchow)](https://geocompr.robinlovelace.net). 8 | 9 | 10 | This book was built with: 11 | 12 | ```{r session_info} 13 | 14 | devtools::session_info() 15 | ``` 16 | -------------------------------------------------------------------------------- /06-references.Rmd: -------------------------------------------------------------------------------- 1 | `r if (knitr::is_html_output()) ' 2 | # References {-} 3 | '` 4 | -------------------------------------------------------------------------------- /FOSS4G2019_Geoprocessing_with_R_workshop.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Website 16 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | ## creative commons 2 | 3 | # Attribution-NonCommercial-ShareAlike 4.0 International 4 | 5 | Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. 6 | 7 | ### Using Creative Commons Public Licenses 8 | 9 | Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. 10 | 11 | * __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). 12 | 13 | * __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). 14 | 15 | ## Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License 16 | 17 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. 18 | 19 | ### Section 1 – Definitions. 20 | 21 | a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. 22 | 23 | b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. 24 | 25 | c. __BY-NC-SA Compatible License__ means a license listed at [creativecommons.org/compatiblelicenses](http://creativecommons.org/compatiblelicenses), approved by Creative Commons as essentially the equivalent of this Public License. 26 | 27 | d. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 28 | 29 | e. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. 30 | 31 | f. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. 32 | 33 | g. __License Elements__ means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike. 34 | 35 | h. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. 36 | 37 | i. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. 38 | 39 | j. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. 40 | 41 | k. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. 42 | 43 | l. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. 44 | 45 | m. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. 46 | 47 | n. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. 48 | 49 | ### Section 2 – Scope. 50 | 51 | a. ___License grant.___ 52 | 53 | 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: 54 | 55 | A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and 56 | 57 | B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. 58 | 59 | 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 60 | 61 | 3. __Term.__ The term of this Public License is specified in Section 6(a). 62 | 63 | 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 64 | 65 | 5. __Downstream recipients.__ 66 | 67 | A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. 68 | 69 | B. __Additional offer from the Licensor – Adapted Material.__ Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. 70 | 71 | C. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 72 | 73 | 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). 74 | 75 | b. ___Other rights.___ 76 | 77 | 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 78 | 79 | 2. Patent and trademark rights are not licensed under this Public License. 80 | 81 | 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. 82 | 83 | ### Section 3 – License Conditions. 84 | 85 | Your exercise of the Licensed Rights is expressly made subject to the following conditions. 86 | 87 | a. ___Attribution.___ 88 | 89 | 1. If You Share the Licensed Material (including in modified form), You must: 90 | 91 | A. retain the following if it is supplied by the Licensor with the Licensed Material: 92 | 93 | i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); 94 | 95 | ii. a copyright notice; 96 | 97 | iii. a notice that refers to this Public License; 98 | 99 | iv. a notice that refers to the disclaimer of warranties; 100 | 101 | v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; 102 | 103 | B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and 104 | 105 | C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 106 | 107 | 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 108 | 109 | 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 110 | 111 | b. ___ShareAlike.___ 112 | 113 | In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 114 | 115 | 1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License. 116 | 117 | 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 118 | 119 | 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. 120 | 121 | ### Section 4 – Sui Generis Database Rights. 122 | 123 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: 124 | 125 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; 126 | 127 | b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and 128 | 129 | c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. 130 | 131 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. 132 | 133 | ### Section 5 – Disclaimer of Warranties and Limitation of Liability. 134 | 135 | a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ 136 | 137 | b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ 138 | 139 | c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. 140 | 141 | ### Section 6 – Term and Termination. 142 | 143 | a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. 144 | 145 | b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 146 | 147 | 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 148 | 149 | 2. upon express reinstatement by the Licensor. 150 | 151 | For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. 152 | 153 | c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. 154 | 155 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 156 | 157 | ### Section 7 – Other Terms and Conditions. 158 | 159 | a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. 160 | 161 | b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. 162 | 163 | ### Section 8 – Interpretation. 164 | 165 | a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. 166 | 167 | b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. 168 | 169 | c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. 170 | 171 | d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 172 | 173 | > Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. 174 | > 175 | > Creative Commons may be contacted at creativecommons.org 176 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | render: 2 | Rscript -e "bookdown::render_book('index.Rmd', 'bookdown::gitbook')" 3 | Rscript -e "bookdown::render_book('index.Rmd', 'bookdown::pdf_book')" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is the teaching material for the GeoProcessing with R workshop of FOSS4G 2019 - Bucarest. 2 | 3 | To be ready for the workshop, please install those packages : 4 | 5 | ```r 6 | install.packages("dplyr") 7 | install.packages("sf") 8 | install.packages("spData") 9 | install.packages("here") 10 | install.packages("ggplot2") 11 | install.packages("tmap") 12 | install.packages("cartography") 13 | ``` 14 | 15 | 16 | For [OSGeoLive](https://live.osgeo.org) users, there is already some of them installed in the distribution. 17 | Please start Jupyter Notebooks (Menu -> GeoSpatial -> Spatial Tools -> Jupyter Notebook). It should open a web page. 18 | 19 | Click on `New` in the top right and start a new R Notebook. Then install only the following packages : 20 | 21 | 22 | ```r 23 | install.packages("dplyr") 24 | install.packages("here") 25 | install.packages("tmap") 26 | install.packages("cartography") 27 | ``` 28 | 29 | # Github Pages 30 | 31 | The rendered book is visible with GitHub Pages : 32 | [https://bakaniko.github.io/FOSS4G2019_Geoprocessing_with_R_workshop/](https://bakaniko.github.io/FOSS4G2019_Geoprocessing_with_R_workshop/) 33 | 34 | # Licence 35 | 36 | This material is available on BY-NC-SA licence. 37 | 38 | # Git cloning 39 | 40 | You can clone this repo with this command : 41 | 42 | ``` 43 | git clone https://github.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/ 44 | ``` 45 | -------------------------------------------------------------------------------- /_bookdown.yml: -------------------------------------------------------------------------------- 1 | book_filename: "FOSS4G2019_Geoprocessing_with_R_workshop" 2 | delete_merged_file: true 3 | output_dir: "docs" 4 | language: 5 | label: 6 | fig: "FIGURE " 7 | tab: "TABLE " 8 | 9 | ui: 10 | chapter_name: "Chapter " 11 | -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/__packages: -------------------------------------------------------------------------------- 1 | base 2 | knitr 3 | ggplot2 4 | tidyverse 5 | tibble 6 | tidyr 7 | readr 8 | purrr 9 | dplyr 10 | stringr 11 | forcats 12 | sf 13 | tmap 14 | viridisLite 15 | viridis 16 | ggspatial 17 | mapview 18 | -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-fig_15ac5ab5c056a4bc7340a640d858d055.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-fig_15ac5ab5c056a4bc7340a640d858d055.RData -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-fig_15ac5ab5c056a4bc7340a640d858d055.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-fig_15ac5ab5c056a4bc7340a640d858d055.rdb -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-fig_15ac5ab5c056a4bc7340a640d858d055.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-fig_15ac5ab5c056a4bc7340a640d858d055.rdx -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-tab_9fe9d6117b6a923f16c068132c74ab5d.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-tab_9fe9d6117b6a923f16c068132c74ab5d.RData -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-tab_9fe9d6117b6a923f16c068132c74ab5d.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-tab_9fe9d6117b6a923f16c068132c74ab5d.rdb -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-tab_9fe9d6117b6a923f16c068132c74ab5d.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/nice-tab_9fe9d6117b6a923f16c068132c74ab5d.rdx -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/session_info_7b3623ed836e7d0cfb4572abed2aa607.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/session_info_7b3623ed836e7d0cfb4572abed2aa607.RData -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/session_info_7b3623ed836e7d0cfb4572abed2aa607.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/session_info_7b3623ed836e7d0cfb4572abed2aa607.rdb -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/session_info_7b3623ed836e7d0cfb4572abed2aa607.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/session_info_7b3623ed836e7d0cfb4572abed2aa607.rdx -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.RData -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.rdb -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_cache/html/unnamed-chunk-1_37de3a22733113362c4678cd745c5c4e.rdx -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/ggplot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/ggplot-1.png -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/nice-fig-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/nice-fig-1.png -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/quick_plot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/quick_plot-1.png -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/scale_vidiris-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/scale_vidiris-1.png -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/theme-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/theme-1.png -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_decorations-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_decorations-1.png -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_polygons-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_polygons-1.png -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_sidemaps-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_sidemaps-1.png -------------------------------------------------------------------------------- /_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/unnamed-chunk-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/_bookdown_files/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/unnamed-chunk-1-1.png -------------------------------------------------------------------------------- /_output.yml: -------------------------------------------------------------------------------- 1 | bookdown::gitbook: 2 | css: style.css 3 | config: 4 | toc: 5 | before: | 6 |
  • FOSS4G2019 Geoprocessing with R workshop
  • 7 | after: | 8 |
  • Published with bookdown
  • 9 | download: [] 10 | edit: https://github.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/edit/master/%s 11 | sharing: 12 | github: yes 13 | facebook: no 14 | bookdown::pdf_book: 15 | includes: 16 | in_header: preamble.tex 17 | latex_engine: xelatex 18 | citation_package: natbib 19 | keep_tex: yes 20 | bookdown::epub_book: default 21 | -------------------------------------------------------------------------------- /book.bib: -------------------------------------------------------------------------------- 1 | @Book{xie2015, 2 | title = {Dynamic Documents with {R} and knitr}, 3 | author = {Yihui Xie}, 4 | publisher = {Chapman and Hall/CRC}, 5 | address = {Boca Raton, Florida}, 6 | year = {2015}, 7 | edition = {2nd}, 8 | note = {ISBN 978-1498716963}, 9 | url = {http://yihui.name/knitr/}, 10 | } 11 | 12 | @Book{lovelace_geocomputation_2019, 13 | title = {Geocomputation with {{R}}}, 14 | isbn = {1-138-30451-4}, 15 | abstract = {Book on geographic data with R.}, 16 | publisher = {{CRC Press}}, 17 | author = {Lovelace, Robin and Nowosad, Jakub and Muenchow, Jannes}, 18 | year = {2019} 19 | } 20 | 21 | @misc{graserAggregate, 22 | title = {{Aggregate all the things!}}, 23 | year = {2017}, 24 | howpublished = {\url{https://anitagraser.com/2017/06/08/aggregate-all-the-things-qgis-expression-edition/}}, 25 | note = {Accessed: 2019-08-13} 26 | } 27 | 28 | @article{WickamGrammar, 29 | author = {Hadley Wickham}, 30 | title = {A Layered Grammar of Graphics}, 31 | journal = {Journal of Computational and Graphical Statistics}, 32 | volume = {19}, 33 | number = {1}, 34 | pages = {3-28}, 35 | year = {2010}, 36 | publisher = {Taylor & Francis}, 37 | doi = {10.1198/jcgs.2009.07098}, 38 | 39 | URL = { 40 | https://doi.org/10.1198/jcgs.2009.07098 41 | 42 | }, 43 | eprint = { 44 | https://doi.org/10.1198/jcgs.2009.07098 45 | 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/.nojekyll -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/ggplot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/ggplot-1.png -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/ggplot_multiple_layer-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/ggplot_multiple_layer-1.png -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/quick_plot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/quick_plot-1.png -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/scale_vidiris-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/scale_vidiris-1.png -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/theme-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/theme-1.png -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_decorations-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_decorations-1.png -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_polygons-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_polygons-1.png -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_sidemaps-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/tmap_sidemaps-1.png -------------------------------------------------------------------------------- /docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/with_cartography-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/FOSS4G2019_Geoprocessing_with_R_workshop_files/figure-html/with_cartography-1.png -------------------------------------------------------------------------------- /docs/images/01_tidyverse_data_science.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/01_tidyverse_data_science.png -------------------------------------------------------------------------------- /docs/images/QGIS_r_intro_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/QGIS_r_intro_5.png -------------------------------------------------------------------------------- /docs/images/Rlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/Rlogo.png -------------------------------------------------------------------------------- /docs/images/cartography_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/cartography_example.png -------------------------------------------------------------------------------- /docs/images/caution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/caution.png -------------------------------------------------------------------------------- /docs/images/data.table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/data.table.png -------------------------------------------------------------------------------- /docs/images/important.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/important.png -------------------------------------------------------------------------------- /docs/images/note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/note.png -------------------------------------------------------------------------------- /docs/images/r_qgis_puzzle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/r_qgis_puzzle.png -------------------------------------------------------------------------------- /docs/images/sf_logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/sf_logo.gif -------------------------------------------------------------------------------- /docs/images/tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/tip.png -------------------------------------------------------------------------------- /docs/images/venn-clip-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/venn-clip-1.png -------------------------------------------------------------------------------- /docs/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/images/warning.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | R for Geospatial Processing 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 |
    125 | 126 |
    127 | 210 |
    211 | 212 |
    213 |
    214 | 219 | 220 |
    221 |
    222 | 223 |
    224 | 229 |
    230 |

    Chapter 1 Prerequisites

    231 |

    This workshop is designed for the attendance of FOSS4G 2019. So basics knowledge in GIS is expected (simple features, projections and CRS, geometrical operations, etc.).

    232 |

    No knowledge of R is required. A minimal knowledge of (R)mardown will be a plus to take notes.

    233 |

    Please install R on your system and the following libraries.

    234 |

    Please follow installation instructions from the CRAN projet.

    235 |

    The {sf} library needs several geospatial core libraries (GDAL, GEOS, PROJ) so please follow {sf} installation instructions to be sure to have those.

    236 |

    For Ubuntu users, ThinkR published a blogpost about the installation of r 3 5 on Ubuntu 18.04 LTS and tips for spatial packages

    237 |
    install.packages("dplyr")
    238 | install.packages("sf")
    239 | install.packages("spData")
    240 | install.packages("here")
    241 | install.packages("ggplot2")
    242 | install.packages("tmap")
    243 | install.packages("cartography")
    244 |

    For OSGeoLive users, there is already some of them installed in the distribution. 245 | Please start Jupyter Notebooks (Menu -> GeoSpatial -> Spatial Tools -> Jupyter Notebook). It should open a web page.

    246 |

    Click on New in the top right and start a new R Notebook. Then install only the following packages :

    247 |
    install.packages("dplyr")
    248 | install.packages("here")
    249 | install.packages("tmap")
    250 | install.packages("cartography")
    251 |
    252 |

    1.1 About this document

    253 |

    This document had been written with the R Bookdown package and Rstudio. You can use the editor of your choice to follow the instruction, be careful on the path given by the {here} package.

    254 |

    To compile this example to PDF, you need XeLaTeX. You are recommended to install TinyTeX (which includes XeLaTeX): https://yihui.name/tinytex/.

    255 |

    You can contribute to this document on GitHub :

    256 |

    https://github.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop

    257 | 258 |
    259 |
    260 |
    261 | 262 |
    263 |
    264 |
    265 | 266 | 267 |
    268 |
    269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 310 | 311 | 312 | 313 | 314 | -------------------------------------------------------------------------------- /docs/libs/Proj4Leaflet-1.0.1/proj4leaflet.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | var L, proj4; 3 | if (typeof define === 'function' && define.amd) { 4 | // AMD 5 | define(['leaflet', 'proj4'], factory); 6 | } else if (typeof module === 'object' && typeof module.exports === "object") { 7 | // Node/CommonJS 8 | L = require('leaflet'); 9 | proj4 = require('proj4'); 10 | module.exports = factory(L, proj4); 11 | } else { 12 | // Browser globals 13 | if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined') 14 | throw 'Leaflet and proj4 must be loaded first'; 15 | factory(window.L, window.proj4); 16 | } 17 | }(function (L, proj4) { 18 | if (proj4.__esModule && proj4.default) { 19 | // If proj4 was bundled as an ES6 module, unwrap it to get 20 | // to the actual main proj4 object. 21 | // See discussion in https://github.com/kartena/Proj4Leaflet/pull/147 22 | proj4 = proj4.default; 23 | } 24 | 25 | L.Proj = {}; 26 | 27 | L.Proj._isProj4Obj = function(a) { 28 | return (typeof a.inverse !== 'undefined' && 29 | typeof a.forward !== 'undefined'); 30 | }; 31 | 32 | L.Proj.Projection = L.Class.extend({ 33 | initialize: function(code, def, bounds) { 34 | var isP4 = L.Proj._isProj4Obj(code); 35 | this._proj = isP4 ? code : this._projFromCodeDef(code, def); 36 | this.bounds = isP4 ? def : bounds; 37 | }, 38 | 39 | project: function (latlng) { 40 | var point = this._proj.forward([latlng.lng, latlng.lat]); 41 | return new L.Point(point[0], point[1]); 42 | }, 43 | 44 | unproject: function (point, unbounded) { 45 | var point2 = this._proj.inverse([point.x, point.y]); 46 | return new L.LatLng(point2[1], point2[0], unbounded); 47 | }, 48 | 49 | _projFromCodeDef: function(code, def) { 50 | if (def) { 51 | proj4.defs(code, def); 52 | } else if (proj4.defs[code] === undefined) { 53 | var urn = code.split(':'); 54 | if (urn.length > 3) { 55 | code = urn[urn.length - 3] + ':' + urn[urn.length - 1]; 56 | } 57 | if (proj4.defs[code] === undefined) { 58 | throw 'No projection definition for code ' + code; 59 | } 60 | } 61 | 62 | return proj4(code); 63 | } 64 | }); 65 | 66 | L.Proj.CRS = L.Class.extend({ 67 | includes: L.CRS, 68 | 69 | options: { 70 | transformation: new L.Transformation(1, 0, -1, 0) 71 | }, 72 | 73 | initialize: function(a, b, c) { 74 | var code, 75 | proj, 76 | def, 77 | options; 78 | 79 | if (L.Proj._isProj4Obj(a)) { 80 | proj = a; 81 | code = proj.srsCode; 82 | options = b || {}; 83 | 84 | this.projection = new L.Proj.Projection(proj, options.bounds); 85 | } else { 86 | code = a; 87 | def = b; 88 | options = c || {}; 89 | this.projection = new L.Proj.Projection(code, def, options.bounds); 90 | } 91 | 92 | L.Util.setOptions(this, options); 93 | this.code = code; 94 | this.transformation = this.options.transformation; 95 | 96 | if (this.options.origin) { 97 | this.transformation = 98 | new L.Transformation(1, -this.options.origin[0], 99 | -1, this.options.origin[1]); 100 | } 101 | 102 | if (this.options.scales) { 103 | this._scales = this.options.scales; 104 | } else if (this.options.resolutions) { 105 | this._scales = []; 106 | for (var i = this.options.resolutions.length - 1; i >= 0; i--) { 107 | if (this.options.resolutions[i]) { 108 | this._scales[i] = 1 / this.options.resolutions[i]; 109 | } 110 | } 111 | } 112 | 113 | this.infinite = !this.options.bounds; 114 | 115 | }, 116 | 117 | scale: function(zoom) { 118 | var iZoom = Math.floor(zoom), 119 | baseScale, 120 | nextScale, 121 | scaleDiff, 122 | zDiff; 123 | if (zoom === iZoom) { 124 | return this._scales[zoom]; 125 | } else { 126 | // Non-integer zoom, interpolate 127 | baseScale = this._scales[iZoom]; 128 | nextScale = this._scales[iZoom + 1]; 129 | scaleDiff = nextScale - baseScale; 130 | zDiff = (zoom - iZoom); 131 | return baseScale + scaleDiff * zDiff; 132 | } 133 | }, 134 | 135 | zoom: function(scale) { 136 | // Find closest number in this._scales, down 137 | var downScale = this._closestElement(this._scales, scale), 138 | downZoom = this._scales.indexOf(downScale), 139 | nextScale, 140 | nextZoom, 141 | scaleDiff; 142 | // Check if scale is downScale => return array index 143 | if (scale === downScale) { 144 | return downZoom; 145 | } 146 | if (downScale === undefined) { 147 | return -Infinity; 148 | } 149 | // Interpolate 150 | nextZoom = downZoom + 1; 151 | nextScale = this._scales[nextZoom]; 152 | if (nextScale === undefined) { 153 | return Infinity; 154 | } 155 | scaleDiff = nextScale - downScale; 156 | return (scale - downScale) / scaleDiff + downZoom; 157 | }, 158 | 159 | distance: L.CRS.Earth.distance, 160 | 161 | R: L.CRS.Earth.R, 162 | 163 | /* Get the closest lowest element in an array */ 164 | _closestElement: function(array, element) { 165 | var low; 166 | for (var i = array.length; i--;) { 167 | if (array[i] <= element && (low === undefined || low < array[i])) { 168 | low = array[i]; 169 | } 170 | } 171 | return low; 172 | } 173 | }); 174 | 175 | L.Proj.GeoJSON = L.GeoJSON.extend({ 176 | initialize: function(geojson, options) { 177 | this._callLevel = 0; 178 | L.GeoJSON.prototype.initialize.call(this, geojson, options); 179 | }, 180 | 181 | addData: function(geojson) { 182 | var crs; 183 | 184 | if (geojson) { 185 | if (geojson.crs && geojson.crs.type === 'name') { 186 | crs = new L.Proj.CRS(geojson.crs.properties.name); 187 | } else if (geojson.crs && geojson.crs.type) { 188 | crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code); 189 | } 190 | 191 | if (crs !== undefined) { 192 | this.options.coordsToLatLng = function(coords) { 193 | var point = L.point(coords[0], coords[1]); 194 | return crs.projection.unproject(point); 195 | }; 196 | } 197 | } 198 | 199 | // Base class' addData might call us recursively, but 200 | // CRS shouldn't be cleared in that case, since CRS applies 201 | // to the whole GeoJSON, inluding sub-features. 202 | this._callLevel++; 203 | try { 204 | L.GeoJSON.prototype.addData.call(this, geojson); 205 | } finally { 206 | this._callLevel--; 207 | if (this._callLevel === 0) { 208 | delete this.options.coordsToLatLng; 209 | } 210 | } 211 | } 212 | }); 213 | 214 | L.Proj.geoJson = function(geojson, options) { 215 | return new L.Proj.GeoJSON(geojson, options); 216 | }; 217 | 218 | L.Proj.ImageOverlay = L.ImageOverlay.extend({ 219 | initialize: function (url, bounds, options) { 220 | L.ImageOverlay.prototype.initialize.call(this, url, null, options); 221 | this._projectedBounds = bounds; 222 | }, 223 | 224 | // Danger ahead: Overriding internal methods in Leaflet. 225 | // Decided to do this rather than making a copy of L.ImageOverlay 226 | // and doing very tiny modifications to it. 227 | // Future will tell if this was wise or not. 228 | _animateZoom: function (event) { 229 | var scale = this._map.getZoomScale(event.zoom); 230 | var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y); 231 | var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center); 232 | 233 | L.DomUtil.setTransform(this._image, offset, scale); 234 | }, 235 | 236 | _reset: function () { 237 | var zoom = this._map.getZoom(); 238 | var pixelOrigin = this._map.getPixelOrigin(); 239 | var bounds = L.bounds( 240 | this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin), 241 | this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin) 242 | ); 243 | var size = bounds.getSize(); 244 | 245 | L.DomUtil.setPosition(this._image, bounds.min); 246 | this._image.style.width = size.x + 'px'; 247 | this._image.style.height = size.y + 'px'; 248 | }, 249 | 250 | _projectedToNewLayerPoint: function (point, zoom, center) { 251 | var viewHalf = this._map.getSize()._divideBy(2); 252 | var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round(); 253 | var topLeft = newTopLeft.add(this._map._getMapPanePos()); 254 | 255 | return this._transform(point, zoom)._subtract(topLeft); 256 | }, 257 | 258 | _transform: function (point, zoom) { 259 | var crs = this._map.options.crs; 260 | var transformation = crs.transformation; 261 | var scale = crs.scale(zoom); 262 | 263 | return transformation.transform(point, scale); 264 | } 265 | }); 266 | 267 | L.Proj.imageOverlay = function (url, bounds, options) { 268 | return new L.Proj.ImageOverlay(url, bounds, options); 269 | }; 270 | 271 | return L.Proj; 272 | })); 273 | -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/css/fontawesome/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bakaniko/FOSS4G2019_Geoprocessing_with_R_workshop/c02e0ed2e9f56737b3b23733ef798927eb8f4549/docs/libs/gitbook-2.6.7/css/fontawesome/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/css/plugin-bookdown.css: -------------------------------------------------------------------------------- 1 | .book .book-header h1 { 2 | padding-left: 20px; 3 | padding-right: 20px; 4 | } 5 | .book .book-header.fixed { 6 | position: fixed; 7 | right: 0; 8 | top: 0; 9 | left: 0; 10 | border-bottom: 1px solid rgba(0,0,0,.07); 11 | } 12 | span.search-highlight { 13 | background-color: #ffff88; 14 | } 15 | @media (min-width: 600px) { 16 | .book.with-summary .book-header.fixed { 17 | left: 300px; 18 | } 19 | } 20 | @media (max-width: 1240px) { 21 | .book .book-body.fixed { 22 | top: 50px; 23 | } 24 | .book .book-body.fixed .body-inner { 25 | top: auto; 26 | } 27 | } 28 | @media (max-width: 600px) { 29 | .book.with-summary .book-header.fixed { 30 | left: calc(100% - 60px); 31 | min-width: 300px; 32 | } 33 | .book.with-summary .book-body { 34 | transform: none; 35 | left: calc(100% - 60px); 36 | min-width: 300px; 37 | } 38 | .book .book-body.fixed { 39 | top: 0; 40 | } 41 | } 42 | 43 | .book .book-body.fixed .body-inner { 44 | top: 50px; 45 | } 46 | .book .book-body .page-wrapper .page-inner section.normal sub, .book .book-body .page-wrapper .page-inner section.normal sup { 47 | font-size: 85%; 48 | } 49 | 50 | @media print { 51 | .book .book-summary, .book .book-body .book-header, .fa { 52 | display: none !important; 53 | } 54 | .book .book-body.fixed { 55 | left: 0px; 56 | } 57 | .book .book-body,.book .book-body .body-inner, .book.with-summary { 58 | overflow: visible !important; 59 | } 60 | } 61 | .kable_wrapper { 62 | border-spacing: 20px 0; 63 | border-collapse: separate; 64 | border: none; 65 | margin: auto; 66 | } 67 | .kable_wrapper > tbody > tr > td { 68 | vertical-align: top; 69 | } 70 | .book .book-body .page-wrapper .page-inner section.normal table tr.header { 71 | border-top-width: 2px; 72 | } 73 | .book .book-body .page-wrapper .page-inner section.normal table tr:last-child td { 74 | border-bottom-width: 2px; 75 | } 76 | .book .book-body .page-wrapper .page-inner section.normal table td, .book .book-body .page-wrapper .page-inner section.normal table th { 77 | border-left: none; 78 | border-right: none; 79 | } 80 | .book .book-body .page-wrapper .page-inner section.normal table.kable_wrapper > tbody > tr, .book .book-body .page-wrapper .page-inner section.normal table.kable_wrapper > tbody > tr > td { 81 | border-top: none; 82 | } 83 | .book .book-body .page-wrapper .page-inner section.normal table.kable_wrapper > tbody > tr:last-child > td { 84 | border-bottom: none; 85 | } 86 | 87 | div.theorem, div.lemma, div.corollary, div.proposition, div.conjecture { 88 | font-style: italic; 89 | } 90 | span.theorem, span.lemma, span.corollary, span.proposition, span.conjecture { 91 | font-style: normal; 92 | } 93 | div.proof:after { 94 | content: "\25a2"; 95 | float: right; 96 | } 97 | .header-section-number { 98 | padding-right: .5em; 99 | } 100 | -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/css/plugin-fontsettings.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Theme 1 3 | */ 4 | .color-theme-1 .dropdown-menu { 5 | background-color: #111111; 6 | border-color: #7e888b; 7 | } 8 | .color-theme-1 .dropdown-menu .dropdown-caret .caret-inner { 9 | border-bottom: 9px solid #111111; 10 | } 11 | .color-theme-1 .dropdown-menu .buttons { 12 | border-color: #7e888b; 13 | } 14 | .color-theme-1 .dropdown-menu .button { 15 | color: #afa790; 16 | } 17 | .color-theme-1 .dropdown-menu .button:hover { 18 | color: #73553c; 19 | } 20 | /* 21 | * Theme 2 22 | */ 23 | .color-theme-2 .dropdown-menu { 24 | background-color: #2d3143; 25 | border-color: #272a3a; 26 | } 27 | .color-theme-2 .dropdown-menu .dropdown-caret .caret-inner { 28 | border-bottom: 9px solid #2d3143; 29 | } 30 | .color-theme-2 .dropdown-menu .buttons { 31 | border-color: #272a3a; 32 | } 33 | .color-theme-2 .dropdown-menu .button { 34 | color: #62677f; 35 | } 36 | .color-theme-2 .dropdown-menu .button:hover { 37 | color: #f4f4f5; 38 | } 39 | .book .book-header .font-settings .font-enlarge { 40 | line-height: 30px; 41 | font-size: 1.4em; 42 | } 43 | .book .book-header .font-settings .font-reduce { 44 | line-height: 30px; 45 | font-size: 1em; 46 | } 47 | .book.color-theme-1 .book-body { 48 | color: #704214; 49 | background: #f3eacb; 50 | } 51 | .book.color-theme-1 .book-body .page-wrapper .page-inner section { 52 | background: #f3eacb; 53 | } 54 | .book.color-theme-2 .book-body { 55 | color: #bdcadb; 56 | background: #1c1f2b; 57 | } 58 | .book.color-theme-2 .book-body .page-wrapper .page-inner section { 59 | background: #1c1f2b; 60 | } 61 | .book.font-size-0 .book-body .page-inner section { 62 | font-size: 1.2rem; 63 | } 64 | .book.font-size-1 .book-body .page-inner section { 65 | font-size: 1.4rem; 66 | } 67 | .book.font-size-2 .book-body .page-inner section { 68 | font-size: 1.6rem; 69 | } 70 | .book.font-size-3 .book-body .page-inner section { 71 | font-size: 2.2rem; 72 | } 73 | .book.font-size-4 .book-body .page-inner section { 74 | font-size: 4rem; 75 | } 76 | .book.font-family-0 { 77 | font-family: Georgia, serif; 78 | } 79 | .book.font-family-1 { 80 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 81 | } 82 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal { 83 | color: #704214; 84 | } 85 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal a { 86 | color: inherit; 87 | } 88 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h1, 89 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h2, 90 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h3, 91 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h4, 92 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h5, 93 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h6 { 94 | color: inherit; 95 | } 96 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h1, 97 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h2 { 98 | border-color: inherit; 99 | } 100 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h6 { 101 | color: inherit; 102 | } 103 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal hr { 104 | background-color: inherit; 105 | } 106 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal blockquote { 107 | border-color: #c4b29f; 108 | opacity: 0.9; 109 | } 110 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre, 111 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code { 112 | background: #fdf6e3; 113 | color: #657b83; 114 | border-color: #f8df9c; 115 | } 116 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal .highlight { 117 | background-color: inherit; 118 | } 119 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table th, 120 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table td { 121 | border-color: #f5d06c; 122 | } 123 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table tr { 124 | color: inherit; 125 | background-color: #fdf6e3; 126 | border-color: #444444; 127 | } 128 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n) { 129 | background-color: #fbeecb; 130 | } 131 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal { 132 | color: #bdcadb; 133 | } 134 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal a { 135 | color: #3eb1d0; 136 | } 137 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h1, 138 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h2, 139 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h3, 140 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h4, 141 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h5, 142 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h6 { 143 | color: #fffffa; 144 | } 145 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h1, 146 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h2 { 147 | border-color: #373b4e; 148 | } 149 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h6 { 150 | color: #373b4e; 151 | } 152 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal hr { 153 | background-color: #373b4e; 154 | } 155 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal blockquote { 156 | border-color: #373b4e; 157 | } 158 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre, 159 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code { 160 | color: #9dbed8; 161 | background: #2d3143; 162 | border-color: #2d3143; 163 | } 164 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal .highlight { 165 | background-color: #282a39; 166 | } 167 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table th, 168 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table td { 169 | border-color: #3b3f54; 170 | } 171 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table tr { 172 | color: #b6c2d2; 173 | background-color: #2d3143; 174 | border-color: #3b3f54; 175 | } 176 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n) { 177 | background-color: #35394b; 178 | } 179 | .book.color-theme-1 .book-header { 180 | color: #afa790; 181 | background: transparent; 182 | } 183 | .book.color-theme-1 .book-header .btn { 184 | color: #afa790; 185 | } 186 | .book.color-theme-1 .book-header .btn:hover { 187 | color: #73553c; 188 | background: none; 189 | } 190 | .book.color-theme-1 .book-header h1 { 191 | color: #704214; 192 | } 193 | .book.color-theme-2 .book-header { 194 | color: #7e888b; 195 | background: transparent; 196 | } 197 | .book.color-theme-2 .book-header .btn { 198 | color: #3b3f54; 199 | } 200 | .book.color-theme-2 .book-header .btn:hover { 201 | color: #fffff5; 202 | background: none; 203 | } 204 | .book.color-theme-2 .book-header h1 { 205 | color: #bdcadb; 206 | } 207 | .book.color-theme-1 .book-body .navigation { 208 | color: #afa790; 209 | } 210 | .book.color-theme-1 .book-body .navigation:hover { 211 | color: #73553c; 212 | } 213 | .book.color-theme-2 .book-body .navigation { 214 | color: #383f52; 215 | } 216 | .book.color-theme-2 .book-body .navigation:hover { 217 | color: #fffff5; 218 | } 219 | /* 220 | * Theme 1 221 | */ 222 | .book.color-theme-1 .book-summary { 223 | color: #afa790; 224 | background: #111111; 225 | border-right: 1px solid rgba(0, 0, 0, 0.07); 226 | } 227 | .book.color-theme-1 .book-summary .book-search { 228 | background: transparent; 229 | } 230 | .book.color-theme-1 .book-summary .book-search input, 231 | .book.color-theme-1 .book-summary .book-search input:focus { 232 | border: 1px solid transparent; 233 | } 234 | .book.color-theme-1 .book-summary ul.summary li.divider { 235 | background: #7e888b; 236 | box-shadow: none; 237 | } 238 | .book.color-theme-1 .book-summary ul.summary li i.fa-check { 239 | color: #33cc33; 240 | } 241 | .book.color-theme-1 .book-summary ul.summary li.done > a { 242 | color: #877f6a; 243 | } 244 | .book.color-theme-1 .book-summary ul.summary li a, 245 | .book.color-theme-1 .book-summary ul.summary li span { 246 | color: #877f6a; 247 | background: transparent; 248 | font-weight: normal; 249 | } 250 | .book.color-theme-1 .book-summary ul.summary li.active > a, 251 | .book.color-theme-1 .book-summary ul.summary li a:hover { 252 | color: #704214; 253 | background: transparent; 254 | font-weight: normal; 255 | } 256 | /* 257 | * Theme 2 258 | */ 259 | .book.color-theme-2 .book-summary { 260 | color: #bcc1d2; 261 | background: #2d3143; 262 | border-right: none; 263 | } 264 | .book.color-theme-2 .book-summary .book-search { 265 | background: transparent; 266 | } 267 | .book.color-theme-2 .book-summary .book-search input, 268 | .book.color-theme-2 .book-summary .book-search input:focus { 269 | border: 1px solid transparent; 270 | } 271 | .book.color-theme-2 .book-summary ul.summary li.divider { 272 | background: #272a3a; 273 | box-shadow: none; 274 | } 275 | .book.color-theme-2 .book-summary ul.summary li i.fa-check { 276 | color: #33cc33; 277 | } 278 | .book.color-theme-2 .book-summary ul.summary li.done > a { 279 | color: #62687f; 280 | } 281 | .book.color-theme-2 .book-summary ul.summary li a, 282 | .book.color-theme-2 .book-summary ul.summary li span { 283 | color: #c1c6d7; 284 | background: transparent; 285 | font-weight: 600; 286 | } 287 | .book.color-theme-2 .book-summary ul.summary li.active > a, 288 | .book.color-theme-2 .book-summary ul.summary li a:hover { 289 | color: #f4f4f5; 290 | background: #252737; 291 | font-weight: 600; 292 | } 293 | -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/css/plugin-search.css: -------------------------------------------------------------------------------- 1 | .book .book-summary .book-search { 2 | padding: 6px; 3 | background: transparent; 4 | position: absolute; 5 | top: -50px; 6 | left: 0px; 7 | right: 0px; 8 | transition: top 0.5s ease; 9 | } 10 | .book .book-summary .book-search input, 11 | .book .book-summary .book-search input:focus, 12 | .book .book-summary .book-search input:hover { 13 | width: 100%; 14 | background: transparent; 15 | border: 1px solid #ccc; 16 | box-shadow: none; 17 | outline: none; 18 | line-height: 22px; 19 | padding: 7px 4px; 20 | color: inherit; 21 | box-sizing: border-box; 22 | } 23 | .book.with-search .book-summary .book-search { 24 | top: 0px; 25 | } 26 | .book.with-search .book-summary ul.summary { 27 | top: 50px; 28 | } 29 | -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/css/plugin-table.css: -------------------------------------------------------------------------------- 1 | .book .book-body .page-wrapper .page-inner section.normal table{display:table;width:100%;border-collapse:collapse;border-spacing:0;overflow:auto}.book .book-body .page-wrapper .page-inner section.normal table td,.book .book-body .page-wrapper .page-inner section.normal table th{padding:6px 13px;border:1px solid #ddd}.book .book-body .page-wrapper .page-inner section.normal table tr{background-color:#fff;border-top:1px solid #ccc}.book .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n){background-color:#f8f8f8}.book .book-body .page-wrapper .page-inner section.normal table th{font-weight:700} 2 | -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/js/jquery.highlight.js: -------------------------------------------------------------------------------- 1 | gitbook.require(["jQuery"], function(jQuery) { 2 | 3 | /* 4 | * jQuery Highlight plugin 5 | * 6 | * Based on highlight v3 by Johann Burkard 7 | * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html 8 | * 9 | * Code a little bit refactored and cleaned (in my humble opinion). 10 | * Most important changes: 11 | * - has an option to highlight only entire words (wordsOnly - false by default), 12 | * - has an option to be case sensitive (caseSensitive - false by default) 13 | * - highlight element tag and class names can be specified in options 14 | * 15 | * Copyright (c) 2009 Bartek Szopka 16 | * 17 | * Licensed under MIT license. 18 | * 19 | */ 20 | 21 | jQuery.extend({ 22 | highlight: function (node, re, nodeName, className) { 23 | if (node.nodeType === 3) { 24 | var match = node.data.match(re); 25 | if (match) { 26 | var highlight = document.createElement(nodeName || 'span'); 27 | highlight.className = className || 'highlight'; 28 | var wordNode = node.splitText(match.index); 29 | wordNode.splitText(match[0].length); 30 | var wordClone = wordNode.cloneNode(true); 31 | highlight.appendChild(wordClone); 32 | wordNode.parentNode.replaceChild(highlight, wordNode); 33 | return 1; //skip added node in parent 34 | } 35 | } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children 36 | !/(script|style)/i.test(node.tagName) && // ignore script and style nodes 37 | !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted 38 | for (var i = 0; i < node.childNodes.length; i++) { 39 | i += jQuery.highlight(node.childNodes[i], re, nodeName, className); 40 | } 41 | } 42 | return 0; 43 | } 44 | }); 45 | 46 | jQuery.fn.unhighlight = function (options) { 47 | var settings = { className: 'highlight', element: 'span' }; 48 | jQuery.extend(settings, options); 49 | 50 | return this.find(settings.element + "." + settings.className).each(function () { 51 | var parent = this.parentNode; 52 | parent.replaceChild(this.firstChild, this); 53 | parent.normalize(); 54 | }).end(); 55 | }; 56 | 57 | jQuery.fn.highlight = function (words, options) { 58 | var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false }; 59 | jQuery.extend(settings, options); 60 | 61 | if (words.constructor === String) { 62 | words = [words]; 63 | } 64 | words = jQuery.grep(words, function(word, i){ 65 | return word !== ''; 66 | }); 67 | words = jQuery.map(words, function(word, i) { 68 | return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 69 | }); 70 | if (words.length === 0) { return this; } 71 | 72 | var flag = settings.caseSensitive ? "" : "i"; 73 | var pattern = "(" + words.join("|") + ")"; 74 | if (settings.wordsOnly) { 75 | pattern = "\\b" + pattern + "\\b"; 76 | } 77 | var re = new RegExp(pattern, flag); 78 | 79 | return this.each(function () { 80 | jQuery.highlight(this, re, settings.element, settings.className); 81 | }); 82 | }; 83 | 84 | }); 85 | -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/js/lunr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.5.12 3 | * Copyright (C) 2015 Oliver Nightingale 4 | * MIT Licensed 5 | * @license 6 | */ 7 | !function(){var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.5.12",t.utils={},t.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},t.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},t.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},t.EventEmitter.prototype.hasHandler=function(t){return t in this.events},t.tokenizer=function(t){return arguments.length&&null!=t&&void 0!=t?Array.isArray(t)?t.map(function(t){return t.toLowerCase()}):t.toString().trim().toLowerCase().split(/[\s\-\/]+/):[]},t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.registeredFunctions[e];if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");this._stack.splice(i,0,n)},t.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);-1!=e&&this._stack.splice(e,1)},t.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,i=this._stack.length,o=0;n>o;o++){for(var r=t[o],s=0;i>s&&(r=this._stack[s](r,o,t),void 0!==r);s++);void 0!==r&&e.push(r)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(en.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t1;){if(r===t)return o;t>r&&(e=o),r>t&&(n=o),i=n-e,o=e+Math.floor(i/2),r=this.elements[o]}return r===t?o:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,o=e+Math.floor(i/2),r=this.elements[o];i>1;)t>r&&(e=o),r>t&&(n=o),i=n-e,o=e+Math.floor(i/2),r=this.elements[o];return r>t?o:t>r?o+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,o=0,r=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>r-1||o>s-1)break;a[i]!==h[o]?a[i]h[o]&&o++:(n.add(a[i]),i++,o++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;return this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone(),i.add.apply(i,n.toArray()),i},t.SortedSet.prototype.toJSON=function(){return this.toArray()},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.Store,this.tokenStore=new t.TokenStore,this.corpusTokens=new t.SortedSet,this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var t=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,t)},t.Index.prototype.off=function(t,e){return this.eventEmitter.removeListener(t,e)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;return n._fields=e.fields,n._ref=e.ref,n.documentStore=t.Store.load(e.documentStore),n.tokenStore=t.TokenStore.load(e.tokenStore),n.corpusTokens=t.SortedSet.load(e.corpusTokens),n.pipeline=t.Pipeline.load(e.pipeline),n},t.Index.prototype.field=function(t,e){var e=e||{},n={name:t,boost:e.boost||1};return this._fields.push(n),this},t.Index.prototype.ref=function(t){return this._ref=t,this},t.Index.prototype.add=function(e,n){var i={},o=new t.SortedSet,r=e[this._ref],n=void 0===n?!0:n;this._fields.forEach(function(n){var r=this.pipeline.run(t.tokenizer(e[n.name]));i[n.name]=r,t.SortedSet.prototype.add.apply(o,r)},this),this.documentStore.set(r,o),t.SortedSet.prototype.add.apply(this.corpusTokens,o.toArray());for(var s=0;s0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(t.tokenizer(e)),i=new t.Vector,o=[],r=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*r,h=this,l=this.tokenStore.expand(e).reduce(function(n,o){var r=h.corpusTokens.indexOf(o),s=h.idf(o),l=1,u=new t.SortedSet;if(o!==e){var c=Math.max(3,o.length-e.length);l=1/Math.log(c)}return r>-1&&i.insert(r,a*s*l),Object.keys(h.tokenStore.get(o)).forEach(function(t){u.add(t)}),n.union(u)},new t.SortedSet);o.push(l)},this);var a=o.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,o=new t.Vector,r=0;i>r;r++){var s=n.elements[r],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);o.insert(this.corpusTokens.indexOf(s),a*h)}return o},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",o=n+"[^aeiouy]*",r=i+"[aeiou]*",s="^("+o+")?"+r+o,a="^("+o+")?"+r+o+"("+r+")?$",h="^("+o+")?"+r+o+r+o,l="^("+o+")?"+i,u=new RegExp(s),c=new RegExp(h),f=new RegExp(a),d=new RegExp(l),p=/^(.+?)(ss|i)es$/,m=/^(.+?)([^s])s$/,v=/^(.+?)eed$/,y=/^(.+?)(ed|ing)$/,g=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),x=new RegExp("^"+o+i+"[^aeiouwxy]$"),k=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,_=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,F=/^(.+?)(s|t)(ion)$/,O=/^(.+?)e$/,P=/ll$/,N=new RegExp("^"+o+i+"[^aeiouwxy]$"),T=function(n){var i,o,r,s,a,h,l;if(n.length<3)return n;if(r=n.substr(0,1),"y"==r&&(n=r.toUpperCase()+n.substr(1)),s=p,a=m,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=v,a=y,s.test(n)){var T=s.exec(n);s=u,s.test(T[1])&&(s=g,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=d,a.test(i)&&(n=i,a=S,h=w,l=x,a.test(n)?n+="e":h.test(n)?(s=g,n=n.replace(s,"")):l.test(n)&&(n+="e"))}if(s=k,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],o=T[2],s=u,s.test(i)&&(n=i+t[o])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],o=T[2],s=u,s.test(i)&&(n=i+e[o])}if(s=_,a=F,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=O,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=N,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=P,a=c,s.test(n)&&a.test(n)&&(s=g,n=n.replace(s,"")),"y"==r&&(n=r.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.stopWordFilter=function(e){return e&&t.stopWordFilter.stopWords[e]!==e?e:void 0},t.stopWordFilter.stopWords={a:"a",able:"able",about:"about",across:"across",after:"after",all:"all",almost:"almost",also:"also",am:"am",among:"among",an:"an",and:"and",any:"any",are:"are",as:"as",at:"at",be:"be",because:"because",been:"been",but:"but",by:"by",can:"can",cannot:"cannot",could:"could",dear:"dear",did:"did","do":"do",does:"does",either:"either","else":"else",ever:"ever",every:"every","for":"for",from:"from",get:"get",got:"got",had:"had",has:"has",have:"have",he:"he",her:"her",hers:"hers",him:"him",his:"his",how:"how",however:"however",i:"i","if":"if","in":"in",into:"into",is:"is",it:"it",its:"its",just:"just",least:"least",let:"let",like:"like",likely:"likely",may:"may",me:"me",might:"might",most:"most",must:"must",my:"my",neither:"neither",no:"no",nor:"nor",not:"not",of:"of",off:"off",often:"often",on:"on",only:"only",or:"or",other:"other",our:"our",own:"own",rather:"rather",said:"said",say:"say",says:"says",she:"she",should:"should",since:"since",so:"so",some:"some",than:"than",that:"that",the:"the",their:"their",them:"them",then:"then",there:"there",these:"these",they:"they","this":"this",tis:"tis",to:"to",too:"too",twas:"twas",us:"us",wants:"wants",was:"was",we:"we",were:"were",what:"what",when:"when",where:"where",which:"which","while":"while",who:"who",whom:"whom",why:"why",will:"will","with":"with",would:"would",yet:"yet",you:"you",your:"your"},t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){var e=t.replace(/^\W+/,"").replace(/\W+$/,"");return""===e?void 0:e},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t[0],o=t.slice(1);return i in n||(n[i]={docs:{}}),0===o.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(o,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;n's that are truncated 107 | $('a').each(function(i, el) { 108 | if (el.offsetWidth >= el.scrollWidth) return; 109 | if (typeof el.title === 'undefined') return; 110 | el.title = el.text; 111 | }); 112 | 113 | // restore TOC scroll position 114 | var pos = gs.get('tocScrollTop'); 115 | if (typeof pos !== 'undefined') summary.scrollTop(pos); 116 | 117 | // highlight the TOC item that has same text as the heading in view as scrolling 118 | if (toc && toc.scroll_highlight !== false) (function() { 119 | // scroll the current TOC item into viewport 120 | var ht = $(window).height(), rect = li[0].getBoundingClientRect(); 121 | if (rect.top >= ht || rect.top <= 0 || rect.bottom <= 0) { 122 | summary.scrollTop(li[0].offsetTop); 123 | } 124 | // current chapter TOC items 125 | var items = $('a[href^="' + href + '"]').parent('li.chapter'), 126 | m = items.length; 127 | if (m === 0) { 128 | items = summary.find('li.chapter'); 129 | m = items.length; 130 | } 131 | if (m === 0) return; 132 | // all section titles on current page 133 | var hs = bookInner.find('.page-inner').find('h1,h2,h3'), n = hs.length, 134 | ts = hs.map(function(i, el) { return $(el).text(); }); 135 | if (n === 0) return; 136 | var scrollHandler = function(e) { 137 | var ht = $(window).height(); 138 | clearTimeout($.data(this, 'scrollTimer')); 139 | $.data(this, 'scrollTimer', setTimeout(function() { 140 | // find the first visible title in the viewport 141 | for (var i = 0; i < n; i++) { 142 | var rect = hs[i].getBoundingClientRect(); 143 | if (rect.top >= 0 && rect.bottom <= ht) break; 144 | } 145 | if (i === n) return; 146 | items.removeClass('active'); 147 | for (var j = 0; j < m; j++) { 148 | if (items.eq(j).children('a').first().text() === ts[i]) break; 149 | } 150 | if (j === m) j = 0; // highlight the chapter title 151 | // search bottom-up for a visible TOC item to highlight; if an item is 152 | // hidden, we check if its parent is visible, and so on 153 | while (j > 0 && items.eq(j).is(':hidden')) j--; 154 | items.eq(j).addClass('active'); 155 | }, 250)); 156 | }; 157 | bookInner.on('scroll.bookdown', scrollHandler); 158 | bookBody.on('scroll.bookdown', scrollHandler); 159 | })(); 160 | 161 | // do not refresh the page if the TOC item points to the current page 162 | $('a[href="' + href + '"]').parent('li.chapter').children('a') 163 | .on('click', function(e) { 164 | bookInner.scrollTop(0); 165 | bookBody.scrollTop(0); 166 | return false; 167 | }); 168 | 169 | var toolbar = config.toolbar; 170 | if (!toolbar || toolbar.position !== 'static') { 171 | var bookHeader = $('.book-header'); 172 | bookBody.addClass('fixed'); 173 | bookHeader.addClass('fixed') 174 | .css('background-color', bookBody.css('background-color')) 175 | .on('click.bookdown', function(e) { 176 | // the theme may have changed after user clicks the theme button 177 | bookHeader.css('background-color', bookBody.css('background-color')); 178 | }); 179 | } 180 | 181 | }); 182 | 183 | gitbook.events.bind("page.change", function(e) { 184 | // store TOC scroll position 185 | var summary = $('ul.summary'); 186 | gs.set('tocScrollTop', summary.scrollTop()); 187 | }); 188 | 189 | var bookBody = $('.book-body'), bookInner = bookBody.find('.body-inner'); 190 | var chapterTitle = function() { 191 | return bookInner.find('.page-inner').find('h1,h2').first().text(); 192 | }; 193 | var bookTitle = function() { 194 | return bookInner.find('.book-header > h1').first().text(); 195 | }; 196 | var saveScrollPos = function(e) { 197 | // save scroll position before page is reloaded 198 | gs.set('bodyScrollTop', { 199 | body: bookBody.scrollTop(), 200 | inner: bookInner.scrollTop(), 201 | focused: document.hasFocus(), 202 | title: chapterTitle() 203 | }); 204 | }; 205 | $(document).on('servr:reload', saveScrollPos); 206 | 207 | // check if the page is loaded in an iframe (e.g. the RStudio preview window) 208 | var inIFrame = function() { 209 | var inIframe = true; 210 | try { inIframe = window.self !== window.top; } catch (e) {} 211 | return inIframe; 212 | }; 213 | $(window).on('blur unload', function(e) { 214 | if (inIFrame()) saveScrollPos(e); 215 | gs.set('bookTitle', bookTitle()); 216 | }); 217 | 218 | $(function(e) { 219 | if (gs.get('bookTitle', '') !== bookTitle()) localStorage.clear(); 220 | var pos = gs.get('bodyScrollTop'); 221 | if (pos) { 222 | if (pos.title === chapterTitle()) { 223 | if (pos.body !== 0) bookBody.scrollTop(pos.body); 224 | if (pos.inner !== 0) bookInner.scrollTop(pos.inner); 225 | } 226 | if (pos.focused) bookInner.find('.page-wrapper').focus(); 227 | } 228 | // clear book body scroll position 229 | gs.remove('bodyScrollTop'); 230 | }); 231 | 232 | }); 233 | -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/js/plugin-fontsettings.js: -------------------------------------------------------------------------------- 1 | gitbook.require(["gitbook", "lodash", "jQuery"], function(gitbook, _, $) { 2 | var fontState; 3 | 4 | var THEMES = { 5 | "white": 0, 6 | "sepia": 1, 7 | "night": 2 8 | }; 9 | 10 | var FAMILY = { 11 | "serif": 0, 12 | "sans": 1 13 | }; 14 | 15 | // Save current font settings 16 | function saveFontSettings() { 17 | gitbook.storage.set("fontState", fontState); 18 | update(); 19 | } 20 | 21 | // Increase font size 22 | function enlargeFontSize(e) { 23 | e.preventDefault(); 24 | if (fontState.size >= 4) return; 25 | 26 | fontState.size++; 27 | saveFontSettings(); 28 | }; 29 | 30 | // Decrease font size 31 | function reduceFontSize(e) { 32 | e.preventDefault(); 33 | if (fontState.size <= 0) return; 34 | 35 | fontState.size--; 36 | saveFontSettings(); 37 | }; 38 | 39 | // Change font family 40 | function changeFontFamily(index, e) { 41 | e.preventDefault(); 42 | 43 | fontState.family = index; 44 | saveFontSettings(); 45 | }; 46 | 47 | // Change type of color 48 | function changeColorTheme(index, e) { 49 | e.preventDefault(); 50 | 51 | var $book = $(".book"); 52 | 53 | if (fontState.theme !== 0) 54 | $book.removeClass("color-theme-"+fontState.theme); 55 | 56 | fontState.theme = index; 57 | if (fontState.theme !== 0) 58 | $book.addClass("color-theme-"+fontState.theme); 59 | 60 | saveFontSettings(); 61 | }; 62 | 63 | function update() { 64 | var $book = gitbook.state.$book; 65 | 66 | $(".font-settings .font-family-list li").removeClass("active"); 67 | $(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")").addClass("active"); 68 | 69 | $book[0].className = $book[0].className.replace(/\bfont-\S+/g, ''); 70 | $book.addClass("font-size-"+fontState.size); 71 | $book.addClass("font-family-"+fontState.family); 72 | 73 | if(fontState.theme !== 0) { 74 | $book[0].className = $book[0].className.replace(/\bcolor-theme-\S+/g, ''); 75 | $book.addClass("color-theme-"+fontState.theme); 76 | } 77 | }; 78 | 79 | function init(config) { 80 | var $bookBody, $book; 81 | 82 | //Find DOM elements. 83 | $book = gitbook.state.$book; 84 | $bookBody = $book.find(".book-body"); 85 | 86 | // Instantiate font state object 87 | fontState = gitbook.storage.get("fontState", { 88 | size: config.size || 2, 89 | family: FAMILY[config.family || "sans"], 90 | theme: THEMES[config.theme || "white"] 91 | }); 92 | 93 | update(); 94 | }; 95 | 96 | 97 | gitbook.events.bind("start", function(e, config) { 98 | var opts = config.fontsettings; 99 | 100 | // Create buttons in toolbar 101 | gitbook.toolbar.createButton({ 102 | icon: 'fa fa-font', 103 | label: 'Font Settings', 104 | className: 'font-settings', 105 | dropdown: [ 106 | [ 107 | { 108 | text: 'A', 109 | className: 'font-reduce', 110 | onClick: reduceFontSize 111 | }, 112 | { 113 | text: 'A', 114 | className: 'font-enlarge', 115 | onClick: enlargeFontSize 116 | } 117 | ], 118 | [ 119 | { 120 | text: 'Serif', 121 | onClick: _.partial(changeFontFamily, 0) 122 | }, 123 | { 124 | text: 'Sans', 125 | onClick: _.partial(changeFontFamily, 1) 126 | } 127 | ], 128 | [ 129 | { 130 | text: 'White', 131 | onClick: _.partial(changeColorTheme, 0) 132 | }, 133 | { 134 | text: 'Sepia', 135 | onClick: _.partial(changeColorTheme, 1) 136 | }, 137 | { 138 | text: 'Night', 139 | onClick: _.partial(changeColorTheme, 2) 140 | } 141 | ] 142 | ] 143 | }); 144 | 145 | 146 | // Init current settings 147 | init(opts); 148 | }); 149 | }); 150 | 151 | 152 | -------------------------------------------------------------------------------- /docs/libs/gitbook-2.6.7/js/plugin-search.js: -------------------------------------------------------------------------------- 1 | gitbook.require(["gitbook", "lodash", "jQuery"], function(gitbook, _, $) { 2 | var index = null; 3 | var $searchInput, $searchLabel, $searchForm; 4 | var $highlighted, hi = 0, hiOpts = { className: 'search-highlight' }; 5 | var collapse = false; 6 | 7 | // Use a specific index 8 | function loadIndex(data) { 9 | // [Yihui] In bookdown, I use a character matrix to store the chapter 10 | // content, and the index is dynamically built on the client side. 11 | // Gitbook prebuilds the index data instead: https://github.com/GitbookIO/plugin-search 12 | // We can certainly do that via R packages V8 and jsonlite, but let's 13 | // see how slow it really is before improving it. On the other hand, 14 | // lunr cannot handle non-English text very well, e.g. the default 15 | // tokenizer cannot deal with Chinese text, so we may want to replace 16 | // lunr with a dumb simple text matching approach. 17 | index = lunr(function () { 18 | this.ref('url'); 19 | this.field('title', { boost: 10 }); 20 | this.field('body'); 21 | }); 22 | data.map(function(item) { 23 | index.add({ 24 | url: item[0], 25 | title: item[1], 26 | body: item[2] 27 | }); 28 | }); 29 | } 30 | 31 | // Fetch the search index 32 | function fetchIndex() { 33 | return $.getJSON(gitbook.state.basePath+"/search_index.json") 34 | .then(loadIndex); // [Yihui] we need to use this object later 35 | } 36 | 37 | // Search for a term and return results 38 | function search(q) { 39 | if (!index) return; 40 | 41 | var results = _.chain(index.search(q)) 42 | .map(function(result) { 43 | var parts = result.ref.split("#"); 44 | return { 45 | path: parts[0], 46 | hash: parts[1] 47 | }; 48 | }) 49 | .value(); 50 | 51 | // [Yihui] Highlight the search keyword on current page 52 | hi = 0; 53 | $highlighted = results.length === 0 ? undefined : $('.page-inner') 54 | .unhighlight(hiOpts).highlight(q, hiOpts).find('span.search-highlight'); 55 | scrollToHighlighted(); 56 | toggleTOC(results.length > 0); 57 | 58 | return results; 59 | } 60 | 61 | // [Yihui] Scroll the chapter body to the i-th highlighted string 62 | function scrollToHighlighted() { 63 | if (!$highlighted) return; 64 | var n = $highlighted.length; 65 | if (n === 0) return; 66 | var $p = $highlighted.eq(hi), p = $p[0], rect = p.getBoundingClientRect(); 67 | if (rect.top < 0 || rect.bottom > $(window).height()) { 68 | ($(window).width() >= 1240 ? $('.body-inner') : $('.book-body')) 69 | .scrollTop(p.offsetTop - 100); 70 | } 71 | $highlighted.css('background-color', ''); 72 | // an orange background color on the current item and removed later 73 | $p.css('background-color', 'orange'); 74 | setTimeout(function() { 75 | $p.css('background-color', ''); 76 | }, 2000); 77 | } 78 | 79 | // [Yihui] Expand/collapse TOC 80 | function toggleTOC(show) { 81 | if (!collapse) return; 82 | var toc_sub = $('ul.summary').children('li[data-level]').children('ul'); 83 | if (show) return toc_sub.show(); 84 | var href = window.location.pathname; 85 | href = href.substr(href.lastIndexOf('/') + 1); 86 | if (href === '') href = 'index.html'; 87 | var li = $('a[href^="' + href + location.hash + '"]').parent('li.chapter').first(); 88 | toc_sub.hide().parent().has(li).children('ul').show(); 89 | li.children('ul').show(); 90 | } 91 | 92 | // Create search form 93 | function createForm(value) { 94 | if ($searchForm) $searchForm.remove(); 95 | if ($searchLabel) $searchLabel.remove(); 96 | if ($searchInput) $searchInput.remove(); 97 | 98 | $searchForm = $('
    ', { 99 | 'class': 'book-search', 100 | 'role': 'search' 101 | }); 102 | 103 | $searchLabel = $('