Earth Engine User Interfaces and Apps
#GeoForGood19
How to build awesome UI in Earth Engine
Sufyan Abbasi
sufy@google.com
#GeoForGood19
How to think like a Google frontend engineer
Sufyan Abbasi
sufy@google.com
#GeoForGood19
UI is Challenging
It’s easy to go overboard!
#GeoForGood19
UI is Subjective
Two Internet Browsers, circa 1999
#GeoForGood19
Humans are asynchronous ⏰
“ I’ll let you know when I get to it! ”
#GeoForGood19
Goals for this session:
#GeoForGood19
Logistics
Or:
✨ Go to this app: sufy.users.earthengine.app/view/g4g-ui-apps ✨
#GeoForGood19
UI and Apps in Earth Engine
#GeoForGood19
#GeoForGood19
When Printing to the Console is Not Enough
#GeoForGood19
Earth Engine Apps are built from Widgets
#GeoForGood19
What kind of Widgets do we have in Earth Engine?
#GeoForGood19
What kind of Widgets do we have in Earth Engine?
#GeoForGood19
Display Widget: ui.Label
ui.Label
ui.Chart
ui.Thumbnail
var label = ui.Label("Hello!");
label.setValue("Changed label.");
label.setUrl("https://earthengine.google.com");
Map.add(label);
#GeoForGood19
Display Widget: ui.Chart
ui.Label
ui.Chart
ui.Thumbnail
var chart = ui.Chart.image.series(
ndvi, point, ee.Reducer.mean(), 200);
chart.setOptions({
title: 'NDVI Over Time',
vAxis: {title: 'NDVI'},
hAxis: {
title: 'date',
format: 'MM-yy',
gridlines: {count: 7},
},
});
Map.add(chart);
#GeoForGood19
Display Widget: ui.Thumbnail
ui.Label
ui.Chart
ui.Thumbnail
ui.Thumbnail({
image: collection,
params: {
crs: 'EPSG:3857',
dimensions: '300',
region: rect,
min: -2000,
max: 10000,
palette: 'black, blanchedalmond, green, green',
framesPerSecond: 12,
}
});
See: Animated Thumbnail Example
#GeoForGood19
What kind of Widgets do we have in Earth Engine?
#GeoForGood19
Input Widget: ui.Buttons
ui.Button
ui.CheckBox
ui.DateSlider
ui.Select
ui.Textbox
var button = ui.Button("Click me!");
button.onClick(function() {
print("I was clicked");
});
Map.add(button);
#GeoForGood19
Input Widget: ui.Checkbox
ui.Button
ui.CheckBox
ui.DateSlider
ui.Select
ui.Textbox
var checkbox = ui.Checkbox("Check me!");
checkbox.onChange(function(isChecked) {
if (isChecked) {
print("I'm checked");
} else {
print("I'm unchecked");
}
});
Map.add(checkbox);
#GeoForGood19
Input Widget: ui.DateSlider
ui.Button
ui.CheckBox
ui.DateSlider
ui.Select
ui.Textbox
var dateSlider = ui.DateSlider({
start: "2019-09-10",
end: "2019-09-20",
value: "2019-09-16",
});
dateSlider.onChange(function(dateRange) {
print(dateRange);
});
Map.add(dateSlider);
#GeoForGood19
Input Widget: ui.Select
ui.Button
ui.CheckBox
ui.DateSlider
ui.Select
ui.Textbox
var select = ui.Select(
['Option1', 'Option2', 'Option3'],
"Select an Option");
select.onChange(function(selected) {
print("Selected Option: " + selected);
});
Map.add(select);
#GeoForGood19
Input Widget: ui.Textbox
ui.Button
ui.CheckBox
ui.DateSlider
ui.Select
ui.Textbox
var textbox = ui.Textbox("Type Something");
textbox.onChange(function(text) {
print("Typed: " + text);
});
print(textbox.getValue());
Map.add(textbox);
#GeoForGood19
What kind of Widgets do we have in Earth Engine?
#GeoForGood19
Layout Widget: ui.Map
ui.Map
ui.Panel
ui.SplitPanel
var map = ui.Map();
ui.root.clear();
ui.root.add(map);
map.addLayer(...);
map.onClick(...);
#GeoForGood19
Layout Widget: ui.Panel
ui.Map
ui.Panel
ui.SplitPanel
var panel = ui.Panel();
var title = ui.Label("Mini Map:");
panel.add(title);
panel.add(ui.Map());
panel.setLayout(
ui.Panel.Layout.flow("vertical"))
Map.add(panel);
#GeoForGood19
Layout Widget: ui.SplitPanel
ui.Map
ui.Panel
ui.SplitPanel
var leftMap = ui.Map();
var rightMap = ui.Map();
var splitPanel = ui.SplitPanel({
firstPanel: leftMap,
secondPanel: rightMap,
wipe: true, // false for resizable panels
orientation: "horizontal",
});
ui.root.clear();
ui.root.add(splitPanel);
#GeoForGood19
How do I work with widgets?
#GeoForGood19
But first, some JavaScript!
#GeoForGood19
Functions
A function is a block of code that executes when you call it by its name. They may also accept some inputs:
function sayHello(name) {
return "Hello, my name is " + name;
}
print(sayHello("Sufyan"));
Console Output:
> Hello, my name is Sufyan
#GeoForGood19
Dictionaries
An object is a data structure that allows you store key-value pairs. Input a key and it returns the value that you passed in:
var imageCollections = {
landsat: 'LANDSAT/LC08/C01/T1_RT',
sentinel: 'COPERNICUS/S5P/NRTI/L3_NO2',
}
print(imageCollections.landsat)
print(imageCollections['sentinel'])
imageCollections.srtm = 'CGIAR/SRTM90_V4’
Console Output:
> LANDSAT/LC08/C01/T1_RT
> COPERNICUS/S5P/NRTI/L3_NO2
#GeoForGood19
How do I work with widgets?
#GeoForGood19
Widget Workflow
print("I was clicked.");
});
button.style().set('position', 'top-right');
#GeoForGood19
A more compact form:
var button = ui.Button({
label: "Click Me",
onClick: function() {
print("I was clicked.");
},
style: {
color: 'red',
position: 'top-right',
},
});
Map.add(button);
#GeoForGood19
Result:
#GeoForGood19
How do I make my widgets useful?
#GeoForGood19
Event Handling: making your widgets interactive
By binding an event handler, or callback, to a user event, you can execute a function when the user does something.
#GeoForGood19
Event Handling: making your widgets interactive
By binding an event handler, or callback, to a user event, you can execute a function when the user does something.
Click Me!
ui.Button("Click Me!")
OnClick Handler
I was clicked!
Clicked.
button.onClick(function() {
button.setLabel("Clicked.");
})
Update the UI
#GeoForGood19
Event Handling Patterns
textbox.onChange(function(value, widget) {
print("Widget: " + widget + " has value: " + value);
});
#GeoForGood19
How do I make my app pretty?
#GeoForGood19
Making Layouts with ui.Panel and ui.Map
EE Apps “Bread and Butter” Template:
#GeoForGood19
Making Layouts with ui.Panel and ui.Map
Step 1: Make the side panel.
var sidePanel = ui.Panel({
layout: ui.Panel.Layout.flow('vertical'),
style: {
height: '100%',
width: '30%',
},
})
#GeoForGood19
Making Layouts with ui.Panel and ui.Map
Step 2: Make the map and legend.
var map = ui.Map();
var legendPanel = ui.Panel({
widgets: [ui.Label("Legend")],
layout: ui.Panel.Layout.flow('vertical'),
style: {
position: 'bottom-right',
},
});
map.add(legendPanel);
#GeoForGood19
Making Layouts with ui.Panel and ui.Map
Step 3: Combine the side panel and map into a ui.SplitPanel:
var splitPanel = ui.SplitPanel({
firstPanel: sidePanel,
secondPanel: map,
});
#GeoForGood19
Making Layouts with ui.Panel and ui.Map
Step 4: Clear the ui.root and add the split panel:
ui.root.clear();
ui.root.add(splitPanel);
#GeoForGood19
All that’s left...
#GeoForGood19
All that’s left… is the hard part.
#GeoForGood19
Example: NDVI Explorer (see Logistics)
#GeoForGood19
Styling Widgets
You can style widgets two ways:
style: {
height: '100%',
width: '30%',
position: 'bottom-right'
}
widget.style().set('position': 'bottom-right');
#GeoForGood19
Styling Widgets
Easy styling properties (they use CSS syntax)
Property | Function | Example Values |
padding | Puts padding around the widget | '10px' '10px 0px' '10px 5px 0px 5px' |
margin | Adds space between widgets | '10px' '10px 0px' '10px 5px 0px 5px' |
color | Changes the font color | 'white' 'rgb(255,255,255)' '#ffffff' |
backgroundColor | Changes the background color | 'white' 'rgb(255,255,255)' '#ffffff' |
fontWeight | Changes font weight | 'bold' 'lighter' '100' |
#GeoForGood19
Earth Engine User Interfaces and Apps
Intro to EE UI
Sufyan Abbasi
sufy@google.com
#GeoForGood19