<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 🏭 Coal Plant ON/OFF
Step1:  🛎️ [DON’T PANIC] It’s safe to ignore the warnings.
When we pip install the requirements, there might be some warnings about conflicting dependency versions.
For the scope of this sample, that’s ok.
⚠️ Restart the runtime
Step2:  🗺️ Authenticate to Earth Engine
In order to use the Earth Engine API, you'll need to have an Earth Engine account.
To create an account, fill out the registration form here.
Step3:  🚏 Overview
This notebook leverages geospatial data from Google Earth Engine, and labeled data provided by the organization Climate TRACE. By combining these two data sources, you'll build and train a model that predicts whether or not a power plant is turned on and producing emissions.
🛰️ Data (inputs)
The data in this example consists of images from a satellite called Sentinel-2, a wide-swath, high-resolution, multi-spectral imaging mission for land monitoring studies.
When working with satellite data, each input image has the dimensions [width, height, bands]. Bands are measurements from specific satellite instruments for different ranges of the electromagnetic spectrum. For example, Sentinel-2 contains 🌈 13 spectral bands. If you're familiar with image classification problems, you can think of the bands as similar to an image's RGB (red, green, blue) channels. However, when working with satellite data we generally have more than just 3 channels.
🏷️ Labels (outputs)
For each patch of pixels (an image of a power plant) that we give to the model, it performs binary classification, which indicates whether the power plant is on or off.
In this example, the output is a single number between 0 (Off) and 1 (On), representing the probability of that power plant being ON.
Model (function)
TL;DR
The model will receive a patch of pixels, in the center is the power plant tower. We take 16 pixels as padding creating a 33x33 patch. The model returns a classification of ON/OFF
In this example, we have a CSV file of labels. Each row in this file represents a power plant at a specific lat/lon and timestamp. At training time we'll prepare a dataset where each input image is a single pixel that we have a label for. We will then add padding around that image. These padded pixels will not get predictions, but will help our model to make better predictions for the center point that we have a label for.
For example, with a padding of 16, each 1 pixel input point would become a 33x33 image after the padding is added.
The model in this sample is trained for image patches where a power plant is located in the center, and the dimensions must be 33x33 pixels where each pixel has a constant number of bands.
1. 🛰️ Get the training data
The training data in this sample comes from two places
Step4:  🏷️ Import labels
First, we import the CSV file that contains the labels.
Step5:  Each row in this dataframe represents a power plant at a particular timestamp. 
The "is_powered_on" column indicates whether or not the coal plant was turned on (1) or off (0) at that timestamp.
Step6:  🎛️ Create train/validation splits
Before we can train an ML model, we need to split this data into training and validation datasets. We will do this by creating two new dataframes with a 70/30 training validation split.
Step7:  Merge 🏷️ labels + 🛰️ Sentinel image data
In Earth Engine, an ImageCollection is a stack or sequence of images. An Image is composed of one or more bands and each band has its own name, data type, scale, mask and projection. The Sentinel-2 dataset is represented as an ImageCollection, where each image in the collection is of a specific geographic location at a particular time.
In the cell below, we write a function to extract the Sentinel image taken at the specific latitude/longitude and timestamp for each row of our dataframe.
We will store all of this information as an Earth Engine Feature Collection. In Earth Engine, a Feature is an object with a geometry property storing a Geometry object, and a properties property storing a dictionary of other properties. Groups of related Features can be combined into a FeatureCollection to enable additional operations on the entire set such as filtering, sorting, and rendering. 
We first filter the Sentinel-2 ImageCollection at the start/end dates for a particular row in our dataframe.
Then, using the neighorboodToArray method we create a FeatureCollection that contains the satellite data for each band at the latitude and longitude of interest as well as a 16 pixel padding around that point.
In the image below you can think of the purple box representing the lat/lon where the power plant is located. And around this pixel, we add the padding.
Step8:  To get a better sense of what's going on, let's look at the properties for the first Feature in the train_features list. You can see that it contains a property for the label is_powered_on, and 13 additional properies, one for each spectral band.
Step9:  The data contained in each band property is an array of shape 33x33.
For example, here is the data for band B1 in the first element in our list expressed as a numpy array.
Step10:  💾 Export data
Lastly, we'll export the data to a Cloud Storage bucket. We'll export the data as TFRecords.
Later when we run the training job, we'll parse these TFRecords and feed them to the model.
Step11:  This export will take around 10 minutes. You can monitor the progress with the following command
Step12:  2. 👟 Run a custom training job
Once the export jobs have finished, we're ready to use that data to train a model on Vertex AI Training.
The complete training code can be found in the task.py file.
To run our custom training job on Vertex AI Training, we'll use the pre-built containers provided by Vertex AI to run our training script.
We'll also make use of a GPU. Our model training will only take a couple of minutes, so using a GPU isn't really necessary. But for demonstration purposes (since adding a GPU is simple!) we will make sure we use a container image that is GPU compatible, and then add the accelerator_type and accelerator_count parameters to job.run. TensorFlow will make use of a single GPU out of the box without any extra code changes.
Step13:  The job will take around 10 minutes to run.
Step14:  3. 💻 Deploy a web service to host the trained model
Next, we use
Cloud Run
to deploy a web service that exposes a
REST API to
get predictions from our trained model.
We'll deploy our service to Cloud Run directly from source code so we don't need to build the container image first. Behind the scenes, this command uses Google Cloud buildpacks and Cloud Build to automatically build a container image from our source code in the serving_app directory. To run the web service, we configure Cloud Run to launch
gunicorn
on this container image. 
Since calls to this web service could launch potentially expensive jobs in our project, we configure it to only accept authenticated calls.
🐣 Deploy app
Step15:  Now we need the web service URL to make calls to the REST API we just exposed. We can use gcloud run services describe to get the web service URL.
Since we only accept authorized calls in our web service, we also need to authenticate each call.
gcloud is already authenticated, so we can use gcloud auth print-identity-token to get quick access.
ℹ️ For more information on how to do authenticated calls in Cloud Run, see the
Authentication overview page.
Step16:  Finally, we can test that everything is working.
We included a ping method in our web service just to make sure everything is working as expected.
It simply returns back the arguments we passed to the call, as well as a response saying that the call was successful.
🛎️ This is a convenient way to make sure the web service is reachable, the authentication is working as expected, and the request arguments are passed correctly.
We can use Python's
requests
library.
The web service was built to always accept JSON-encoded requests, and returns JSON-encoded responses.
For a request to be successful, it must
Step18:  4.🔮 Get Predictions
Now that we know our app is up and running, we can use it to make predictions.
Let's start by making a prediction for a particular coal plant. To do this we will need to extract the Sentinel data from Earth Engine and send it in the body of the post requst to the prediction service.
We'll start with a plant located at the coordinates -84.80529, 39.11613, and then extract the satellite data from October 2021.
Step19:  When we call the get_prediction_data function  we need to pass in the start and end dates. 
Sentinel-2 takes pictures every 10 days. At training time, we knew the exact date of the Sentinel-2 image, as this was provided in the labels CSV file. However, for user supplied images for prediction we don't know the specific date the image was taken. To address this, we'll extract data for the entire month of October and then use the mosaic function in Earth Engine which will grab the earliest image in that range, stitch together images at the seams, and discard the rest.
Step20:  The prediction service expects two things the input data for the prediction as well as the Cloud Storage path where the model is stored.
Step21:  4. 🗺️ Visualize predictions
Let's visualize the results of a coal plant in Spain. First, we get predictions for the four towers at this power plant.
Step22:  Next, we can plot these points on a map. Blue means our model predicts that the towers are "off", and red means our model predicts that the towers are "on" and producing carbon pollution.
<ASSISTANT_TASK:>
Python Code:
# Get the sample source code.
!git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git ~/python-docs-samples
%cd ~/python-docs-samples/people-and-planet-ai/geospatial-classification
!pip install -r requirements.txt -c constraints.txt
Explanation: 🏭 Coal Plant ON/OFF: Predictions
Time estimate: 1 hour
Cost estimate: Around $1.00 USD (free if you use \$300 Cloud credits)
Watch the video in YouTube<br> 
This is an interactive notebook that contains all of the code necessary to train an ML model from satellite images for geospatial classification of whether a coal plant is on/off. 
This is a first step introductory example of how these satellite images can be used to detect carbon pollution from power plants.
💚 This is one of many machine learning how-to samples inspired from real climate solutions aired on the People and Planet AI 🎥 series.
🙈 Using this interactive notebook
Click the run icons ▶️ of each section within this notebook. 
This notebook code lets you train and deploy an ML model from end-to-end. When you run a code cell, the code runs in the notebook's runtime, so you're not making any changes to your personal computer.
🛎️ To avoid any errors, wait for each section to finish in their order before clicking the next “run” icon.
This sample must be connected to a Google Cloud project, but nothing else is needed other than your Google Cloud project.
You can use an existing project and the cost will be around $1.00. Alternatively, you can create a new Cloud project with cloud credits for free.
🚴‍♀️ Steps summary
Here's a quick summary of what you’ll go through:
Get the training data (~15 minutes to complete, no cost for using Earth Engine):
  Extract satellite images from Earth Engine, combine it with the data that was labeled and contains lat/long coordinates from Climate TRACE in a CSV, and export to
  Cloud Storage.
Run a custom training job  (~15 minutes to complete, costs ~ $1):
  Using Tensorflow on Vertex AI Training using a pre-built training container.
Deploy a web service to host the trained model (~7 minutes to complete, costs a few cents to build the image, and deployment cost covered by free tier):
  On
  Cloud Run
  and get predictions using the model.
Get Predictions (a few seconds per prediction, costs covered by free tier):
  Use the web service to get predictions for new data.
Visualize predictions (~5 minutes to complete) :
  Visualize the predictions on a map.
(Optional) Delete the project to avoid ongoing costs.
✨ Before you begin, you need to…
Decide on creating a new
   free project
   (recommended) or using an existing one.
   Then copy the project ID and paste it in the google_cloud_project field in the "Entering project details” section below.
💡 If you don't plan to keep the resources that you create via this sample, we recommend creating a new project instead of selecting an existing project.
After you finish these steps, you can delete the project, removing all the resources associated in bulk.
Click here
   to enable the following APIs in your Google Cloud project:
   Earth Engine, Vertex AI, Container Registry, Cloud Build, and Cloud Run.
Make sure that billing is enabled for your Google Cloud project,
   click here
   to learn how to confirm that billing is enabled.
Click here
   to create a Cloud Storage bucket.
   Then copy the bucket’s name and paste it in the cloud_storage_bucket field in the “Entering project details” section below.
🛎️ Make sure it's a regional bucket in a location where
Vertex AI is available.
Have an Earth Engine account (it's FREE) or create a new one.
  To create an account, fill out the registration form here.. Please note this can take from 0-24 hours...but it's worth it! Come back to this sample after you have this.
⛏️ Preparing the project environment
Click the run ▶️ icons in order for the cells to download and install the necessary code, libraries, and resources for this solution.
💡 You can optionally view the entire
code in GitHub.
↘️ Get the code
End of explanation
#@title My Google Cloud resources
project = '' #@param {type:"string"}
cloud_storage_bucket = '' #@param {type:"string"}
region = '' #@param {type:"string"}
# Validate the inputs.
if not project:
  raise ValueError(f"Please provide a value for 'project'")
if not cloud_storage_bucket:
  raise ValueError(f"Please provide a value for 'cloud_storage_bucket'")
if not region:
  raise ValueError(f"Please provide a value for 'region'")
# Authenticate
from google.colab import auth
auth.authenticate_user()
print('Authenticated')
!gcloud config set project {project}
%cd ~/python-docs-samples/people-and-planet-ai/geospatial-classification
Explanation: 🛎️ [DON’T PANIC] It’s safe to ignore the warnings.
When we pip install the requirements, there might be some warnings about conflicting dependency versions.
For the scope of this sample, that’s ok.
⚠️ Restart the runtime: Running the previous cell just updated some libraries and requires to restart the runtime to load those libraries correctly.
In the top-left menu, click "Runtime" > "Restart runtime".
✏️ Enter your Cloud project's details. Ensure you provide a regional bucket!
End of explanation
import ee
import google.auth
credentials, _ = google.auth.default()
ee.Initialize(credentials, project=project)
Explanation: 🗺️ Authenticate to Earth Engine
In order to use the Earth Engine API, you'll need to have an Earth Engine account.
To create an account, fill out the registration form here.
End of explanation
# Define constants
LABEL = 'is_powered_on'
IMAGE_COLLECTION = "COPERNICUS/S2"
BANDS = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A', 'B9', 'B10', 'B11', 'B12']
SCALE = 10
PATCH_SIZE = 16
Explanation: 🚏 Overview
This notebook leverages geospatial data from Google Earth Engine, and labeled data provided by the organization Climate TRACE. By combining these two data sources, you'll build and train a model that predicts whether or not a power plant is turned on and producing emissions.
🛰️ Data (inputs)
The data in this example consists of images from a satellite called Sentinel-2, a wide-swath, high-resolution, multi-spectral imaging mission for land monitoring studies.
When working with satellite data, each input image has the dimensions [width, height, bands]. Bands are measurements from specific satellite instruments for different ranges of the electromagnetic spectrum. For example, Sentinel-2 contains 🌈 13 spectral bands. If you're familiar with image classification problems, you can think of the bands as similar to an image's RGB (red, green, blue) channels. However, when working with satellite data we generally have more than just 3 channels.
🏷️ Labels (outputs)
For each patch of pixels (an image of a power plant) that we give to the model, it performs binary classification, which indicates whether the power plant is on or off.
In this example, the output is a single number between 0 (Off) and 1 (On), representing the probability of that power plant being ON.
Model (function)
TL;DR
The model will receive a patch of pixels, in the center is the power plant tower. We take 16 pixels as padding creating a 33x33 patch. The model returns a classification of ON/OFF
In this example, we have a CSV file of labels. Each row in this file represents a power plant at a specific lat/lon and timestamp. At training time we'll prepare a dataset where each input image is a single pixel that we have a label for. We will then add padding around that image. These padded pixels will not get predictions, but will help our model to make better predictions for the center point that we have a label for.
For example, with a padding of 16, each 1 pixel input point would become a 33x33 image after the padding is added.
The model in this sample is trained for image patches where a power plant is located in the center, and the dimensions must be 33x33 pixels where each pixel has a constant number of bands.
1. 🛰️ Get the training data
The training data in this sample comes from two places: 
The satellite images will be extracted from Earth Engine.
The labels are provided in a CSV file that indicates whether a coal plant is turned on or off at a particular timestamp. 
For each row in the CSV file, we need to extract the corresponding Sentinel image taken at that specific latitude/longitude and timestamp. We'll export this image data, along with the corresponding label (on/off), to Cloud Storage.
End of explanation
import pandas as pd
import numpy as np
labels_dataframe = pd.read_csv('labeled_geospatial_data.csv')
Explanation: 🏷️ Import labels
First, we import the CSV file that contains the labels.
End of explanation
labels_dataframe.head()
Explanation: Each row in this dataframe represents a power plant at a particular timestamp. 
The "is_powered_on" column indicates whether or not the coal plant was turned on (1) or off (0) at that timestamp.
End of explanation
TRAIN_VALIDATION_SPLIT = 0.7
train_dataframe = labels_dataframe.sample(frac=TRAIN_VALIDATION_SPLIT,random_state=200) #random state is a seed value
validation_dataframe = labels_dataframe.drop(train_dataframe.index).sample(frac=1.0)
Explanation: 🎛️ Create train/validation splits
Before we can train an ML model, we need to split this data into training and validation datasets. We will do this by creating two new dataframes with a 70/30 training validation split.
End of explanation
from datetime import datetime, timedelta
def labeled_feature(row):
    start = datetime.fromisoformat(row.timestamp)
    end = start + timedelta(days=1)
    image = (
        ee.ImageCollection(IMAGE_COLLECTION)
        .filterDate(start.strftime("%Y-%m-%d"), end.strftime("%Y-%m-%d"))
        .select(BANDS)
        .mosaic()
    )
    point = ee.Feature(
        ee.Geometry.Point([row.lon, row.lat]),
        {LABEL: row.is_powered_on},
    )
    return (
        image.neighborhoodToArray(ee.Kernel.square(PATCH_SIZE))
        .sampleRegions(ee.FeatureCollection([point]), scale=SCALE)
        .first()
    )
train_features = [labeled_feature(row) for row in train_dataframe.itertuples()]
validation_features = [labeled_feature(row) for row in validation_dataframe.itertuples()]
Explanation: Merge 🏷️ labels + 🛰️ Sentinel image data
In Earth Engine, an ImageCollection is a stack or sequence of images. An Image is composed of one or more bands and each band has its own name, data type, scale, mask and projection. The Sentinel-2 dataset is represented as an ImageCollection, where each image in the collection is of a specific geographic location at a particular time.
In the cell below, we write a function to extract the Sentinel image taken at the specific latitude/longitude and timestamp for each row of our dataframe.
We will store all of this information as an Earth Engine Feature Collection. In Earth Engine, a Feature is an object with a geometry property storing a Geometry object, and a properties property storing a dictionary of other properties. Groups of related Features can be combined into a FeatureCollection to enable additional operations on the entire set such as filtering, sorting, and rendering. 
We first filter the Sentinel-2 ImageCollection at the start/end dates for a particular row in our dataframe.
Then, using the neighorboodToArray method we create a FeatureCollection that contains the satellite data for each band at the latitude and longitude of interest as well as a 16 pixel padding around that point.
In the image below you can think of the purple box representing the lat/lon where the power plant is located. And around this pixel, we add the padding.
End of explanation
ee.FeatureCollection(train_features[0]).propertyNames().getInfo()
Explanation: To get a better sense of what's going on, let's look at the properties for the first Feature in the train_features list. You can see that it contains a property for the label is_powered_on, and 13 additional properies, one for each spectral band.
End of explanation
example_feature = np.array(train_features[0].get('B1').getInfo())
print(example_feature)
print('shape: ' + str(example_feature.shape))
Explanation: The data contained in each band property is an array of shape 33x33.
For example, here is the data for band B1 in the first element in our list expressed as a numpy array.
End of explanation
# Export data
training_task = ee.batch.Export.table.toCloudStorage(
    collection=ee.FeatureCollection(train_features),
    description="Training image export",
    bucket=cloud_storage_bucket,
    fileNamePrefix="geospatial_training",
    selectors=BANDS + [LABEL],
    fileFormat="TFRecord",
)
training_task.start()
validation_task = ee.batch.Export.table.toCloudStorage(
    collection=ee.FeatureCollection(validation_features),
    description="Validation image export",
    bucket=cloud_storage_bucket,
    fileNamePrefix="geospatial_validation",
    selectors= BANDS + [LABEL],
    fileFormat='TFRecord')
validation_task.start()
Explanation: 💾 Export data
Lastly, we'll export the data to a Cloud Storage bucket. We'll export the data as TFRecords.
Later when we run the training job, we'll parse these TFRecords and feed them to the model.
End of explanation
from pprint import pprint
pprint(ee.batch.Task.list())
Explanation: This export will take around 10 minutes. You can monitor the progress with the following command:
End of explanation
from google.cloud import aiplatform
aiplatform.init(project=project, staging_bucket=cloud_storage_bucket)
job = aiplatform.CustomTrainingJob(
    display_name="geospatial_model_training",
    script_path="task.py",
    container_uri="us-docker.pkg.dev/vertex-ai/training/tf-gpu.2-7:latest")
Explanation: 2. 👟 Run a custom training job
Once the export jobs have finished, we're ready to use that data to train a model on Vertex AI Training.
The complete training code can be found in the task.py file.
To run our custom training job on Vertex AI Training, we'll use the pre-built containers provided by Vertex AI to run our training script.
We'll also make use of a GPU. Our model training will only take a couple of minutes, so using a GPU isn't really necessary. But for demonstration purposes (since adding a GPU is simple!) we will make sure we use a container image that is GPU compatible, and then add the accelerator_type and accelerator_count parameters to job.run. TensorFlow will make use of a single GPU out of the box without any extra code changes.
End of explanation
model = job.run(accelerator_type='NVIDIA_TESLA_K80', accelerator_count=1, args=[f'--bucket={cloud_storage_bucket}'])
Explanation: The job will take around 10 minutes to run.
End of explanation
# Deploy the web service to Cloud Run.
# https://cloud.google.com/sdk/gcloud/reference/run/deploy
!gcloud run deploy "geospatial-service" \
  --source=serving_app \
  --command="gunicorn" \
  --args="--threads=8,--timeout=0,main:app" \
  --region="{region}" \
  --memory="1G" \
  --no-allow-unauthenticated \
Explanation: 3. 💻 Deploy a web service to host the trained model
Next, we use
Cloud Run
to deploy a web service that exposes a
REST API to
get predictions from our trained model.
We'll deploy our service to Cloud Run directly from source code so we don't need to build the container image first. Behind the scenes, this command uses Google Cloud buildpacks and Cloud Build to automatically build a container image from our source code in the serving_app directory. To run the web service, we configure Cloud Run to launch
gunicorn
on this container image. 
Since calls to this web service could launch potentially expensive jobs in our project, we configure it to only accept authenticated calls.
🐣 Deploy app
End of explanation
import subprocess
# Get the web service URL.
#   https://cloud.google.com/sdk/gcloud/reference/run/services/describe
service_url = subprocess.run(
    [ 'gcloud', 'run', 'services', 'describe', 'geospatial-service',
        f'--region={region}',
        f'--format=get(status.url)',
    ],
    capture_output=True,
).stdout.decode('utf-8').strip()
print(f"service_url: {service_url}")
# Get an identity token for authorized calls to our web service.
#   https://cloud.google.com/sdk/gcloud/reference/auth/print-identity-token
identity_token = subprocess.run(
    ['gcloud', 'auth', 'print-identity-token'],
    capture_output=True,
).stdout.decode('utf-8').strip()
print(f"identity_token: {identity_token}")
Explanation: Now we need the web service URL to make calls to the REST API we just exposed. We can use gcloud run services describe to get the web service URL.
Since we only accept authorized calls in our web service, we also need to authenticate each call.
gcloud is already authenticated, so we can use gcloud auth print-identity-token to get quick access.
ℹ️ For more information on how to do authenticated calls in Cloud Run, see the
Authentication overview page.
End of explanation
import requests
requests.post(
    url=f'{service_url}/ping',
    headers={'Authorization': f'Bearer {identity_token}'},
    json={'x': 42, 'message': 'Hello world!'},
).json()
Explanation: Finally, we can test that everything is working.
We included a ping method in our web service just to make sure everything is working as expected.
It simply returns back the arguments we passed to the call, as well as a response saying that the call was successful.
🛎️ This is a convenient way to make sure the web service is reachable, the authentication is working as expected, and the request arguments are passed correctly.
We can use Python's
requests
library.
The web service was built to always accept JSON-encoded requests, and returns JSON-encoded responses.
For a request to be successful, it must:
Be an HTTP POST request
Contain the following headers:
Authorization: Bearer IDENTITY_TOKEN
Content-Type: application/json
The data must be valid JSON, if no arguments are needed we can pass {} as an empty object.
For ease of use, requests.post has a
json parameter
that automatically attaches the header Content-Type: application/json and encodes our data into a JSON string.
End of explanation
# Extract image data
import json
def get_prediction_data(lon, lat, start, end):
    Extracts Sentinel image as json at specific lat/lon and timestamp.
    location = ee.Feature(ee.Geometry.Point([lon, lat]))
    image = (
        ee.ImageCollection(IMAGE_COLLECTION)
        .filterDate(start, end)
        .select(BANDS)
        .mosaic()
    )
    feature = image.neighborhoodToArray(ee.Kernel.square(PATCH_SIZE)).sampleRegions(
        collection=ee.FeatureCollection([location]), scale=SCALE
    )
    return feature.getInfo()["features"][0]["properties"]
Explanation: 4.🔮 Get Predictions
Now that we know our app is up and running, we can use it to make predictions.
Let's start by making a prediction for a particular coal plant. To do this we will need to extract the Sentinel data from Earth Engine and send it in the body of the post requst to the prediction service.
We'll start with a plant located at the coordinates -84.80529, 39.11613, and then extract the satellite data from October 2021.
End of explanation
prediction_data = get_prediction_data(-84.80529, 39.11613, '2021-10-01', '2021-10-31')
Explanation: When we call the get_prediction_data function  we need to pass in the start and end dates. 
Sentinel-2 takes pictures every 10 days. At training time, we knew the exact date of the Sentinel-2 image, as this was provided in the labels CSV file. However, for user supplied images for prediction we don't know the specific date the image was taken. To address this, we'll extract data for the entire month of October and then use the mosaic function in Earth Engine which will grab the earliest image in that range, stitch together images at the seams, and discard the rest.
End of explanation
requests.post(
    url=f'{service_url}/predict',
    headers={'Authorization': f'Bearer {identity_token}'},
    json={'data': prediction_data, 'bucket': cloud_storage_bucket},
).json()['predictions']
Explanation: The prediction service expects two things the input data for the prediction as well as the Cloud Storage path where the model is stored.
End of explanation
def get_prediction(lon, lat, start, end):
    prediction_data = get_prediction_data(lon, lat, start, end)
    result = requests.post(
      url=f'{service_url}/predict',
      headers={'Authorization': f'Bearer {identity_token}'},
      json={'data': prediction_data, 'bucket': cloud_storage_bucket},).json()
    return result['predictions']['predictions'][0][0][0][0]
lons = [-7.86444, -7.86376, -7.85755, -7.85587]
lats = [43.43717, 43.43827, 43.44075, 43.44114]
plant_predictions = [get_prediction(lon , lat, '2021-10-01', '2021-10-31') for lon, lat in zip(lons, lats)]
Explanation: 4. 🗺️ Visualize predictions
Let's visualize the results of a coal plant in Spain. First, we get predictions for the four towers at this power plant.
End of explanation
import folium
import folium.plugins as folium_plugins
import branca.colormap as cm
colormap = cm.LinearColormap(colors=['lightblue', 'red'], index=[0,1], vmin=0, vmax=1)
map = folium.Map(
    location=[43.44, -7.86],
    zoom_start=16,
    tiles='https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
    attr = 'ESRI'
)
for loc, p in zip(zip(lats, lons), plant_predictions):
    folium.Circle(
        location=loc,
        radius=20,
        fill=True,
        color=colormap(p),
    ).add_to(map)
map.add_child(colormap)
display(map)
Explanation: Next, we can plot these points on a map. Blue means our model predicts that the towers are "off", and red means our model predicts that the towers are "on" and producing carbon pollution.
End of explanation
<END_TASK>