## 1. Explore the cloud mask asset

### 1.1 Access the cloud mask COG

```python
import rioxarray as rxr
from matplotlib import pyplot as plt
import matplotlib.colors as mcolors
import seaborn as sns
import numpy as np

cloud_mask = rxr.open_rasterio(item.assets['CLOUD_MASK'].href)
```

### 1.2 Visualize the cloud mask

```python
def plot_mask(data, set_min=True, title=None, cmap='cubehelix', vmin=None, vmax=None, colorbar_label=None):
    '''
    data: a DataArray containing quality or cloud mask data
    set_min: boolean, if True, sets the color for the minimum value to white
    title: None or string representing the title of the plot
    cmap: colormap to be used with plt.imshow()
    vmin, vmax: min and max values for the colormap
    colorbar_label: None or string
    '''
    data = data.squeeze() # Remove extra dimension if present

min_val = int(data.min().values)
    max_val = int(data.max().values)
    n_colors = max_val - min_val +1

cmap = sns.color_palette(cmap, n_colors) # Discrete cmap with breaks at every integer
    if set_min: cmap[0] = 'whitesmoke' # set specific color for min
    cmap = mcolors.ListedColormap(cmap)

bounds = np.arange(min_val, max_val+2)
    norm = mcolors.BoundaryNorm(bounds, cmap.N)

plt.figure(figsize=(12,10))
    plot = plt.imshow(data, cmap=cmap, norm=norm)
    if colorbar_label is not None:
        max_ticks = 10
        values = np.arange(min_val, max_val + 1)
        tick_values = values if len(values) <= max_ticks else np.linspace(min_val, max_val, max_ticks, dtype=int)
        cbar = plt.colorbar(
            plot,
            label=colorbar_label,
            ticks=tick_values + 0.5
        )
        cbar.ax.set_yticklabels(tick_values)

plt.xticks([])
    plt.yticks([])
    plt.title(title, weight='bold')
    plt.tight_layout()
    plt.show()
    return
```

```python
plot_mask(cloud_mask, title=f'Item ID: {item.id}', colorbar_label='Cloud mask value')
```

### 1.3 Interpret the cloud mask pixel values

```python
def decimal_to_binary(value, bit_length=16):
    return format(value, f'0{bit_length}b')
```

```python
cloud_mask_bit_meanings = {
    0: "No data",
    1: "Cloud"
}
```

```python
import pandas as pd

def make_lookup_table(mask, meanings):

unique_decimal_values = np.unique(mask)
    binary_strings = [decimal_to_binary(int(val)) for val in unique_decimal_values]

df = pd.DataFrame({
        "Decimal": unique_decimal_values,
        "Binary": binary_strings
    })

# Add Yes/No columns for each bit
    for bit, bit_name in meanings.items():
        df[bit_name] = ["Yes" if binary[-(bit + 1)] == "1" else "No" for binary in binary_strings] # -(bit + 1) ensures we are reading the string from right to left

return df
```

```python
cloud_LUT = make_lookup_table(cloud_mask, cloud_mask_bit_meanings)
cloud_LUT
```

| Decimal | Binary               | No data | Cloud |
|---------|----------------------|---------|-------|
| 0.0    | 0000000000000000     | No      | No    |
| 1.0    | 0000000000000001     | Yes     | No    |
| 2.0    | 0000000000000010     | No      | Yes   |

## Access the QA mask asset

```python
qa_mask = rxr.open_rasterio(item.assets['quality_assurance'].href).squeeze()
```

```python
qa_mask_bit_meanings = {
    0: "Blue band saturation",
    1: "Green band saturation",
    2: "Red band saturation",
    3: "Red edge 1 band saturation",
    4: "Red edge 2 band saturation",
    5: "Red edge 3 band saturation",
    6: "NIR band saturation",
    7: "LWIR 1 band saturation",
    8: "LWIR 2 band saturation"
}
```

```python
plot_mask(qa_mask, set_min=False, cmap='rainbow', title=f'Item ID: {item.id}', colorbar_label='QA mask value')
```

## Interpret the QA mask pixel values

```python
qa_LUT = make_lookup_table(qa_mask, qa_mask_bit_meanings)
qa_LUT
```

| Decimal | Binary               | Blue band saturation | Green band saturation | Red band saturation | Red edge 1 band saturation | Red edge 2 band saturation | Red edge 3 band saturation | NIR band saturation | LWIR 1 band saturation | LWIR 2 band saturation |
|---------|----------------------|---------------------|----------------------|--------------------|----------------------------|---------------------------|--------------------------|----------------------|-----------------------|-----------------------|
| 0       | 0000000000000000     | No                  | No                   | No                 | No                         | No                        | No                       | No                   | No                    | No                    |
| 1       | 0000000000000001     | Yes                 | No                   | No                 | No                         | No                        | No                       | No                   | No                    | No                    |
| 2       | 0000000000000010     | No                  | Yes                  | No                 | No                         | No                        | No                       | No                   | No                    | No                    |
| ...     | ...                  | ...                 | ...                  | ...                | ...                        | ...                       | ...                      | ...                  | ...                   | ...                   |

The bottom line is that a pixel value of 0 means that no bands are saturated, while a nonzero pixel value indicates some saturation.
