Create charts dynamically in Google Earth Engine

Iago Mendes
5 min readFeb 9, 2024

--

In this post, we'll look at leveraging ui package widgets to create charts dynamically in Google Earth Engine (GEE).

Inspired by Spatial Thoughts' "Creating Publication Quality Charts with GEE" course, this article presents an alternative method for customizing charts in the Code Editor. This approach simplifies creating high-quality charts and offers greater flexibility and control over customization options.

You can access the course material here.

The post is divided into the following parts:

  1. Setting up the environment
  2. Creating the pseudo-DataTable
  3. Selecting the configuration options
  4. Checking the range and type of values for the selected options
  5. Creating the widgets
  6. Defining the callback functions

Setting up the environment

First, we will create two panels, which will initially be empty:

  • chartPanel: used as a container for the chart.
  • controlPanel: used to organize the control widgets.
var chartPanel = ui.Panel({ style: { position: 'top-center' } });
var controlPanel = ui.Panel({ style: { position: 'middle-left' } });

Map.add(chartPanel);
Map.add(controlPanel);

Creating the pseudo-DataTable

In the context of GEE, a DataTable (or pseudo-DataTable) is a data structure that can be represented by a 2-D array or a literal JS object. In both cases, the DataTable must be a client-side object.

Learn more about the DataTable Class.

We will use the same DataTable used in section 4.1 Data Table Charts of the course for simplification.

var dataTable = {
cols: [
{ id: 'language', label: 'Programming Language', type: 'string' },
{ id: 'responses', label: 'Number of Responses', type: 'number' },
{ id: 'percentage', label: 'Percentage', type: 'number', role: 'annotation' },
{ id: 'style', label: 'Style', type: 'string', role: 'style' },
],
rows: [
{ c: [{ v: 'Python' }, { v: 178 }, { v: 77.1 }, { v: 'color: #8dd3c7' }] },
{ c: [{ v: 'R' }, { v: 102 }, { v: 44.2 }, { v: 'color: #ffffb3' }] },
{ c: [{ v: 'Javascript' }, { v: 59 }, { v: 25.5 }, { v: 'color: #bebada' }] },
{ c: [{ v: 'Fortran' }, { v: 37 }, { v: 16 }, { v: 'color: #fb8072' }] },
{ c: [{ v: 'Java' }, { v: 32 }, { v: 13.9 }, { v: 'color: #80b1d3' }] },
{ c: [{ v: 'C++' }, { v: 27 }, { v: 11.7 }, { v: 'color: #fdb462' }] },
{ c: [{ v: 'C' }, { v: 18 }, { v: 7.8 }, { v: 'color: #b3de69' }] },
{ c: [{ v: 'PHP' }, { v: 14 }, { v: 6.1 }, { v: 'color: #fccde5' }] },
{ c: [{ v: 'Julia' }, { v: 6 }, { v: 2.6 }, { v: 'color: #d9d9d9' }] },
{ c: [{ v: 'Scala' }, { v: 3 }, { v: 1.3 }, { v: 'color: #bc80bd' }] },
],
};

Selecting the configuration options

For each type of chart, dozens of configuration options can be adjusted.

In this article, we will work with a BarChartand adjust the chartArea.left, chartArea.top, chartArea.width and chartArea.height settings.

Checking the range and type of values for the selected options

In the configuration options table, we can obtain important information, such as the type of data the option requires and in which units we must provide it.

We will use percentages instead of pixels to work with the standard 0 to 100% range.

Creating the widgets

First, we will create a JS literal object that will store the configuration options for our chart.

var options = {
title: 'Use of Programming Languages by Users of Big Earth Data'
};

Then, we will create a ui.Slider for each option we will adjust.

var chartAreaLeft = ui.Slider(0, 100, 0, 1);
var chartAreaTop = ui.Slider(0, 100, 0, 1);
var chartAreaWidth = ui.Slider(0, 100, 0, 1);
var chartAreaHeight = ui.Slider(0, 100, 0, 1);

Note: if we were working with boolean configuration options, we could use a ui.Checkbox; if it were an option that receives a string with the name or hexadecimal code of a color, we could use a ui.Textbox.

Defining the callback functions

For each option, we will create a function that:

  • Adds the options to the options object if it does not exist.
  • Updates the configuration option value from the widget value.
  • Calls the drawChart function, which handles creating and updating the chart in the panel.
var drawChart = function() {
var chart = ui.Chart(dataTable, 'BarChart', options);
chartPanel.widgets().reset([chart]);
};

var updateChartAreaLeft = function(value) {
if (!options.chartArea) options.chartArea = {};
options.chartArea.left = value + '%';
drawChart();
};

var updateChartAreaTop = function(value) {
if (!options.chartArea) options.chartArea = {};
options.chartArea.top = value + '%';
drawChart();
};

var updateChartAreaWidth = function(value) {
if (!options.chartArea) options.chartArea = {};
options.chartArea.width = value + '%';
drawChart();
};

var updateChartAreaHeight = function(value) {
if (!options.chartArea) options.chartArea = {};
options.chartArea.height = value + '%';
drawChart();
};

We can organize all the information — widgets and callback functions — into an array of objects and use forEach to compose the controlPanel.

var components = [
{
widget: chartAreaLeft,
callback: updateChartAreaLeft,
name: 'chartArea.left',
},
{
widget: chartAreaTop,
callback: updateChartAreaTop,
name: 'chartArea.top',
},
{
widget: chartAreaWidth,
callback: updateChartAreaWidth,
name: 'chartArea.width',
},
{
widget: chartAreaHeight,
callback: updateChartAreaHeight,
name: 'chartArea.height',
},
];


var populateControlPanel = function (components) {
var widget = components.widget;
var callback = components.callback;
var name = components.name;

var nameLabel = ui.Label(name, {
textAlign: 'right',
stretch: 'horizontal',
});

widget.onSlide(callback);
widget.style().set('width', '150px');

var innerPanel = ui.Panel([nameLabel, widget]);
innerPanel.setLayout(ui.Panel.Layout.flow('horizontal'));

controlPanel.widgets().add(innerPanel);
};

components.forEach(populateControlPanel);

The outcome will look like this::

In this script, you can access a more complete version of this exercise, with more options already defined.

--

--