ウィジェット

UI の作成に使用できるウィジェットはさまざまです。これらのウィジェットには、ボタン、チェックボックス、スライダー、テキスト ボックス、選択メニューなどがあります。ウィジェットを印刷またはパネルに追加できるのは 1 回だけです。以降のセクションでは、ウィジェットの基本的な機能と外観について説明します。ウィジェットのスタイル設定について詳しくは、スタイルのセクションをご覧ください。次の例では、ウィジェットをコンソールに print() します。パネルにウィジェットを追加する方法については、パネルとレイアウトのページをご覧ください。

ui.Label

ラベルは、テキストを表示する領域にすぎません。たとえば、次のコードはラベルを出力します。

コードエディタ(JavaScript)

var label = ui.Label('Cool label!');
print(label);

次のような形式になります。

ui_label.png

長いラベルを分割するには、改行文字(\n)を挿入し、whiteSpace スタイル プロパティ引数を 'pre' に設定します。

print(ui.Label('Here is a:\nnew line', {whiteSpace: 'pre'}));

ui.Button

ボタンは、クリック可能なインタラクティブな UI ウィジェットです。ユーザーがボタンをクリックしたときに呼び出される関数(「コールバック」関数)を指定できます。(コールバック関数によるイベント処理の詳細については、イベント ページをご覧ください)。次の例では、ボタンがクリックされたときに地図の現在の中心を表示します。

コードエディタ(JavaScript)

var button = ui.Button({
  label: 'Get Map Center',
  onClick: function() {
    print(Map.getCenter());
  }
});
print(button);

次のような形式になります。

ui_button.png

ui.Checkbox

チェックボックスは、ユーザーがボックスをオンまたはオフにできるウィジェットです。チェックボックスの状態が変更されると、ウィジェットに登録されているコールバックに、チェックボックスがオンになっているかどうかを示すブール値が渡されます。次に例を示します。

コードエディタ(JavaScript)

var checkbox = ui.Checkbox('Show SRTM layer', true);

checkbox.onChange(function(checked) {
  // Shows or hides the first map layer based on the checkbox's value.
  Map.layers().get(0).setShown(checked);
});

Map.addLayer(ee.Image('CGIAR/SRTM90_V4'));
print(checkbox);

印刷されたチェックボックスは次のようになります。

ui_checkbox.png

チェックボックスをオンにすると、地図にレイヤが表示されます。他の UI コンポーネントと同様に、Code Editor のマップはプログラムで操作できます。Map オブジェクトの詳細については、パネルとレイアウトのページをご覧ください。

ui.Slider

スライダーは、ユーザーがスライダーを調整してスライダーの範囲内の数値を取得できるようにするウィジェットです。範囲は、コンストラクタを使用するか、スライダーのプロパティを設定して構成します。次の例では、スライダーを使用して地図の最初のレイヤの不透明度を設定しています。

コードエディタ(JavaScript)

var slider = ui.Slider();

slider.setValue(0.9);  // Set a default value.
slider.onChange(function(value) {
  Map.layers().get(0).setOpacity(value);
});

Map.addLayer(ee.Image(255), {palette: 'blue'});
print(slider);

スライダーは次のようになります。

ui_slider.png

スライダーの値はスライダーの右側に表示されます。

ui.DateSlider

DateSlider ウィジェットは Slider ウィジェットと似ていますが、日付を明示的に処理します。2018 年 6 月の日付を選択するように構成された DateSlider は次のようになります。

DateSlider.png

DateSlider は、コレクションのフィルタリングに役立ちます。次の例では、DateSlider に設定された DateRange に基づいて年間の複合体を作成しています。

コードエディタ(JavaScript)

// Use a DateSlider to create annual composites of this collection.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1');
// Use the start of the collection and now to bound the slider.
var start = ee.Image(collection.first()).date().get('year').format();
var now = Date.now();
var end = ee.Date(now).format();

// Run this function on a change of the dateSlider.
var showMosaic = function(range) {
  var mosaic = ee.Algorithms.Landsat.simpleComposite({
    collection: collection.filterDate(range.start(), range.end())
  });
  // Asynchronously compute the name of the composite.  Display it.
  range.start().get('year').evaluate(function(name) {
    var visParams = {bands: ['B4', 'B3', 'B2'], max: 100};
    var layer = ui.Map.Layer(mosaic, visParams, name + ' composite');
    Map.layers().set(0, layer);
  });
};

// Asynchronously compute the date range and show the slider.
var dateRange = ee.DateRange(start, end).evaluate(function(range) {
  var dateSlider = ui.DateSlider({
    start: range['dates'][0],
    end: range['dates'][1],
    value: null,
    period: 365,
    onChange: showMosaic,
    style: {width: '180px'}
  });
  Map.add(dateSlider.setValue(now));
});

// Initialize the map location at southern Africa.
Map.setCenter(23.861, -27.144, 6);

ui.Textbox

テキスト ボックスは、ユーザーが入力したテキストを収集する場所です。次に例を示します。

コードエディタ(JavaScript)

var textbox = ui.Textbox({
  placeholder: 'Enter text here...',
  onChange: function(text) {
    print('So what you are saying is ' + text + '?');
  }
});
print(textbox);

テキスト ボックスは次のようになります。

ui_textbox.png

コールバックは、ユーザーがテキストの入力を終了したとき(Return キーを押したとき)またはユーザーがテキスト ボックスから離れたときにのみ呼び出されます。

ui.Select

選択ウィジェットは、ユーザーが選択できる選択肢のプルダウン メニューを表します。次の例は、ユーザーが場所を選択できるようにするプルダウン メニューを示しています。

コードエディタ(JavaScript)

var places = {
  MTV: [-122.0849, 37.3887],
  PEK: [116.4056, 39.9097],
  ZRH: [8.536, 47.376]
};

var select = ui.Select({
  items: Object.keys(places),
  onChange: function(key) {
    Map.setCenter(places[key][0], places[key][1]);
  }
});

// Set a place holder.
select.setPlaceholder('Choose a location...');

print(select);

選択ウィジェットは次のようになります。

ui_select.png

ui.Chart

ui.Chart パッケージのグラフは、Chart パッケージのグラフと同様に動作します。具体的には、ui.Chart は Google Visualization API の ChartWrapper のインスタンスの周囲にある薄いシェルです。ChartWrapper オブジェクトの操作の詳細については、こちらのリファレンスをご覧ください。Earth Engine のグラフ ヘルパー関数の詳細については、グラフのドキュメントをご覧ください。

ui.Thumbnail

サムネイル ウィジェットを使用すると、ee.Image オブジェクトと ee.ImageCollection オブジェクトをプレビューできます。ee.Image を指定すると、ウィジェットは静止画像を表示します。ee.ImageCollection を指定すると、入力の画像ごとに 1 つのフレームを含むアニメーションが表示されます。ee.Image.getThumbURL()ee.ImageCollection.getVideoThumbURL() と同様に、パラメータを指定して、生成されるサムネイルの形式とサイズを制御できます。

コードエディタ(JavaScript)

// Create a box around an area in the Brazilian Amazon.
var box = ee.Geometry.Polygon([[
  [-62.9564, 2.5596], [-62.9550, 2.4313], [-62.8294, 2.4327], [-62.8294, 2.5596]
]]);

// Visualize the image in RGB.
var image = ee.Image('LANDSAT/LE07/C02/T1_L2/LE07_233058_20011113')
                .select(['SR_B[1-3]'])  // blue, green, red reflectance
                .multiply(0.0000275).add(-0.2)  // apply scaling factors
                .visualize({
                  bands: ['SR_B3', 'SR_B2', 'SR_B1'],
                  min: 0,
                  max: 0.12,
                  gamma: 1.3
                });

// Print a thumbnail to the console.
print(ui.Thumbnail({
  image: image,
  params: {dimensions: '256x256', region: box, format: 'png'},
  style: {height: '300px', width: '300px'}
}));

サムネイルは次のようになります。

ui_thumbnail.png

ui.Map

ui.Map は地図ウィジェットです。(実際、デフォルトの Code Editor Map は、このクラスのインスタンスです)。他のウィジェットと同様に、地図をコンソールに印刷できます。個々のレイヤを消去、取得、設定して、地図のコンテンツを操作します。次の例は、Code Editor のマップの境界を示すマップをコンソールに出力します。

コードエディタ(JavaScript)

// Make a little map.
var map = ui.Map();

// Make the little map display an inset of the big map.
var createInset = function() {
  var bounds = ee.Geometry.Rectangle(Map.getBounds());
  map.centerObject(bounds);
  map.clear();
  map.addLayer(bounds);
};

// Run it once to initialize.
createInset();

// Get a new inset map whenever you click on the big map.
Map.onClick(createInset);

// Display the inset map in the console.
print(map);

インセット地図は次のようになります。

ui_map.png

この例では、ユーザーが大きな地図をクリックして、小さな地図にインセットを描画する必要があります。

地図インスタンスで layers() を呼び出して、地図上のレイヤを操作することもできます。layers() は、配列のようなオブジェクトである ui.data.ActiveList を返します。変更すると、地図のレイヤも変更されます。詳しくは、ui.Map.Layer セクションをご覧ください。

ui.Map.Layer

レイヤは、ui.Button のようなスタイル設定可能なウィジェットではありません。これは、地図上のレイヤのデータ表現にすぎません。次の例は、レイヤを作成し、ユーザー入力に基づいてレイヤのプロパティを更新することで地図を更新する方法を示しています。

コードエディタ(JavaScript)

var consoleMap = ui.Map({
  lon: -2.0174,
  lat: 48.6474,
  zoom: 13
});

// Create a Layer from this Sentinel-2 image
var image = ee.Image('COPERNICUS/S2/20150821T111616_20160314T094808_T30UWU');
var visParams = {bands: ['B4', 'B3', 'B2'], max: 2048, gamma: 1};
var layer = ui.Map.Layer(image, visParams);

// Update the map by updating the layers list.
var layers = consoleMap.layers();
layers.add(layer);

// Make a textbox to accept a gamma value.
// Update the layer when the gamma value is entered.
var gammaBox = ui.Textbox({
  value: 1,
  onChange: function(value) {
    // visParams is NOT an ActiveDictionary, so set it again.
    visParams.gamma = value;
    layer.setVisParams(visParams);
  }
});

print(ui.Label('Enter a gamma value:'));
print(gammaBox);
print(consoleMap);

ui.Map.CloudStorageLayer

計算コストが比較的高いレイヤを表示する場合(例: アプリ内)、パフォーマンス上の理由から、データを Cloud Storage バケットにエクスポートすることをおすすめします。これらの静的な可視化専用レイヤを使用すると、アプリとスクリプトの応答性が向上します。この目的のために、Export.map.toCloudStorage() を使用して静的ディスプレイ レイヤを作成できます。Export.map.toCloudStorage() で以前にエクスポートしたタイルセットを使用するには、指定した Cloud Storage バケットとパスから新しい ui.Map.Layer を作成します。

Map.add(ui.Map.CloudStorageLayer({
  bucket: 'earthenginepartners-hansen',
  path: 'tiles/gfc_v1.4/loss_year',
  maxZoom: 12,
  suffix: '.png'
}));

Cloud Storage レイヤを読み込むスクリプトを実行すると、次のような警告メッセージが表示されることがあります。

雲層に関する警告

ui.Map.DrawingTools

コードエディタの Map には、デフォルトでジオメトリ描画ツールのセットが追加されています。デフォルトの Map でこれらのツールの動作を変更するには、Map.drawingTools() を呼び出します。たとえば、描画ツールを非表示にするには:

コードエディタ(JavaScript)

Map.drawingTools().setShown(false);

新しく作成された地図にはデフォルトで描画ツールが設定されていませんが、地図で drawingTools() メソッドを呼び出すと有効にできます。

コードエディタ(JavaScript)

var map = ui.Map();
// Prints true since drawingTools() adds drawing tools to the map.
print(map.drawingTools().getShown());
// Replace the default Map with the newly created map.
ui.root.widgets().reset([map]);

描画ツールで描画されたジオメトリ レイヤは ui.data.ActiveList に格納され、Map.drawingTools().layers() を呼び出してアクセスできます。ジオメトリ レイヤリストは、Map.layers() によって返される Map のレイヤのリストなど、他のアクティブなリストと同様にイベントに応答します。次の例は、ツールによって描画されるジオメトリ レイヤ(デフォルトで表示)の可視性を設定する方法を示しています。

コードエディタ(JavaScript)

Map.drawingTools().layers().forEach(function(layer) {
  layer.setShown(false);
});

レイヤをプログラムで描画ツールに追加するには、描画ツールで addLayer メソッドを呼び出すか、レイヤリストにレイヤを直接追加します。

コードエディタ(JavaScript)

var geometries = [ee.Geometry.Point([0,0]), ee.Geometry.Rectangle([[0,0], [1,1]])];
Map.drawingTools().addLayer(geometries, 'my_geometry1', 'red');

var layer = ui.Map.GeometryLayer(geometries, 'my_geometry2', 'blue');
Map.drawingTools().layers().add(layer);

描画ツールの状態も、アプリを公開するときに引き継がれます。描画ツールを表示または非表示にしている場合は、アプリでも表示または非表示になります。インポートしたジオメトリもアプリに引き継がれます。

ui.Map.GeometryLayer

GeometryLayer は、単一の GeometryGeometryCollection、または FeatureCollection として機能するジオメトリのコレクションです。スクリプトの上部にある imports セクションに追加され、コードで参照できます。

描画ツールによって描画される GeometryLayer にはデフォルトの動作があり、新しいコールバック関数を指定することでオーバーライドできます。たとえば、ジオメトリをインタラクティブに変更してイベントをトリガーするとします。特定の動作を実装するには、ツールに onEdit()onErase()、または onDraw() メソッドを設定して、ユーザー操作に応答します。次の例は、ユーザーがジオメトリを追加、編集、消去したときに計算をトリガーし、計算結果でラベルを更新する方法を示しています。

コードエディタ(JavaScript)

// Load elevation data.
var srtm = ee.Image('USGS/SRTMGL1_003');
Map.addLayer(srtm, {min: 0, max: 5000}, 'SRTM');

// Make a label to display mean elevation at drawn points.
var label = new ui.Label('Draw points to calculate mean elevation');
var inspector = new ui.Panel([label]);
Map.add(inspector);
// Don't make imports that correspond to the drawn points.
Map.drawingTools().setLinked(false);
// Limit the draw modes to points.
Map.drawingTools().setDrawModes(['point']);
// Add an empty layer to hold the drawn points.
Map.drawingTools().addLayer([]);
// Set the geometry type to be point.
Map.drawingTools().setShape('point');
// Enter drawing mode.
Map.drawingTools().draw();

// This function gets called when the geometry layer changes.
// Use debounce to call the function at most every 100 milliseconds.
var getAverageElevation = ui.util.debounce(function() {
  var points = Map.drawingTools().layers().get(0).toGeometry();
  var elevation = srtm.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry: points,
    scale: 30
  }).get('elevation');
  // Asynchronously evaluate the mean elevation.
  elevation.evaluate(showElevation);
}, 100);

// Set the callback function on changes of the geometry layer.
Map.drawingTools().onEdit(getAverageElevation);
Map.drawingTools().onDraw(getAverageElevation);
Map.drawingTools().onErase(getAverageElevation);

// Set the label to the result of the mean reduction.
function showElevation(elevation) {
  inspector.clear();
  var elevationLabel = ui.Label('Mean elevation: ' + elevation);
  inspector.add(elevationLabel);
}

setLinked() は、ジオメトリ描画ツールと Code Editor の [Imports] セクションとの接続を切り替えるために使用されます。この例では、ジオメトリ ツールのリンクを解除して、インポートが作成されないようにしています。toGeometry は、レイヤを ee.Geometry に変換するために使用されます。インポートされたレイヤが Feature または FeatureCollection を表す場合は、getEeObject() を使用して基盤となる EE オブジェクトを取得できます。また、ジオメトリの移動ごとにコールバック関数がトリガーされないように ui.util.debounce を使用していることにも注意してください。具体的には、前回のイベントから 100 ミリ秒が経過するまで関数はトリガーされません。これにより、ユーザーが編集アクションを完了したときにのみ関数が実行されるようになります。

インポートのジオメトリ レイヤは Geometry または GeometryCollection に関連付けられているため、GeoJSON 形式ではジオメトリのコレクションに単一のジオデシック状態のみを許可するため、同じジオデシック状態のジオメトリのみを含めることができます(詳細については、ジオデシック ジオメトリと平面ジオメトリのページをご覧ください)。レイヤ名の横にある歯車アイコンを押してジオメトリ レイヤを FeatureCollection に変換すると、ジオデシック ジオメトリと平面ジオメトリを同じレイヤに追加できます。ただし、これを Geometry に戻すとエラーが発生します。これを回避するには、FeatureCollection に変換するか、レイヤにジオデシック状態が 1 つだけになるまでジオメトリを削除します。

ui.Map.Linker

レイヤと同様に、リンカーはスタイル設定可能なウィジェットではありません。これは、複数の ui.Map インスタンスの移動を同期するために使用できるバックグラウンド ユーティリティです。

コードエディタ(JavaScript)

// Add two maps to the screen.
var left = ui.Map();
var right = ui.Map();
ui.root.clear();
ui.root.add(left);
ui.root.add(right);

// Link the "change-bounds" event for the maps.
// When the user drags one map, the other will be moved in sync.
ui.Map.Linker([left, right], 'change-bounds');

ui.SplitPanel

ui.SplitPanel は、並べて比較する場合に便利です。2 つの通常のパネルと比較した場合の ui.SplitPanel の利点は、ハンドルを使用して ui.SplitPanel 内のパネル間でワイプ遷移を実現できることです。次の例では、ui.SplitPanel を使用して火傷痕のスペクトルの違いを表示します。

コードエディタ(JavaScript)

// Load an image of the Santa Rosa, California 2017 fires.
var image = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_045033_20171011');

// Add a color-SWIR composite to the default Map.
Map.setCenter(-122.6624, 38.5011, 12);
Map.addLayer(image, {bands: ['B7', 'B5', 'B3'], max: 0.3}, 'color-SWIR');

// Make another map and add a color-NIR composite to it.
var linkedMap = ui.Map();
linkedMap.addLayer(image, {bands: ['B5', 'B4', 'B3'], max: 0.3}, 'color-NIR');
// Add a thermal image to the map.
linkedMap.addLayer(image, {
  bands: ['B11'],
  min: 290,
  max: 305,
  palette: ['gray', 'white', 'yellow', 'red']
}, 'Thermal');

// Link the default Map to the other map.
var linker = ui.Map.Linker([ui.root.widgets().get(0), linkedMap]);

// Make an inset map and add it to the linked map.
var inset = ui.Map();
inset.style().set({position: 'bottom-right', width: '300px', height: '250px'});
inset.setControlVisibility({all: false, mapTypeControl: true});
linkedMap.add(inset);

// Register a function to the linked map to update the inset map.
linkedMap.onChangeBounds(function() {
  var bounds = ee.Geometry.Rectangle(Map.getBounds());
  inset.centerObject(bounds);
  inset.layers().set(0, bounds);
});

// Create a SplitPanel which holds the linked maps side-by-side.
var splitPanel = ui.SplitPanel({
  firstPanel: linker.get(0),
  secondPanel: linker.get(1),
  orientation: 'horizontal',
  wipe: true,
  style: {stretch: 'both'}
});

// Set the SplitPanel as the only thing in root.
ui.root.widgets().reset([splitPanel]);

ユーザーが 2 つのビジュアリゼーション間でハンドルをスワイプできるように、wipe パラメータは ui.SplitPanel コンストラクタで true に設定されています。

ウィジェットのスタイル設定

ウィジェットのスタイルは、ウィジェットのスタイル プロパティのディクショナリで制御されます。ウィジェットで style() を呼び出すと、辞書にアクセスできます。style() から返されるオブジェクトは ui.data.ActiveDictionary のインスタンスです。つまり、スタイル辞書のプロパティを設定すると、ウィジェットの表示方法が自動的に更新されます。各ウィジェットのスタイル ディクショナリで使用できるキーについては、style() 呼び出しに関するウィジェットのリファレンス ドキュメントをご覧ください。

ウィジェットのスタイルは、コンストラクタで設定するか、style().set() を呼び出すか、辞書引数を指定して style() を呼び出すことで設定できます。次に例を示します。

コードエディタ(JavaScript)

var redLabel = ui.Label('Big, Red Label');

redLabel.style().set('color', 'red');
redLabel.style().set('fontWeight', 'bold');
redLabel.style().set({
  fontSize: '32px',
  padding: '10px'
});

print(redLabel);

この例では、まずキーと値の引数で style().set() を呼び出し、次にディクショナリ引数で style().set() を呼び出して、ラベルにスタイルを設定しています。2 回目の呼び出しは 1 回目の呼び出しをオーバーライドしません。スタイル辞書全体を置き換えるのではなく、個々のスタイル プロパティを追加して置き換えます。

ウィジェットのスタイル設定オプションの詳細については、各ウィジェットの style() ドキュメントに記載されているスタイルについて、こちらのCSS リファレンスをご覧ください。Earth Engine ウィジェットで使用できるスタイルは、いくつかの点で CSS スタイルと異なります。特に、font-stylefont-weightfontSizefontWeight が異なります。

スタイル辞書には、ウィジェットの位置を制御するキーも含まれています。位置プロパティの使用方法については、パネルとレイアウトのページをご覧ください。