Composites#

Plotting individual bands is good but we usually want to make some composite images to visualize information from multiple bands at once. For that, we have to create composites. We provide the xlandsat.composite function to make this process easier.

As an example, let’s load two example scenes from the Brumadinho tailings dam disaster:

import xlandsat as xls
import matplotlib.pyplot as plt

path_before = xls.datasets.fetch_brumadinho_before()
path_after = xls.datasets.fetch_brumadinho_after()

before = xls.load_scene(path_before)
after = xls.load_scene(path_after)

Creating composites#

Let’s make both RGB (true color) and CIR (color infrared) composites for both of our scenes:

# Make the composite and add it as a variable to the scene
before = before.assign(rgb=xls.composite(before, rescale_to=[0.03, 0.2]))
cir_bands = ("nir", "red", "green")
before = before.assign(
    cir=xls.composite(before, bands=cir_bands, rescale_to=[0, 0.4]),
)
before
<xarray.Dataset>
Dimensions:   (easting: 400, northing: 300, channel: 4)
Coordinates:
  * easting   (easting) float64 5.835e+05 5.835e+05 ... 5.954e+05 5.955e+05
  * northing  (northing) float64 -2.232e+06 -2.232e+06 ... -2.223e+06 -2.223e+06
  * channel   (channel) <U5 'red' 'green' 'blue' 'alpha'
Data variables:
    blue      (northing, easting) float16 0.07288 0.07373 ... 0.06506 0.06653
    green     (northing, easting) float16 0.09851 0.099 ... 0.0835 0.08716
    red       (northing, easting) float16 0.1035 0.1041 ... 0.07959 0.08423
    nir       (northing, easting) float16 0.2803 0.2749 0.3203 ... 0.2118 0.2267
    swir1     (northing, easting) float16 0.2467 0.2474 0.2147 ... 0.172 0.1769
    swir2     (northing, easting) float16 0.1571 0.1571 0.1281 ... 0.1171 0.1206
    rgb       (northing, easting, channel) uint8 110 102 64 255 ... 81 85 54 255
    cir       (northing, easting, channel) uint8 178 66 62 255 ... 144 53 55 255
Attributes: (12/19)
    Conventions:                CF-1.8
    title:                      Landsat 8 scene from 2019-01-14 (path/row=218...
    digital_object_identifier:  https://doi.org/10.5066/P9OGBGM6
    origin:                     Image courtesy of the U.S. Geological Survey
    landsat_product_id:         LC08_L2SP_218074_20190114_20200829_02_T1
    processing_level:           L2SP
    ...                         ...
    ellipsoid:                  WGS84
    date_acquired:              2019-01-14
    scene_center_time:          12:57:13.1804960Z
    wrs_path:                   218
    wrs_row:                    74
    mtl_file:                   GROUP = LANDSAT_METADATA_FILE\n  GROUP = PROD...

The composites have a similar layout as the bands but with an extra "channel" dimension corresponding to red, green, blue, and alpha/transparency. The values are scaled to the [0, 255] range and the composite is an array of unsigned 8-bit integers.

Transparency

If any of the bands used for the composite have NaNs, those pixels will have their transparency set to the maximum value of 255. If there are no NaNs in any band, then the composite will only have 3 channels (red, green, blue).

Now do the same for the after scene:

after = after.assign(rgb=xls.composite(after, rescale_to=[0.03, 0.2]))
after = after.assign(
    cir=xls.composite(after, bands=cir_bands, rescale_to=[0, 0.4]),
)
after
<xarray.Dataset>
Dimensions:   (easting: 400, northing: 300, channel: 4)
Coordinates:
  * easting   (easting) float64 5.844e+05 5.844e+05 ... 5.963e+05 5.964e+05
  * northing  (northing) float64 -2.232e+06 -2.232e+06 ... -2.223e+06 -2.223e+06
  * channel   (channel) <U5 'red' 'green' 'blue' 'alpha'
Data variables:
    blue      (northing, easting) float16 0.0686 0.07043 ... 0.05823 0.0564
    green     (northing, easting) float16 0.1027 0.09839 ... 0.07593 0.07043
    red       (northing, easting) float16 0.09778 0.09778 ... 0.06799 0.06177
    nir       (northing, easting) float16 0.2988 0.2715 0.2881 ... 0.2637 0.251
    swir1     (northing, easting) float16 0.2311 0.2274 0.2316 ... 0.1608 0.142
    swir2     (northing, easting) float16 0.145 0.1442 0.144 ... 0.09961 0.08655
    rgb       (northing, easting, channel) uint8 101 108 57 255 ... 47 60 39 255
    cir       (northing, easting, channel) uint8 190 62 65 255 ... 160 39 44 255
Attributes: (12/19)
    Conventions:                CF-1.8
    title:                      Landsat 8 scene from 2019-01-30 (path/row=218...
    digital_object_identifier:  https://doi.org/10.5066/P9OGBGM6
    origin:                     Image courtesy of the U.S. Geological Survey
    landsat_product_id:         LC08_L2SP_218074_20190130_20200829_02_T1
    processing_level:           L2SP
    ...                         ...
    ellipsoid:                  WGS84
    date_acquired:              2019-01-30
    scene_center_time:          12:57:09.1851220Z
    wrs_path:                   218
    wrs_row:                    74
    mtl_file:                   GROUP = LANDSAT_METADATA_FILE\n  GROUP = PROD...

Plotting composites#

Composites can be plotted using xarray.DataArray.plot.imshow (using plot won’t work and will display histograms instead). Let’s make the before and after figures again for each of the composites we generated.

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 12))

# Plot the composites
before.rgb.plot.imshow(ax=ax1)
after.rgb.plot.imshow(ax=ax2)

# The "long_name" of the composite is the band combination
ax1.set_title(f"Before: {before.rgb.attrs['long_name']}")
ax2.set_title(f"After: {after.rgb.attrs['long_name']}")

ax1.set_aspect("equal")
ax2.set_aspect("equal")

plt.show()
_images/composites_3_0.png

And now the CIR composites:

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 12))

before.cir.plot.imshow(ax=ax1)
after.cir.plot.imshow(ax=ax2)

ax1.set_title(f"Before: {before.cir.attrs['long_name']}")
ax2.set_title(f"After: {after.cir.attrs['long_name']}")

ax1.set_aspect("equal")
ax2.set_aspect("equal")

plt.show()
_images/composites_4_0.png