diff --git a/samples/javascript/guides/landsat01.js b/samples/javascript/guides/landsat01.js index a81dacacb..f66f17ac3 100644 --- a/samples/javascript/guides/landsat01.js +++ b/samples/javascript/guides/landsat01.js @@ -44,6 +44,7 @@ var surfaceReflectanceL4 = ee.ImageCollection('LANDSAT/LT04/C02/T1_L2'); var surfaceReflectanceL5 = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'); var surfaceReflectanceL7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'); var surfaceReflectanceL8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); +var surfaceReflectanceL9 = ee.ImageCollection('LANDSAT/LC09/C02/T1_L2'); // [END earthengine__landsat01__sr_collections] diff --git a/tutorials/beginners-cookbook/index.md b/tutorials/beginners-cookbook/index.md index a3cae8670..a65a9c968 100644 --- a/tutorials/beginners-cookbook/index.md +++ b/tutorials/beginners-cookbook/index.md @@ -874,7 +874,7 @@ var geometry = ee.Geometry.Rectangle([55.1, 25, 55.4, 25.4]); // Add layer to map. Map.addLayer(geometry); // Load Landsat image collection. -var allImages = ee.ImageCollection('LANDSAT/LT05/C01/T1_TOA') +var allImages = ee.ImageCollection('LANDSAT/LT05/C02/T1_TOA') // Filter row and path such that they cover Dubai. .filter(ee.Filter.eq('WRS_PATH', 160)) .filter(ee.Filter.eq('WRS_ROW', 43)) diff --git a/tutorials/histogram-matching/index.ipynb b/tutorials/histogram-matching/index.ipynb index d66b3184f..85efef14e 100644 --- a/tutorials/histogram-matching/index.ipynb +++ b/tutorials/histogram-matching/index.ipynb @@ -80,6 +80,8 @@ }, "source": [ "import ee\n", + "import geemap\n", + "\n", "ee.Authenticate()\n", "ee.Initialize(project='my-project')" ], @@ -161,36 +163,36 @@ "id": "l-ofElnberw1" }, "source": [ - "def histogram_match(source_img, target_img, geometry):\r\n", - " \"\"\"Performs histogram matching for 3-band RGB images by forcing the histogram CDF of source_img to match target_img.\r\n", - "\r\n", - " Args:\r\n", - " source_img: A 3-band ee.Image to be color matched. Must have bands named 'R', 'G', and 'B'.\r\n", - " target_img: A 3-band ee.Image for color reference. Must have bands named 'R', 'G', and 'B'.\r\n", - " geometry: An ee.Geometry that defines the region to generate RGB histograms for.\r\n", - " It should intersect both source_img and target_img inputs.\r\n", - "\r\n", - " Returns:\r\n", - " A copy of src_img color-matched to target_img.\r\n", - " \"\"\"\r\n", - "\r\n", - " args = {\r\n", - " 'reducer': ee.Reducer.autoHistogram(**{'maxBuckets': 256, 'cumulative': True}),\r\n", - " 'geometry': geometry,\r\n", - " 'scale': 1, # Need to specify a scale, but it doesn't matter what it is because bestEffort is true.\r\n", - " 'maxPixels': 65536 * 4 - 1,\r\n", - " 'bestEffort': True\r\n", - " }\r\n", - "\r\n", - " # Only use pixels in target that have a value in source (inside the footprint and unmasked).\r\n", - " source = source_img.reduceRegion(**args)\r\n", - " target = target_img.updateMask(source_img.mask()).reduceRegion(**args)\r\n", - "\r\n", - " return ee.Image.cat(\r\n", - " source_img.select(['R']).interpolate(**lookup(source.getArray('R'), target.getArray('R'))),\r\n", - " source_img.select(['G']).interpolate(**lookup(source.getArray('G'), target.getArray('G'))),\r\n", - " source_img.select(['B']).interpolate(**lookup(source.getArray('B'), target.getArray('B')))\r\n", - " ).copyProperties(source_img, ['system:time_start'])" + "def histogram_match(source_img, target_img, geometry):\n", + " \"\"\"Performs histogram matching for 3-band RGB images by forcing the histogram CDF of source_img to match target_img.\n", + "\n", + " Args:\n", + " source_img: A 3-band ee.Image to be color matched. Must have bands named 'R', 'G', and 'B'.\n", + " target_img: A 3-band ee.Image for color reference. Must have bands named 'R', 'G', and 'B'.\n", + " geometry: An ee.Geometry that defines the region to generate RGB histograms for.\n", + " It should intersect both source_img and target_img inputs.\n", + "\n", + " Returns:\n", + " A copy of src_img color-matched to target_img.\n", + " \"\"\"\n", + "\n", + " args = {\n", + " 'reducer': ee.Reducer.autoHistogram(maxBuckets=256, cumulative=True),\n", + " 'geometry': geometry,\n", + " 'scale': 1, # Need to specify a scale, but it doesn't matter what it is because bestEffort is true.\n", + " 'maxPixels': 65536 * 4 - 1,\n", + " 'bestEffort': True\n", + " }\n", + "\n", + " # Only use pixels in target that have a value in source (inside the footprint and unmasked).\n", + " source = source_img.reduceRegion(**args)\n", + " target = target_img.updateMask(source_img.mask()).reduceRegion(**args)\n", + "\n", + " return ee.Image(ee.Image.cat(\n", + " source_img.select(['R']).interpolate(**lookup(source.getArray('R'), target.getArray('R'))),\n", + " source_img.select(['G']).interpolate(**lookup(source.getArray('G'), target.getArray('G'))),\n", + " source_img.select(['B']).interpolate(**lookup(source.getArray('B'), target.getArray('B')))\n", + " ).copyProperties(source_img, ['system:time_start']))" ], "execution_count": null, "outputs": [] @@ -214,33 +216,33 @@ "id": "_EmxcWn_gOE_" }, "source": [ - "def find_closest(target_image, image_col, days):\r\n", - " \"\"\"Filter images in a collection by date proximity and spatial intersection to a target image.\r\n", - "\r\n", - " Args:\r\n", - " target_image: An ee.Image whose observation date is used to find near-date images in\r\n", - " the provided image_col image collection. It must have a 'system:time_start' property.\r\n", - " image_col: An ee.ImageCollection to filter by date proximity and spatial intersection\r\n", - " to the target_image. Each image in the collection must have a 'system:time_start'\r\n", - " property.\r\n", - " days: A number that defines the maximum number of days difference allowed between\r\n", - " the target_image and images in the image_col.\r\n", - "\r\n", - " Returns:\r\n", - " An ee.ImageCollection that has been filtered to include those images that are within the\r\n", - " given date proximity to target_image and intersect it spatially.\r\n", - " \"\"\"\r\n", - "\r\n", - " # Compute the timespan for N days (in milliseconds).\r\n", - " range = ee.Number(days).multiply(1000 * 60 * 60 * 24)\r\n", - "\r\n", - " filter = ee.Filter.And(\r\n", - " ee.Filter.maxDifference(range, 'system:time_start', None, 'system:time_start'),\r\n", - " ee.Filter.intersects('.geo', None, '.geo'))\r\n", - "\r\n", - " closest = (ee.Join.saveAll('matches', 'measure')\r\n", - " .apply(ee.ImageCollection([target_image]), image_col, filter))\r\n", - "\r\n", + "def find_closest(target_image, image_col, days):\n", + " \"\"\"Filter images in a collection by date proximity and spatial intersection to a target image.\n", + "\n", + " Args:\n", + " target_image: An ee.Image whose observation date is used to find near-date images in\n", + " the provided image_col image collection. It must have a 'system:time_start' property.\n", + " image_col: An ee.ImageCollection to filter by date proximity and spatial intersection\n", + " to the target_image. Each image in the collection must have a 'system:time_start'\n", + " property.\n", + " days: A number that defines the maximum number of days difference allowed between\n", + " the target_image and images in the image_col.\n", + "\n", + " Returns:\n", + " An ee.ImageCollection that has been filtered to include those images that are within the\n", + " given date proximity to target_image and intersect it spatially.\n", + " \"\"\"\n", + "\n", + " # Compute the timespan for N days (in milliseconds).\n", + " range = ee.Number(days).multiply(1000 * 60 * 60 * 24)\n", + "\n", + " filter = ee.Filter.And(\n", + " ee.Filter.maxDifference(range, 'system:time_start', None, 'system:time_start'),\n", + " ee.Filter.intersects('.geo', None, '.geo'))\n", + "\n", + " closest = (ee.Join.saveAll('matches', 'measure')\n", + " .apply(ee.ImageCollection([target_image]), image_col, filter))\n", + "\n", " return ee.ImageCollection(ee.List(closest.first().get('matches')))" ], "execution_count": null, @@ -274,13 +276,9 @@ "id": "OPBddAaYNMIz" }, "source": [ - "geometry = ee.Geometry.Polygon(\r\n", - " [[[-155.97117211519446, 20.09006980142336],\r\n", - " [-155.97117211519446, 19.7821681268256],\r\n", - " [-155.73256280122962, 19.7821681268256],\r\n", - " [-155.73256280122962, 20.09006980142336]]], None, False)\r\n", - "\r\n", - "skysat = (ee.Image('SKYSAT/GEN-A/PUBLIC/ORTHO/RGB/s01_20161020T214047Z')\r\n", + "geometry = ee.Geometry.BBox(-155.971, 19.782, -155.733, 20.09)\n", + "\n", + "skysat = (ee.Image('SKYSAT/GEN-A/PUBLIC/ORTHO/RGB/s01_20161020T214047Z')\n", " .clip(geometry))" ], "execution_count": null, @@ -301,20 +299,24 @@ "id": "5sZYiLMAo6M1" }, "source": [ - "def prep_landsat(image):\r\n", - " \"\"\"Apply cloud/shadow mask and select/rename Landsat 8 bands.\"\"\"\r\n", - "\r\n", - " qa = image.select('pixel_qa')\r\n", - " return (image.updateMask(\r\n", - " qa.bitwiseAnd(1 \u003c\u003c 3).eq(0).And(qa.bitwiseAnd(1 \u003c\u003c 5).eq(0)))\r\n", - " .divide(10000)\r\n", - " .select(['B4', 'B3', 'B2'], ['R', 'G', 'B'])\r\n", - " .copyProperties(image, ['system:time_start']))\r\n", - "\r\n", - "# Get the landsat collection, cloud masked and scaled to surface reflectance.\r\n", - "landsat_col = (ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')\r\n", - "\t.filterBounds(geometry)\r\n", - "\t.map(prep_landsat))" + "def prep_landsat(image):\n", + " \"\"\"Scale, apply cloud/shadow mask, and select/rename Landsat 8 bands.\"\"\"\n", + " qa_mask = image.select('QA_PIXEL').bitwiseAnd(int('11111', 2)).eq(0)\n", + "\n", + " def get_factor_img(factor_names):\n", + " factor_list = image.toDictionary().select(factor_names).values()\n", + " return ee.Image.constant(factor_list)\n", + "\n", + " scale_img = get_factor_img(['REFLECTANCE_MULT_BAND_.'])\n", + " offset_img = get_factor_img(['REFLECTANCE_ADD_BAND_.'])\n", + " scaled = image.select('SR_B.').multiply(scale_img).add(offset_img)\n", + "\n", + " return image.addBands(scaled, None, True).select(\n", + " ['SR_B4', 'SR_B3', 'SR_B2'], ['R', 'G', 'B']).updateMask(qa_mask)\n", + "\n", + "# Get the landsat collection, cloud masked and scaled to surface reflectance.\n", + "landsat_col = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2').filterBounds(\n", + " geometry).map(prep_landsat)" ], "execution_count": null, "outputs": [] @@ -334,7 +336,7 @@ "id": "vxxWeyPVo16v" }, "source": [ - "reference = find_closest(skysat, landsat_col, 32).sort('CLOUD_COVER').mosaic()\r\n", + "reference = find_closest(skysat, landsat_col, 32).sort('CLOUD_COVER').mosaic()\n", "result = histogram_match(skysat, reference, geometry)" ], "execution_count": null, @@ -346,41 +348,9 @@ "id": "s2YImlVmcEA3" }, "source": [ - "## Results\r\n", - "\r\n", - "Setup folium for interactive map viewing." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "2K0O6bv0cGf-" - }, - "source": [ - "import folium\r\n", - "\r\n", - "def add_ee_layer(self, ee_image_object, vis_params, name):\r\n", - " map_id_dict = ee.Image(ee_image_object).getMapId(vis_params)\r\n", - " folium.raster_layers.TileLayer(\r\n", - " tiles=map_id_dict['tile_fetcher'].url_format,\r\n", - " attr='Map Data \u0026copy; \u003ca href=\"https://earthengine.google.com/\"\u003eGoogle Earth Engine\u003c/a\u003e',\r\n", - " name=name,\r\n", - " overlay=True,\r\n", - " control=True\r\n", - " ).add_to(self)\r\n", - "\r\n", - "folium.Map.add_ee_layer = add_ee_layer" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HQgGj9HJrPKa" - }, - "source": [ - "Define a folium map object, add layers, and display it. Until you zoom in really far, it's nearly impossible to tell where the Landsat image ends and the SkySat image begins." + "## Results\n", + "\n", + "Define a `geemap.Map` object, add layers, and display it. Until you zoom in really far, it's nearly impossible to tell where the Landsat image ends and the SkySat image begins." ] }, { @@ -389,16 +359,16 @@ "id": "QJDqpNtDpUKO" }, "source": [ - "lon, lat, zoom = -155.79584, 19.99866, 13\r\n", - "map_matched = folium.Map(location=[lat, lon], zoom_start=zoom)\r\n", - "\r\n", - "vis_params_refl = {'min': 0, 'max': 0.25}\r\n", - "vis_params_dn = {'min': 0, 'max': 255}\r\n", - "\r\n", - "map_matched.add_ee_layer(reference, vis_params_refl, 'Landsat-8 reference')\r\n", - "map_matched.add_ee_layer(skysat, vis_params_dn, 'SkySat source')\r\n", - "map_matched.add_ee_layer(result, vis_params_refl, 'SkySat matched')\r\n", - "display(map_matched.add_child(folium.LayerControl()))" + "lon, lat, zoom = -155.79584, 19.99866, 13\n", + "m = geemap.Map(center=[lat, lon], zoom=zoom)\n", + "\n", + "vis_params_refl = {'min': 0, 'max': 0.25}\n", + "vis_params_dn = {'min': 0, 'max': 255}\n", + "\n", + "m.add_layer(reference, vis_params_refl, 'Landsat-8 reference')\n", + "m.add_layer(skysat, vis_params_dn, 'SkySat source')\n", + "m.add_layer(result, vis_params_refl, 'SkySat matched')\n", + "m" ], "execution_count": null, "outputs": [] diff --git a/tutorials/time-series-visualization-with-altair/index.ipynb b/tutorials/time-series-visualization-with-altair/index.ipynb index 5114159ce..858c86916 100644 --- a/tutorials/time-series-visualization-with-altair/index.ipynb +++ b/tutorials/time-series-visualization-with-altair/index.ipynb @@ -1059,7 +1059,7 @@ "ndvi_df_sub = ndvi_df[(ndvi_df['DOY'] \u003e= ndvi_doy_range[0])\n", " \u0026 (ndvi_df['DOY'] \u003c= ndvi_doy_range[1])]\n", "\n", - "ndvi_df_sub = ndvi_df_sub.groupby('Year').agg('min')" + "ndvi_df_sub = ndvi_df_sub.groupby('Year').min(numeric_only=True)" ], "execution_count": null, "outputs": [] @@ -1094,7 +1094,7 @@ "pdsi_df_sub = pdsi_df[(pdsi_df['DOY'] \u003e= pdsi_doy_range[0])\n", " \u0026 (pdsi_df['DOY'] \u003c= pdsi_doy_range[1])]\n", "\n", - "pdsi_df_sub = pdsi_df_sub.groupby('Year').agg('mean')" + "pdsi_df_sub = pdsi_df_sub.groupby('Year').mean(numeric_only=True)" ], "execution_count": null, "outputs": [] @@ -1360,23 +1360,20 @@ "# Define a function to get and rename bands of interest from OLI.\n", "def rename_oli(img):\n", " return (img.select(\n", - " ee.List(['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'pixel_qa']),\n", - " ee.List(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2', 'pixel_qa'])))\n", + " ee.List(['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']),\n", + " ee.List(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'])))\n", "\n", "# Define a function to get and rename bands of interest from ETM+.\n", "def rename_etm(img):\n", " return (img.select(\n", - " ee.List(['B1', 'B2', 'B3', 'B4', 'B5', 'B7', 'pixel_qa']),\n", - " ee.List(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2', 'pixel_qa'])))\n", - "\n", - "# Define a function to mask out clouds and cloud shadows.\n", - "def cfmask(img):\n", - " cloud_shadow_bi_mask = 1 \u003c\u003c 3\n", - " cloud_bit_mask = 1 \u003c\u003c 5\n", - " qa = img.select('pixel_qa')\n", - " mask = qa.bitwiseAnd(cloud_shadow_bi_mask).eq(0).And(\n", - " qa.bitwiseAnd(cloud_bit_mask).eq(0))\n", - " return img.updateMask(mask)\n", + " ee.List(['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']),\n", + " ee.List(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'])))\n", + "\n", + "# Define a function to scale images and mask out clouds and cloud shadows.\n", + "def scale_and_mask(img):\n", + " qa_mask = img.select('QA_PIXEL').bitwiseAnd(int('11111', 2)).eq(0)\n", + " scaled = img.select('SR_B.').multiply(0.0000275).add(-0.2)\n", + " return scaled.updateMask(qa_mask)\n", "\n", "# Define a function to add year as an image property.\n", "def set_year(img):\n", @@ -1390,8 +1387,8 @@ "# Define a function to prepare OLI images.\n", "def prep_oli(img):\n", " orig = img\n", + " img = scale_and_mask(img)\n", " img = rename_oli(img)\n", - " img = cfmask(img)\n", " img = calc_nbr(img)\n", " img = img.copyProperties(orig, orig.propertyNames())\n", " return set_year(img)\n", @@ -1399,16 +1396,16 @@ "# Define a function to prepare TM/ETM+ images.\n", "def prep_etm(img):\n", " orig = img\n", + " img = scale_and_mask(img)\n", " img = rename_etm(img)\n", - " img = cfmask(img)\n", " img = calc_nbr(img)\n", " img = img.copyProperties(orig, orig.propertyNames())\n", " return set_year(img)\n", "\n", "# Import image collections for each Landsat sensor (surface reflectance).\n", - "tm_col = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR')\n", - "etm_col = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR')\n", - "oli_col = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')\n", + "tm_col = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')\n", + "etm_col = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')\n", + "oli_col = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", "\n", "# Filter collections and prepare them for merging.\n", "oli_col = oli_col.filterBounds(point).filter(\n",