-
Notifications
You must be signed in to change notification settings - Fork 19
/
gee-charts.Rmd
810 lines (508 loc) · 44.8 KB
/
gee-charts.Rmd
1
2
3
4
5
6
7
8
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
---
title: "Creating Publication Quality Charts with GEE (Full Course)"
subtitle: "A comprehesive guide on creating high-quality data visualizations with Google Earth Engine and Google Charts."
author: "Ujaval Gandhi"
fontsize: 12pt
output:
# pdf_document:
# latex_engine: xelatex
# toc: yes
# toc_depth: 3
# fig_caption: false
# word_document:
# toc: false
# fig_caption: false
html_document:
df_print: paged
highlight: pygments
includes:
after_body: comment.html
toc: yes
toc_depth: 2
header-includes:
- \usepackage{fancyhdr}
- \pagestyle{fancy}
- \renewcommand{\footrulewidth}{0.4pt}
- \fancyhead[LE,RO]{\thepage}
- \geometry{left=1in,top=0.75in,bottom=0.75in}
- \fancyfoot[CE,CO]{{\includegraphics[height=0.5cm]{images/cc-by-nc.png}} Ujaval Gandhi http://www.spatialthoughts.com}
---
\newpage
***
```{r echo=FALSE, fig.align='center', out.width='75%', out.width='250pt'}
knitr::include_graphics('images/spatial_thoughts_logo.png')
```
***
\newpage
# Introduction
This is an intermediate-level class that is suited for participants who are familiar with the Google Earth Engine API and want to learn advanced data visualization methods. This class also introduces novel earth observation and climate datasets along with techniques to work with them.
[![Watch the video](https://img.youtube.com/vi/quHX1HOCIKU/mqdefault.jpg)](https://www.youtube.com/watch?v=quHX1HOCIKU&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao){target="_blank"}
[Watch the Video ↗](https://www.youtube.com/watch?v=quHX1HOCIKU&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao){target="_blank"}
[Access the Presentation ↗](https://docs.google.com/presentation/d/1_mqS5eqJghkBBpspnvnyVuz6utfgfe_TVjLiTC-JtsM/edit?usp=sharing){target="_blank"}
# Setting up the Environment
## Sign-up for Google Earth Engine
If you already have a Google Earth Engine account, you can skip this step.
Visit our [GEE Sign-Up Guide](gee-sign-up.html) for step-by-step instructions.
## Get the Course Materials
The course material and exercises are in the form of Earth Engine scripts shared via a code repository.
1. [Click this link](https://code.earthengine.google.co.in/?accept_repo=users/ujavalgandhi/GEE-Charts) to open Google Earth Engine code editor and add the repository to your account.
2. If successful, you will have a new repository named `users/ujavalgandhi/GEE-Charts` in the *Scripts* tab in the *Reader* section.
3. Verify that your code editor looks like below
```{r echo=FALSE, fig.align='center', out.width='50%', fig.cap='Code Editor with Course Repository'}
knitr::include_graphics('images/gee_charts/repository.png')
```
If you do not see the repository in the *Reader* section, click *Refresh repository cache* button in your *Scripts* tab and it will show up.
```{r echo=FALSE, fig.align='center', out.width='50%', fig.cap='Refresh repository cache'}
knitr::include_graphics('images/common/repository_cache.png')
```
## Get the Course Videos
The course is accompanied by a set of videos covering the all the modules. These videos are recorded from our live instructor-led classes and are edited to make them easier to consume for self-study. We have 2 versions of the videos
### YouTube
We have created a YouTube Playlist with separate videos for each script and exercise to enable effective online-learning. [Access the YouTube Playlist ↗](https://www.youtube.com/watch?v=quHX1HOCIKU&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao){target="_blank"}
### Vimeo
We are also making combined full-length video for each module available on Vimeo. These videos can be downloaded for offline learning. [Access the Vimeo Playlist ↗](https://vimeo.com/showcase/11003930){target="_blank"}
# Module 1. Time-Series Charts
In this section, we will explore various built-in functions to create time-series charts from ImageCollections. We will also explore the customization options provided by Google Charts to make high-quality functional graphics.
[![Start Module 1 Videos](https://img.youtube.com/vi/lD2Sj-A2sjc/mqdefault.jpg)](https://www.youtube.com/watch?v=lD2Sj-A2sjc&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=3){target="_blank"}
[Start Module 1 Videos ↗](https://www.youtube.com/watch?v=lD2Sj-A2sjc&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=3){target="_blank"}
## 1.1 Simple Time-Series
We start by using the time-series charting function `ui.Chart.image.series()` that allows you to create a time-series plot from an ImageCollection at a single location. You get one time-series per band of the input dataset. We take the TerraClimate dataset and select the bands for monthly maximum and minimum temperatures. The resulting chart is a [Line Chart](https://developers.google.com/chart/interactive/docs/gallery/linechart) that can be further customized using the `.setOptions()` method.
Here are the customization applied to the default time-series chart:
- `lineWidth`: Sets the thickness of the line
- `pointSize`: Sets the size of the data point
- `title`: Sets the chart title
- `vAxis`: Sets the options for Y-Axis. Axis label is specified using the `title` option.
- `hAxis`: Sets the options for X-Axis. Grid lines are specified using the `gridlines` option. Date format for tick labels is specified with `format` option.
- `series`: Sets the options for each individual time-series. Series count starts from 0.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Time-Series Chart'}
knitr::include_graphics('images/gee_charts/time_series.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A01-Time_Series_Charts%2F01b_Time_Series_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/01-Time_Series_Charts/01b_Time_Series_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A01-Time_Series_Charts%2F01c_Time_Series_(exercise)){target="_blank"}
```
// Exercise
// a) Delete the 'geometry' and add a new point at your chosen location
// b) Modify the chart options display the series with dashed lines
// c) Print the chart.
// See reference:
// https://developers.google.com/chart/interactive/docs/lines#dashed
```
## 1.2 Time-Series with Trendlines
Google Charts can dynamically compute and display [Trendlines](https://developers.google.com/chart/interactive/docs/gallery/trendlines) on the chart. You can choose from linear, polynomial or exponential trendlines. The linear trendline fit a least-square regression model on the dataset. Here we take a time-series of precipitation data, aggregate it to yearly precipitation and then display a linear trendline to indicate whether we see an increasing or decreasing rainfall in the region.
Here are the styling options applied to the time-series chart:
- `vAxis.ticks`: Sets the tick positions for Y-Axis. We manually specify the exact tick marks we want.
- `gridlines.color`: Sets the color of the grid lines.
- `legend`: Sets the position of the legend. The `in` options makes the legend appear inside the chart.
- `series.visibleInLegend`: Sets whether a particular series label is visible in the legend.
- `trendlines`: Sets the option for trendlines. We override the default label using `labelInLegend` option.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Time-Series Chart with Trendline'}
knitr::include_graphics('images/gee_charts/time_series_trend.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A01-Time_Series_Charts%2F02b_Time_Series_With_Trend_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/01-Time_Series_Charts/02b_Time_Series_With_Trend_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A01-Time_Series_Charts%2F02c_Time_Series_With_Trend_(exercise)){target="_blank"}
```
// Exercise
// a) Delete the 'geometry' and add a new point at your chosen location
// b) Modify the chart options to remove the legend from the chart.
// c) Print the chart.
// Hint: Use legend 'position' option
// See reference:
// https://developers.google.com/chart/interactive/docs/gallery/linechart
```
## 1.3 Time-Series at Multiple Locations
So far, we have learnt how to display time-series of one or more variables at a single location using the `ui.Chart.image.series()` function. If you wanted to plot time-series of multiple locations in a single chart, you can use the `ui.Chart.image.series.byRegion()` function. This function takes a FeatureCollection with one or more locations and extract the time-series at each geometry.
Here we take the Global Forecast System (GFS) dataset and create a chart of 16-day temperature-forecasts at 2 cities.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Time-Series Chart at Multiple Locations'}
knitr::include_graphics('images/gee_charts/time_series_by_region.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A01-Time_Series_Charts%2F03b_Time_Series_By_Region_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/01-Time_Series_Charts/03b_Time_Series_By_Region_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A01-Time_Series_Charts%2F03c_Time_Series_By_Region_(exercise)){target="_blank"}
```
// Exercise
// a) Replace the 'geometry1' and 'geometry2' points with your chosen locations.
// b) Modify the chart options to limit the Y-Axis range to the
// actual range of temperatures at your chosen locations (i.e. between 20-45 degrees)
// c) Print the chart.
```
## 1.4 Multi-Year Time-Series
Another useful function to plot time-series is ``ui.Chart.image.doySeriesByYear()` that extracts and plots values from an image band at different Day-Of-Year (DOY) over many years. This type of chart is helpful visualize both inter-annual and inter-annual variations in a single chart.
Here we take the MODIS 16-day Vegetation Indices (VI) dataset and create a chart of NDVI Time-Series over 4 years.
Here are the styling options applied to the time-series chart:
- `interpolateNulls`: Sets whether to fill missing (i.e masked) time-series values
- `curveType`: Apply smoothing on the time-series by [fitting a function](https://developers.google.com/chart/interactive/docs/gallery/linechart#curving-the-lines).
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='DOY Time-Series Chart'}
knitr::include_graphics('images/gee_charts/time_series_by_year.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A01-Time_Series_Charts%2F04b_Time_Series_By_Year_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/01-Time_Series_Charts/04b_Time_Series_By_Year_(complete)')}
```
### Exercise
```{r echo=FALSE, fig.align='center', out.width='100%', fig.cap='Exercise 04c'}
knitr::include_graphics('images/gee_charts/time_series_by_year_exercise.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A01-Time_Series_Charts%2F04c_Time_Series_By_Year_(exercise)){target="_blank"}
```
// Exercise
// a) Replace the 'geometry' with your chosen location.
// b) Modify the chart to specify custom colors for each year.
// Use color codes from https://colorbrewer2.org/
// c) Modify the chart to plot only the time-series
// with lines without any points.
// c) Print the chart.
```
# Module 2. Image Charts
This section covers charting functions and techniques to plot values from an image. We will also learn how to deal with limitations of the charting API and create plots by extracting data from large regions.
[![Start Module 2 Videos](https://img.youtube.com/vi/6LYOBYujE8U/mqdefault.jpg)](https://www.youtube.com/watch?v=6LYOBYujE8U&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=11){target="_blank"}
[Start Module 2 Videos ↗](https://www.youtube.com/watch?v=6LYOBYujE8U&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=11){target="_blank"}
## 2.1 Image Histogram
A histogram plot is a bar chart showing count of pixel values. Typically the pixel values are grouped into range of values called *buckets* on the X-Axis and the total count of pixels is shown on the Y-Axis.
Here we take the Harmonized Night Time Lights dataset that contains images from both DMSP and VIIRS sensors.
Below is the list of styling options applied to the histogram:
- `hAxis.ticks`: Sets the tick labels on the X-Axis.
- `bar.gap`: Sets the gap between each histogram bar
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Image Histogram'}
knitr::include_graphics('images/gee_charts/image_histogram.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A02-Image_Charts%2F01b_Image_Histogram_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/02-Image_Charts/01b_Image_Histogram_(complete)')}
```
### Exercise
```{r echo=FALSE, fig.align='center', out.width='100%', fig.cap='Exercise 01c'}
knitr::include_graphics('images/gee_charts/image_histogram_exercise.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A02-Image_Charts%2F01c_Image_Histogram_(exercise)){target="_blank"}
```
// Exercise
// The code now has a function createChart that creates a chart
// for the given year
// a) Change the name of the country to your chosen country
// b) Call the function to create histograms for the year 2010 and 2020
// c) Print the charts.
// Tip: Adjust the hAxis.viewWindow parameter to appropriate values
// for your chosen country
```
## 2.2 Image Scatter Chart
A scatter plot is useful to explore the relationship between 2 variables. In Earth Engine, you can extract the pixel values from an image using any of the sampling functions such as `sample()` or `stratifiedSample()` to get a FeatureCollection with pixel values for a random subset of the pixels. We can then plot the results using the built-in charting functions for FeatureCollections.
Here we use the Sentinel-2 Surface Reflectance dataset along with Global Surface Water Yearly Water History dataset to get reflectance values of water and non-water pixels within the chosen region. We then use the `ui.Chart.feature.groups()` function to plot the results. Note that you can explicitly set the desired chart type using the `setChartType()` function.
Below is the list of new styling options applied to the scatter plot:
- `titleTextStyle`: Sets the style of the title text.
- `dataOpacity`: Sets the transparency for the data points. Useful when you have overlapping data points.
- `pointShape`: Sets the shape of the marker from the [available marker shapes](https://developers.google.com/chart/interactive/docs/points).
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Scatter Plot'}
knitr::include_graphics('images/gee_charts/image_scatterchart.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A02-Image_Charts%2F02b_Image_Scatter_Chart_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/02-Image_Charts/02b_Image_Scatter_Chart_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A02-Image_Charts%2F02c_Image_Scatter_Chart_(exercise)){target="_blank"}
```
// Exercise
// The code now contains a function createChart() that creates a scatter plot
// between the chosen bands
// a) Delete the 'geometry' and add a new polygon at your chosen location
// b) Create a chart for B3 and B11
// c) Print the chart.
```
## 2.3 Image Class Areas (Table)
Many analysts would want to create a chart or a table showing areas of different landcover classes in an image. The EE API has a dedicated function `ui.Chart.Image.byClass()` that can tabulate image pixel values by class.
Here we use the ESA Landcover 2021 dataset and create a **Table** chart of areas within the buffer zone of a location. Note that we are using `setChartType()` function with the option **Table** to create a table. Such tables are useful when you are creating apps and want to display a formatted table. The [Global Population Explorer](https://google.earthengine.app/view/population-explorer) is a good example where you can switch between a *Bar Chart* and a *Table* to display the results.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Table Chart'}
knitr::include_graphics('images/gee_charts/image_by_class_table.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A02-Image_Charts%2F03b_Area_By_Class_Table_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/02-Image_Charts/03b_Area_By_Class_Table_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A02-Image_Charts%2F03c_Area_By_Class_Table_(exercise)){target="_blank"}
```
// Exercise
// a) Delete the 'geometry' and add a new point at your chosen location
// b) Change the buffer distance to 10km and Area units to Square Kilometers
// c) Print the chart.
```
# Module 3. FeatureCollection Charts
[![Start Module 3 Videos](https://img.youtube.com/vi/oT7ajtbqNy8/mqdefault.jpg)](https://www.youtube.com/watch?v=oT7ajtbqNy8&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=17){target="_blank"}
[Start Module 3 Videos ↗](https://www.youtube.com/watch?v=oT7ajtbqNy8&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=17){target="_blank"}
## 3.1 Image Class Areas (Pie Chart)
One of the biggest limitations of the GEE Charting API is that it cannot create charts from more than 10000000 pixels. While this may seem like a big number, you can easily run into this limit when working with images that cover large areas. If you try creating charts for large regions, you may run into an error such as below:
> *Image.reduceRegion: Too many pixels in the region. Found 159578190, but maxPixels allows only 10000000. Ensure that you are not aggregating at a higher resolution than you intended; that is a frequent cause of this error. If not, then you may set the 'maxPixels' argument to a limit suitable for your computation; set 'bestEffort' to true to aggregate at whatever scale results in 'maxPixels' total pixels; or both.*
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Chart Error'}
knitr::include_graphics('images/gee_charts/chart_error.png')
```
Fortunately, there is a way around it. Earth Engine allows you to aggregate values from very large regions using reducers that have an option to specify a `maxPixels` parameter. You will need to use the appropriate reducer and create a FeatureCollection with the results. The resulting value can then be plotted easily using the charting functions.
Here we take the same dataset as the previous section, but try to summarize the area by class over a much larger region. We use a Grouped Reducer to compute the class areas and post-process the result into a FeatureCollection. If you find the code hard to understand, please review our article on [Calculating Area in Google Earth Engine](https://spatialthoughts.com/2020/06/19/calculating-area-gee/) for explanation.
We set the chart type to `PieChart` and plot the percentage of area of each class in the region.
Below is the list of new styling options applied to the pie chart:
- `pieSliceBorderColor`: Sets the edge color of each pie slice.
- `pieSliceTextStyle`: Sets the text style of pie slice labels.
- `pieSliceText`: Sets the format of the text.
- `sliceVisibilityThreshold`: Sets the threshold below which to group small slices into *others* category.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Pie Chart'}
knitr::include_graphics('images/gee_charts/area_by_class_piechart.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A03-FeatureCollection_Charts%2F01b_Area_By_Class_Pie_Chart_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/03-FeatureCollection_Charts/01b_Area_By_Class_Pie_Chart_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A03-FeatureCollection_Charts%2F01c_Area_By_Class_Pie_Chart_(exercise)){target="_blank"}
```
/ Exercise
// a) Delete the 'geometry' and add a new point at your chosen location
// b) Modify the chart options to show one of the slices separated from the pie.
// c) Print the chart.
// Hint: Use the 'offset' property
// https://developers.google.com/chart/interactive/docs/gallery/piechart#exploding-a-slice
```
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Exercise 04c'}
knitr::include_graphics('images/gee_charts/area_by_class_piechart_exercise.png')
```
## 3.2 FeatureCollection Column Chart
In the previous example, we used the `ui.Chart.feature.byFeature()` function to create a plot from the properties of each feature. There are fewer built-in functions to create different plots from FeatureCollections, but we can always use the GEE API to process our data and create a FeatureCollection to meet our requirements.
Here we take the WRI Global Power Plant Database and create a plot showing total installed capacity by fuel type for the chosen country. The FeatureCollection has one feature for each power plant, so we first need to process the collection to create one feature for each fuel type having a property with the total capacity. We use the a [Grouped Reducer](https://developers.google.com/earth-engine/guides/reducers_grouping) with the `reduceColumns()` function to calculate group statistics on a FeatureCollection.
We then use the `ui.Chart.feature.byFeature()` function to create a Bar Chart.
> Google Charts uses the term *Column Chart* for a vertical bar chart, while the term *Bar Chart* is used for a horizonal bar chart.
Below is the list of new styling options applied to the column chart:
- `backgroundColor`: Sets the background color for the whole chart.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Column Chart'}
knitr::include_graphics('images/gee_charts/group_stats_column_chart.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A03-FeatureCollection_Charts%2F02b_Group_Statistics_Column_Chart_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/03-FeatureCollection_Charts/02b_Group_Statistics_Column_Chart_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A03-FeatureCollection_Charts%2F02c_Group_Statistics_Column_Chart_(exercise)){target="_blank"}
```
// a) Change the country name to your chosen country
// b) Sort the groupFc by 'capacity_mw' property so the bars are plotted
// from largest to smallest values
// c) Print the chart
// Hint: Use the .sort() function
```
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Exercise 02c'}
knitr::include_graphics('images/gee_charts/group_stats_column_chart_exercise.png')
```
# 4. Advanced Charts
[![Start Module 4 Videos](https://img.youtube.com/vi/tm1guEctfOc/mqdefault.jpg)](https://www.youtube.com/watch?v=tm1guEctfOc&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=21){target="_blank"}
[Start Module 4 Videos ↗](https://www.youtube.com/watch?v=tm1guEctfOc&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=21){target="_blank"}
## 4.1 DataTable Charts
The charting helper functions provided by the GEE Javascript API offer a simpler way to create many types of commonly used charts. But in doing so, it offers a subset of the functionality provided by Google Charts API. Whenever you find yourself limited by the built-in charting functions and want additional customization, you can use the `ui.Chart()` function which allows you to specify a Google Charts [DataTable](https://developers.google.com/chart/interactive/docs/reference#DataTable) for creating your chart. There are many options to create a DataTable object but I would recommend using the [Javascript Literal Initializer](https://developers.google.com/chart/interactive/docs/datatables_dataviews#javascriptliteral) which is more explicit and readable compared to other methods. You create a table object with a `cols` key containing column specifications and a `rows` key with the data values.
Here we take a sample dataset from the survey of [Users of open Big Earth data – An analysis of the current state](https://doi.org/10.1016/j.cageo.2021.104916) by Wagemann, J. et. al and reproduce a chart showing *Use of Programming Languages* for using the GEE Charts API.
Below is the list of new styling options applied to the pie chart:
- `annotations.alwaysOutside`: Renders the annotations outside of the bars.
- `annotations.textStyle`: Sets the text style of the annotations.
- `annotations.boxStyle`: Sets the style of the box around annotation text.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='DataTable Column Chart'}
knitr::include_graphics('images/gee_charts/datatable_columnchart.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A04-Advanced_Charts%2F01b_DataTable_Chart_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/04-Advanced_Charts/01b_DataTable_Chart_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A04-Advanced_Charts%2F01c_DataTable_Chart_(exercise)){target="_blank"}
```
// Exercise
// The DataTable now has an additional value with the 'f' key showing the formatted value
// a) Change the chart to show horizonal bars. Hint: Use the type 'BarChart'
// b) Fix the X and Y-axis labels
```
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Exercise 01c'}
knitr::include_graphics('images/gee_charts/datatable_columnchart_exercise.png')
```
## 4.2 Box Plots
Many scientific analysis require showing the spread of values at each data point using a *Box Plot* or a *Whisker Plot*. Google Charts supports this using [Intervals](https://developers.google.com/chart/interactive/docs/gallery/intervals). To display the intervals, we must define a DataTable where certain columns are assigned the `role` of an `interval`.
We start with a Sentinel-2 NDVI Time-Series at a farm polygon showing the median values within the polygon at each observation. We process the results using [Combined Reducers](https://developers.google.com/earth-engine/guides/reducers_intro#combining-reducers) and calculate the minimum, first quartile, second quartile, third quartile and maximum values. Since these values will be used in a DataTable, we apply additional formatting to create a dictionary for each row as per the Javascript literal format.
Below is the list of new styling options applied to the interval chart:
- `intervals`: Sets style of the interval values.
- `interval`: Override the style of selected intervals.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Box Plot'}
knitr::include_graphics('images/gee_charts/box_plot.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A04-Advanced_Charts%2F02b_Box_Plots_(complete)){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/04-Advanced_Charts/02b_Box_Plots_(complete)')}
```
### Exercise
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3A04-Advanced_Charts%2F02b_Box_Plots_(exercise)){target="_blank"}
```
// Exercise
// a) Delete the 'geometry' and add a polygon at your chosen location.
// b) Modify the chart options hide the line connecting the bars.
// c) Print the chart.
// Hint: Set the lideWidth to 0.
```
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Exercise 02c'}
knitr::include_graphics('images/gee_charts/box_plot_exercise.png')
```
# Exporting Charts
The charts produced by Google Earth Engine can be exported in SVG (Scalable Vector Graphics) format. This is a vector format that preserves the full-fidelity of the chart and can be converted to an image format at any resolution. Here are the steps to create a high-resolution graphic from your chart.
1 Once the chart is rendered in the Code Editor, click the arrow next to the chart to view it in a new tab.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gee_charts/export1.png')
```
2. Click the *Download SVG* button.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gee_charts/export2.png')
```
3. You can open the resulting SVG in a graphics software and export it at a chosen resolution from there. You can also use free web-based tools. Visit https://www.svgviewer.dev/ and upload your SVG file.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gee_charts/export3.png')
```
4. Switch to the *.png* tab. Choose the scale factor. The higher the number the higher the resolution of the output file. Click *Download .png* button.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gee_charts/export4.png')
```
You now have a hi-resolution PNG image of your chart.
# Supplement
[![Start Supplement Videos](https://img.youtube.com/vi/wWIDiettodw/mqdefault.jpg)](https://www.youtube.com/watch?v=wWIDiettodw&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=26){target="_blank"}
[Start Supplement Videos ↗](https://www.youtube.com/watch?v=wWIDiettodw&list=PLppGmFLhQ1HKyrR75waIq6TfqL0ESlQao&index=26){target="_blank"}
## Dual Y-Axis Chart
When you are plotting 2 series on a chart that have very different ranges - it makes sense to have 2 separate y-Axes. You can assign the left axis to one series and right axis to another using the `series.targetAxisIndex` option. Here's an example of plotting a monthly NDVI vs Rainfall time-series on the same chart.
```{r echo=FALSE, fig.align='center', out.width='100%', fig.cap='Dual Y-Axis Chart'}
knitr::include_graphics('images/gee_charts/dual_y_axis.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FDual_YAxis_Plots){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Dual_YAxis_Plots')}
```
## Night Time Lights (NTL) Trends
The section on [Time-Series with Trendlines](#time-series-with-trendlines) covered how to add trendlines to the chart. We can apply this technique on a dataset of annual nighttime lights to see the effect of COVID19. We plot two series on a plot and display the trendline for the pre-covid series. This helps show the effect of COVID19 on the trend of nighttime lights.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Annual NTL Trend'}
knitr::include_graphics('images/gee_charts/ntl_trend.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FNight_Time_Lights_Trends){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Night_Time_Lights_Trends')}
```
## Population Time Series
Earth Engine makes it very easy to plot variables over time and compare trends of different regions. Here we take the LandScan population dataset and compare the population of two countries over time.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Population Time-Series'}
knitr::include_graphics('images/gee_charts/population_time_series.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FPopulation_TimeSeries_Chart){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Population_TimeSeries_Chart')}
```
## Daily Time Series Chart
This example shows how to work with Sentinel-5p dataset to aggregate and plot a daily time-series of atmospheric concentrations. Many times when plotting a daily time-series, you would see an shift between the grid labels and the data points. This is because all the GEE datasets have the timestamps in UTC - while the charts are created using your browser's timezone. The offset you see if due to the difference between your timezone and UTC. To avoid this - you can specify a timezone when working with dates in GEE as shown here.
Below is the list of new styling options applied to the time-series chart:
- `slantedText` and `slantedTextAngle`: Apply a rotation the axis labels
- `gridlines.units`: Specify a date format for the tick labels
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='NO2 Daily Time-Series'}
knitr::include_graphics('images/gee_charts/no2_time_series.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FDaily_Time_Series_Chart){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Daily_Time_Series_Chart')}
```
## Surface Water Area Time Series
The [Global Surface Water](https://global-surface-water.appspot.com/) dataset is one of the best Landsat-derived ready-to-use dataset for studying surface water. Using the [JRC Yearly Water Classification History](https://developers.google.com/earth-engine/datasets/catalog/JRC_GSW1_4_YearlyHistory?hl=en), we can calculate the yearly surface water area anywhere in the globe and create a time-series chart. This example also shows how to customize the X-axis labels by supplying a list of Javascript date objects for `ticks` parameter.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Surface Water Area Time-Series'}
knitr::include_graphics('images/gee_charts/surface_water_area.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FSurface_Water_Area_TimeSeries_Chart){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Surface_Water_Area_TimeSeries_Chart')}
```
## Histogram with Reducer
If you wish to compute histogram for a large region, you need to extract the image statistics using `ee.Reducer.fixedHistogram()` and create a FeatureCollection with the resulting values. This will allow you to Export large computations and you can then import the resulting FeatureCollection and use `ui.Chart.feature.byFeature()` to create the histogram.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Histogram of a Large Image'}
knitr::include_graphics('images/gee_charts/histogram_reducer.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FHistogram_with_Reducer){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Histogram_with_Reducer')}
```
## Histogram of Multiple Bands
If you wish to compute a multi-band histogram, we can follow the same method used in the previous section [Histogram with Reducer](#histogram-with-reducer), but use the `ui.Chart.feature.groups()` to create the plot.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Multi-band Histogram'}
knitr::include_graphics('images/gee_charts/multiband_histogram.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FMultiband_Histogram){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Multiband_Histogram')}
```
## Precipitation Combo Chart
Google Charts also supports *Combo Charts* - where each series can be displayed with a different style. Here we create a chart with 2 series - monthly and cumulative precipitation. We can style each series independently using the *style* option. The script also shows how to add a border to the chart and adjust the margins to minimize whitespace.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Precipitation Combo Chart'}
knitr::include_graphics('images/gee_charts/precipitation_combochart.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FPrecipitation_ComboChart){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Precipitation_ComboChart')}
```
## Transect Chart
You can sample values from an image along a line transect and generate a FeatureCollection with latitude, longitude and DN values. This can be then plotted to create a transect chart like below.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gee_charts/transect.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FTransect_Chart){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Transect_Chart')}
```
## Logo Chart
A Table chart allows you to add an image along with any HTML-formatted text. You can use this to display a logo and a description along with a chart in your app.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gee_charts/logo_chart.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FLogo_Chart){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Logo_Chart')}
```
## Stacked Bar Chart (DataTable)
You can use the `isStacked` option to `true` on charts of type *ColumnChart* or *BarChart* to create a stacked chart. We continue with the dataset from the section on [DataTable charts](#datatable-charts) and create a stacked bar chart.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Regular vs. Stacked Bar Charts'}
knitr::include_graphics('images/gee_charts/stacked.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FDataTable_Stacked_BarChart){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/DataTable_Stacked_BarChart')}
```
## Colored Bar Chart (DataTable)
It is possible to assign a different color to each bar of a bar chart. You neeed to create a DataTable with a column having a *style* role and define the color for each row. Here we create a chart that uses a unique color for each bar that representing the year of forest loss. The chart has a one-to-one correspondence with the map palette - making it a very useful tool in interpretation of the spatial and temporal aspects of the trend.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Colored Bar Chart'}
knitr::include_graphics('images/gee_charts/colored_barchart.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FDataTable_Colored_Bars){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/DataTable_Colored_Bars')}
```
## Box Plot with Outliers (DataTable)
Regular box plot displays the whiskers at the minimum and maximum values. A variation of this is to instead first compute the Inter-Quartile Range (IQR) and display whiskers at *1.5 x IQR* above and below the IQR. If the minimum or maximum values fall outside of this range, they are displayed as outlier points. This script calculates the requires values and displays the outlier intervals as points.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Box Plot with Outliers'}
knitr::include_graphics('images/gee_charts/box_plot_with_outliers.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FBox_Plot_with_Outliers){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/Box_Plot_with_Outliers')}
```
## Spectral Profile Charts (DataTable)
Spectral profile charts allow you to review the spectral signature of all bands for different classes. Instead of just displaying mean spectra of multiple pixels, we can use a box plot to show the distribution and central tendency of pixels. The script shows how to automatically extract the requires statistics and create a box plot of spectral profiles for each class.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Spectral Profile Charts'}
knitr::include_graphics('images/gee_charts/spectral_profile.png')
```
[Open in Code Editor ↗](https://code.earthengine.google.co.in/?scriptPath=users%2Fujavalgandhi%2FGEE-Charts%3ASupplement%2FDataTable_Spectral_Profile){target="_blank"}
```{js eval=FALSE, code=readLines('code/gee_charts/Supplement/DataTable_Spectral_Profile')}
```
# References
- Google Earth Engine Developer Guide: [Chart Documentation](https://developers.google.com/earth-engine/guides/charts_overview)
# Data Credits
- Abatzoglou, J.T., S.Z. Dobrowski, S.A. Parks, K.C. Hegewisch, 2018, Terraclimate, a high-resolution global dataset of monthly climate and climatic water balance from 1958-2015, Scientific Data 5:170191, doi:10.1038/sdata.2017.191
- Funk, Chris, Pete Peterson, Martin Landsfeld, Diego Pedreros, James Verdin, Shraddhanand Shukla, Gregory Husak, James Rowland, Laura Harrison, Andrew Hoell & Joel Michaelsen. "The climate hazards infrared precipitation with stations-a new environmental record for monitoring extremes". Scientific Data 2, 150066. doi:10.1038/sdata.2015.66 2015.
- GFS: Global Forecast System 384-Hour Predicted Atmosphere Data. [Source](https://www.emc.ncep.noaa.gov/emc/pages/numerical_forecast_systems/gfs.php)
- MOD13Q1.006 Terra Vegetation Indices 16-Day Global 250m: Didan, K. (2015). MOD13Q1 MODIS/Terra Vegetation Indices 16-Day L3 Global 250m SIN Grid V006 [Data set]. NASA EOSDIS Land Processes DAAC. Accessed 2023-05-06 from https://doi.org/10.5067/MODIS/MOD13Q1.006
- Li, Xuecao; Zhou, Yuyu; zhao, Min; Zhao, Xia (2020): Harmonization of DMSP and VIIRS nighttime light data from 1992-2020 at the global scale. figshare. Dataset. https://doi.org/10.6084/m9.figshare.9828827.v5
- Runfola D, Anderson A, Baier H, Crittenden M, Dowker E, Fuhrig S, et al. (2020) geoBoundaries: A global database of political administrative boundaries. PLoS ONE 15(4): e0231866. https://doi.org/10.1371/journal.pone.0231866
- Sentinel-2 Level-2A: Contains Copernicus Sentinel data.
- Zanaga, D., Van De Kerchove, R., Daems, D., De Keersmaecker, W., Brockmann, C., Kirches, G., Wevers, J., Cartus, O., Santoro, M., Fritz, S., Lesiv, M., Herold, M., Tsendbazar, N.E., Xu, P., Ramoino, F., Arino, O., 2022. ESA WorldCover 10 m 2021 v200. (doi:10.5281/zenodo.7254221)
- Global Energy Observatory, Google, KTH Royal Institute of Technology in Stockholm, Enipedia, World Resources Institute. 2019. Global Power Plant Database. Published on Resource Watch and Google Earth Engine. http://resourcewatch.org/ https://earthengine.google.com/
- Wagemann, Julia, Siemen, Stephan, Seeger, Bernhard, & Bendix, Jörg. (2020). User requirements of Big Earth Data - Survey 2019 (0.1) [Data set]. Zenodo. https://doi.org/10.5281/zenodo.4075058
- Elvidge, C.D, Zhizhin, M., Ghosh T., Hsu FC, Taneja J. Annual time series of global VIIRS nighttime lights derived from monthly averages:2012 to 2019. Remote Sensing 2021, 13(5), p.922, https://doi.org/10.3390/rs13050922
- Sims, K., Reith, A., Bright, E., McKee, J., & Rose, A. (2022). LandScan Global 2021 [Data set]. Oak Ridge National Laboratory. https://doi.org/10.
48690/1527702
- Hansen, M. C., P. V. Potapov, R. Moore, M. Hancher, S. A. Turubanova, A. Tyukavina, D. Thau, S. V. Stehman, S. J. Goetz, T. R. Loveland, A. Kommareddy, A. Egorov, L. Chini, C. O. Justice, and J. R. G. Townshend. 2013. "High-Resolution Global Maps of 21st-Century Forest Cover Change." Science 342 (15 November): 850-53. 10.1126/science.1244693 Data available on-line at: https://glad.earthengine.app/view/global-forest-change.
- Elvidge, C.D, Zhizhin, M., Ghosh T., Hsu FC, Taneja J. Annual time series of global VIIRS nighttime lights derived from monthly averages:2012 to 2019. Remote Sensing 2021, 13(5), p.922, doi:10.3390/rs13050922 doi:10.3390/rs13050922
# License
The course material (text, images, presentation, videos) is licensed under a [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/).
The code (scripts, Jupyter notebooks) is licensed under the MIT License. For a copy, see https://opensource.org/licenses/MIT
You are free to re-use and adapt the material but are required to give appropriate credit to the original author as below:
Copyright © 2023 Ujaval Gandhi [www.spatialthoughts.com](https://spatialthoughts.com)
# Citing and Referencing
You can cite the course materials as follows
* Gandhi, Ujaval, 2023. *Creating Publication Quality Charts with GEE* Course. Spatial Thoughts. https://courses.spatialthoughts.com/gee-charts.html
***