Skip to content

Stats dataset toareflectances

Install marss2l package

pip install marss2l
from marss2l.utils import setup_stream_logger, pathjoin

from huggingface_hub import hf_file_system
from marss2l.huggingface import REPO_ID

fs = hf_file_system.HfFileSystem()

logger = setup_stream_logger()
/home/gonzalo/mambaforge/envs/marss2lpy312_dev/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm

2026-07-09 10:10:35.425 | INFO     | marss2l.utils:setup_stream_logger:157 - marss2l Version: 0.2.8

from marss2l import loaders
import os

os.makedirs("figures", exist_ok=True)

Read validated images

csv_path = f"datasets/{REPO_ID}/validated_images_all.csv" 

dataframe_data_traintest = loaders.read_csv(csv_path, 
                                            add_columns_for_analysis=True, 
                                            add_case_study=True,
                                            split="all",
                                            fs=fs)
dataframe_data_traintest.shape
(93538, 58)
dataframe_data_traintest.columns
Index(['id_loc_image', 's2path', 'plumepath', 'cloudmaskpath', 'ch4path',
       'wind_u', 'wind_v', 'vza', 'sza', 'percentage_clear', 'tile', 'isplume',
       'ch4_fluxrate', 'ch4_fluxrate_std', 'satellite', 'tile_date',
       'notified', 'id_location', 'last_update', 'location_name', 'country',
       'lon', 'lat', 'offshore', 'sector', 'observability',
       'background_image_tile', 'crs', 'transform_a', 'transform_b',
       'transform_c', 'transform_d', 'transform_e', 'transform_f', 'width',
       'height', 'window_row_off', 'window_col_off', 'window_height',
       'window_width', 'footprint', 'plume', 'split_name', 'case_study',
       'wind_source', 'geotransform', 'plumes_good_overlap', 'year',
       'year_month', 'year_month_day', 'wind_speed', 'isplumeneg', 'date',
       'satellite_constellation', 'year_quarter', 'ch4_fluxrate_th',
       'interval_ch4_fluxrate', 'interval_ch4_fluxrate_str'],
      dtype='str')
dataframe_test = dataframe_data_traintest[dataframe_data_traintest.split_name=="test_2023"].copy()
dataframe_test.shape
(43524, 58)
ids_test = set(dataframe_test.id_loc_image)
len(ids_test)
43524

Load MARS-S2L stats

import pandas as pd
import uuid
import numpy as np

stats_path = f"datasets/{REPO_ID}/data/stats_dataset.csv" 
with fs.open(stats_path) as fh:
    dataframe_stats_original = pd.read_csv(fh)
dataframe_stats_original["id_loc_image"] = dataframe_stats_original["id_loc_image"].apply(uuid.UUID)
dataframe_stats_original["isplume"] = dataframe_stats_original.isplume.astype(bool)
dataframe_stats_original.shape
(91594, 114)
# Fill noplume stats with normal stats
from tqdm import tqdm
for cnoplume in tqdm(dataframe_stats_original.columns):
    if "_noplume" in cnoplume:
        cnormal = cnoplume.replace("_noplume","")
        dataframe_stats_original[cnoplume] = dataframe_stats_original.apply(lambda row: getattr(row,cnoplume) if row.isplume else getattr(row,cnormal),axis=1)
100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 114/114 [02:13<00:00,  1.17s/it]

dataframe_stats = pd.merge(dataframe_stats_original, 
                           dataframe_data_traintest[["id_loc_image","offshore",'interval_ch4_fluxrate',"ch4_fluxrate", "ch4_fluxrate_std", 
                                                     'interval_ch4_fluxrate_str','year', 'year_month',"split_name", "country", "case_study",
                                                     "lat","lon","observability",
                                                    'satellite_constellation']],
                          on="id_loc_image")
dataframe_stats["offshorestr"] = dataframe_stats["offshore"].apply(lambda x: "YES" if x else "NO")
dataframe_stats["isplumestr"] = dataframe_stats.isplume.apply(lambda x: "YES" if x &gt;.1 else "NO")
/tmp/ipykernel_70244/2018036628.py:7: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  dataframe_stats["offshorestr"] = dataframe_stats["offshore"].apply(lambda x: "YES" if x else "NO")
/tmp/ipykernel_70244/2018036628.py:8: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  dataframe_stats["isplumestr"] = dataframe_stats.isplume.apply(lambda x: "YES" if x >.1 else "NO")

# Sanity check: isplume only has npixelsplume &gt; 0
dataframe_stats[dataframe_stats.isplume &amp; (dataframe_stats.npixelsplume == 0)]
location_name tile id_loc_image isplume wind_u wind_v npixelsplume npixels ch4_mean ch4_std ... year_month split_name country case_study lat lon observability satellite_constellation offshorestr isplumestr

0 rows Γ— 130 columns

dataframe_stats_test = dataframe_stats[dataframe_stats.id_loc_image.isin(ids_test)].copy()
dataframe_stats_test.shape
dataframe_stats_test_isplume = dataframe_stats_test[dataframe_stats_test.isplume.astype(bool)].copy()
dataframe_stats_test_isplume["snr"] = dataframe_stats_test_isplume["ch4_mean_plume"] / dataframe_stats_test_isplume["ch4_mean_noplume"]
dataframe_stats_test_isplume.shape
(1811, 131)
dataframe_stats["MBMP_mean"].min(), dataframe_stats["MBMP_mean"].max() 
(np.float64(0.257096529006958), np.float64(0.622031569480896))

Load CloudSEN12 stats

csv_path_cloudsen12 = f"datasets/{REPO_ID}/cloudsen12_clear_images.csv" 
with fs.open(csv_path_cloudsen12, "r") as fh:
    cloudsen12 = pd.read_csv(fh)

stats_path_cloudsen12 = f"datasets/{REPO_ID}/cloudsen12_data/cloudsen12_stats_dataset.csv"
with fs.open(stats_path_cloudsen12, "r") as fh:
    cloudsen12_stats = pd.read_csv(fh)

# cloudsen12["id_loc_image"] = cloudsen12["id_loc_image"].apply(uuid.UUID)
cloudsen12["isplume"] = cloudsen12.isplume.astype(bool)
cloudsen12.shape, cloudsen12_stats.shape
((10435, 45), (10434, 42))
cloudsen12.columns
Index(['s2path', 'plumepath', 'cloudmaskpath', 'ch4path', 'wind_u', 'wind_v',
       'vza', 'sza', 'percentage_clear', 'tile', 'isplume', 'ch4_fluxrate',
       'ch4_fluxrate_std', 'satellite', 'tile_date', 'notified', 'id_location',
       'last_update', 'location_name', 'country', 'lon', 'lat', 'offshore',
       'sector', 'observability', 'background_image_tile', 'crs',
       'transform_a', 'transform_b', 'transform_c', 'transform_d',
       'transform_e', 'transform_f', 'width', 'height', 'window_row_off',
       'window_col_off', 'window_height', 'window_width', 'footprint', 'plume',
       'split_name', 'id_loc_image', 'stac:centroid', 'roi_id'],
      dtype='str')
cloudsen12_stats_merged = pd.merge(cloudsen12_stats, 
                           cloudsen12[["location_name","ch4_fluxrate", "ch4_fluxrate_std",
                                        "country",'lon', 'lat', "observability"]],
                          left_on="id_loc_image", right_on="location_name")
cloudsen12_stats_merged["isplumestr"] = cloudsen12_stats_merged.isplume.apply(lambda x: "YES" if x &gt;.1 else "NO")
cloudsen12_stats_merged["ch4_fluxrate"] = 0
cloudsen12_stats_merged["Q"] = 0
cloudsen12_stats_merged["ch4_fluxrate_std"] = 0
cloudsen12_stats_merged["case_study"] = "CloudSEN12"
cloudsen12_stats_merged["MBMP_std_noplume"] = cloudsen12_stats_merged["MBMP_std"]
cloudsen12_stats_merged["B12_mean_noplume"] = cloudsen12_stats_merged["B12_mean"]
cloudsen12_stats_merged["ch4_std_noplume"] = cloudsen12_stats_merged["ch4_std"]
cloudsen12_stats_merged["ch4_mean_noplume"] = cloudsen12_stats_merged["ch4_mean"]
cloudsen12_stats_merged.shape
(10434, 56)
dataframe_stats_test_withcloudsen12 = pd.concat([dataframe_stats_test, cloudsen12_stats_merged], axis=0,
                                      ignore_index=True)
dataframe_stats_test_withcloudsen12.shape
(53958, 132)
dataframe_stats_test_withcloudsen12.observability.value_counts()
observability
clear            49007
cloudy            2428
bad_retrieval     1727
shadow             545
snow               165
smoke               86
Name: count, dtype: int64

Stats by case study

import matplotlib.pyplot as plt
import seaborn as sns
from marss2l.plot import C0, C1, C2
import numpy as np

fig, ax = plt.subplots(1,3, figsize=(12,6),
                       sharey=True,tight_layout=True)

case_studies_plot = [c for c in loaders.ORDER_CASE_STUDIES if c != "Rest"]

sns.boxplot(data=dataframe_stats_test, 
            x="MBMP_std_noplume", hue="isplumestr", y="case_study", ax=ax[0],legend=False,
            palette=[C0, C2], hue_order= ["YES", "NO"],
            order=case_studies_plot)
# ax[0].set_xlim(0,0.027)
ax[0].set_xlim(0,0.08)

sns.boxplot(data=dataframe_stats_test, 
            x="B12_mean_noplume", hue="isplumestr", y="case_study", ax=ax[1],
            palette=[C0, C2], hue_order= ["YES", "NO"],
            order=case_studies_plot)
sns.move_legend(ax[1], "lower right" ,title="Image with emission")
ax[1].set_xlabel(r"ToA reflectance SWIR2 outside plume")
ax[0].set_xlabel(r"$\sigma$ MBMP outside plume")
ax[0].set_ylabel("")
ax[1].set_xlim(0,0.7)

sns.boxplot(data=dataframe_stats_test, 
            x="Q",y="case_study", ax=ax[2],
            color=C0,
            order=case_studies_plot)

for axs in ax:
    axs.xaxis.grid(True)

ax[2].set_xticks(range(0, 50_000, 10_000), [f"{d/1000:.0f}" for d in range(0, 50_000, 10_000)])
ax[2].set_xlabel("Flux rate (t/h)")
ax[2].set_xscale("log")
ax[2].set_xlim(100, 70_000)
fig.savefig("figures/stats_toa_mbmp.pdf")
No description has been provided for this image

Stats by case study with CloudSEN12

dataframe_stats_test_withcloudsen12.case_study.value_counts()
case_study
CloudSEN12                    10434
Turkmenistan                   9438
United States of America       8043
Libya                          6473
Algeria                        4251
Arabian peninsula              3547
Uzbekistan & Kazakhstan        2535
Iran (Islamic Republic of)     2388
Offshore                       2224
Rest                           1830
Egypt                          1672
Syrian Arab Republic            550
Iraq                            463
Venezuela                       110
Name: count, dtype: int64
fig, ax = plt.subplots(1,3, figsize=(12,6),
                       sharey=True,tight_layout=True)

case_studies_plot = [c for c in loaders.ORDER_CASE_STUDIES if c != "Rest"] + ["CloudSEN12"]

sns.boxplot(data=dataframe_stats_test_withcloudsen12, 
            x="MBMP_std_noplume", hue="isplumestr", y="case_study", ax=ax[0],legend=False,
            palette=[C0, C2], hue_order= ["YES", "NO"],
            order=case_studies_plot)
# ax[0].set_xlim(0,0.027)
ax[0].set_xlim(0,0.08)

sns.boxplot(data=dataframe_stats_test_withcloudsen12, 
            x="B12_mean_noplume", hue="isplumestr", y="case_study", ax=ax[1],
            palette=[C0, C2], hue_order= ["YES", "NO"],
            order=case_studies_plot)
sns.move_legend(ax[1], "lower right" ,title="Image with emission")
ax[1].set_xlabel(r"ToA reflectance SWIR2 outside plume")
ax[0].set_xlabel(r"$\sigma$ MBMP outside plume")
ax[0].set_ylabel("")
ax[1].set_xlim(0,0.7)

sns.boxplot(data=dataframe_stats_test_withcloudsen12, 
            x="Q",y="case_study", ax=ax[2],
            color=C0,
            order=case_studies_plot)

for axs in ax:
    axs.xaxis.grid(True)

ax[2].set_xticks(range(0, 50_000, 10_000), [f"{d/1000:.0f}" for d in range(0, 50_000, 10_000)])
ax[2].set_xlabel("Flux rate (t/h)")
ax[2].set_xscale("log")
ax[2].set_xlim(100, 70_000)
fig.savefig("figures/stats_toa_mbmp_with_cloudsen12.pdf")
No description has been provided for this image

Stats $\Delta$XCH$_4$

from matplotlib.ticker import ScalarFormatter, FuncFormatter
from marshsi.quantification import convert_units

units_out = "ppm x m"  # units for the DeltaXCH4 axis; if != "ppb" convert from ppb

fig, ax = plt.subplots(1,2, figsize=(12,6),
                       sharey=True,tight_layout=True)

case_studies_plot = [c for c in loaders.ORDER_CASE_STUDIES if c != "Rest"] + ["CloudSEN12"]

dataframe_stats_test_withcloudsen12_obsclear = dataframe_stats_test_withcloudsen12[dataframe_stats_test_withcloudsen12.observability=="clear"].copy()

# DeltaXCH4 is stored in ppb; convert to units_out if needed (leave the shared df untouched)
plot_df_dxch4 = dataframe_stats_test_withcloudsen12_obsclear.copy()
xlim_dxch4 = (10, 30_000)
if units_out != "ppb":
    plot_df_dxch4["ch4_mean_noplume"] = convert_units(plot_df_dxch4["ch4_mean_noplume"].to_numpy(), "ppb", units_out)
    xlim_dxch4 = tuple(convert_units(np.array(xlim_dxch4, dtype=float), "ppb", units_out))

sns.boxplot(data=plot_df_dxch4, 
            x="ch4_mean_noplume", hue="isplumestr", y="case_study", ax=ax[0],legend=False,
            palette=[C0, C2], hue_order= ["YES", "NO"],
            order=case_studies_plot)
ax[0].set_xscale("log")
ax[0].set_xlim(*xlim_dxch4)
ax[0].xaxis.set_major_formatter(ScalarFormatter())

ax[0].set_xlabel(rf"$\Delta$XCH$_4$ outside plume ({units_out})")
ax[0].set_ylabel("")

# add the number of images per case study to the y-axis labels
counts_obsclear = dataframe_stats_test_withcloudsen12_obsclear["case_study"].value_counts()
ax[0].set_yticks(range(len(case_studies_plot)))
ax[0].set_yticklabels([f"{c} ({counts_obsclear.get(c, 0)})" for c in case_studies_plot])


sns.boxplot(data=dataframe_stats_test_withcloudsen12, 
            x="Q",y="case_study", ax=ax[1],
            color=C0,
            order=case_studies_plot)

for axs in ax:
    axs.xaxis.grid(True, which="both")

ax[1].set_xscale("log")
# ax[1].set_xlim(100, 50_000)
ax[1].xaxis.set_major_formatter(FuncFormatter(lambda d, _: f"{d/1000:g}"))
ax[1].set_xlabel("Flux rate (t/h)")
# fig.savefig("figures/stats_toa_dxch4_with_cloudsen12.pdf")
Text(0.5, 0, 'Flux rate (t/h)')
No description has been provided for this image
pd.concat([dataframe_stats_test_withcloudsen12_obsclear.case_study.value_counts(), 
           dataframe_stats_test_withcloudsen12.case_study.value_counts()], 
           axis=1, keys=["clear", "all"])
clear all
case_study
CloudSEN12 10343 10434
Turkmenistan 7671 9438
United States of America 7344 8043
Libya 6225 6473
Algeria 3954 4251
Arabian peninsula 3359 3547
Iran (Islamic Republic of) 2131 2388
Uzbekistan & Kazakhstan 2083 2535
Offshore 1912 2224
Rest 1584 1830
Egypt 1515 1672
Syrian Arab Republic 464 550
Iraq 364 463
Venezuela 58 110
from matplotlib.ticker import ScalarFormatter, FuncFormatter
from marshsi.quantification import convert_units

units_out = "ppm x m"  # units for the DeltaXCH4 axis; if != "ppb" convert from ppb

# fig, ax = plt.subplots(1,3, figsize=(12,6),
#                        sharey=True,tight_layout=True)

fig, ax = plt.subplots(1, 3, figsize=(12, 5), sharey=True, tight_layout=True, 
                       gridspec_kw={'width_ratios': [2, 1, 1]})

case_studies_plot = [c for c in loaders.ORDER_CASE_STUDIES if c != "Rest"] + ["CloudSEN12"]

# DeltaXCH4 is stored in ppb; convert to units_out if needed (leave the shared df untouched)
plot_df_dxch4 = dataframe_stats_test_withcloudsen12_obsclear.copy()
xlim_dxch4 = (10, 30_000)
if units_out != "ppb":
    plot_df_dxch4["ch4_mean_noplume"] = convert_units(plot_df_dxch4["ch4_mean_noplume"].to_numpy(), "ppb", units_out)
    xlim_dxch4 = tuple(convert_units(np.array(xlim_dxch4, dtype=float), "ppb", units_out))

sns.boxplot(data=plot_df_dxch4, 
            x="ch4_mean_noplume", hue="isplumestr", y="case_study", ax=ax[0],legend=False,
            palette=[C0, C2], hue_order= ["YES", "NO"],
            order=case_studies_plot)
ax[0].set_xscale("log")
ax[0].set_xlim(*xlim_dxch4)
ax[0].xaxis.set_major_formatter(ScalarFormatter())

ax[0].set_xlabel(rf"$\Delta$XCH$_4$ outside plume ({units_out})")
ax[0].set_ylabel("")

# add the number of images per case study to the y-axis labels
counts_obsclear = dataframe_stats_test_withcloudsen12_obsclear["case_study"].value_counts()
ax[0].set_yticks(range(len(case_studies_plot)))
ax[0].set_yticklabels([f"{c} ({counts_obsclear.get(c, 0)})" for c in case_studies_plot])


sns.boxplot(data=dataframe_stats_test_withcloudsen12, 
            x="B12_mean_noplume", hue="isplumestr", y="case_study", ax=ax[1],
            palette=[C0, C2], hue_order= ["YES", "NO"],
            order=case_studies_plot)
sns.move_legend(ax[1], "lower right" ,title="Image with emission")
ax[1].set_xlabel(r"ToA reflectance SWIR2 outside plume")
ax[1].set_xlim(0,0.7)

sns.boxplot(data=dataframe_stats_test_withcloudsen12, 
            x="Q",y="case_study", ax=ax[2],
            color=C0,
            order=case_studies_plot)

for axs in ax:
    axs.xaxis.grid(True, which="both")

ax[2].set_xscale("log")
ax[2].set_xlim(100, 70_000)
ax[2].xaxis.set_major_formatter(FuncFormatter(lambda d, _: f"{d/1000:g}"))
ax[2].set_xlabel("Flux rate (t/h)")
Text(0.5, 0, 'Flux rate (t/h)')
No description has been provided for this image

SNR by case study for plume images

fig, ax = plt.subplots(1,2, figsize=(12,6),
                       sharey=True,tight_layout=True)

case_studies_plot = [c for c in loaders.ORDER_CASE_STUDIES if c != "Rest"] + ["CloudSEN12"]

sns.boxplot(data=dataframe_stats_test_isplume, 
            x="snr",y="case_study", ax=ax[0],legend=False,
            color=C0, 
            order=case_studies_plot)
ax[0].set_xlim(0,10)
# ax[0].set_xlim(0,3000)
# ticks = np.arange(0,1000,100).tolist() + np.arange(1000,3000,200).tolist()
ticks = np.arange(0,10,.5)
ax[0].set_xticks(ticks)
ax[0].set_xticklabels(ticks, rotation=45)

ax[0].set_xlabel(r"SNR $\Delta$XCH$_4$")
ax[0].set_ylabel("")


sns.boxplot(data=dataframe_stats_test_isplume, 
            x="Q",y="case_study", ax=ax[1],
            color=C0,
            order=case_studies_plot)

for axs in ax:
    axs.xaxis.grid(True)

ax[1].set_xticks(range(0, 50_000, 10_000), [f"{d/1000:.0f}" for d in range(0, 50_000, 10_000)])
ax[1].set_xlabel("Flux rate (t/h)")
ax[1].set_xscale("log")
ax[1].set_xlim(100, 70_000)
(100, 70000)
No description has been provided for this image

Plumes detected with low ToA reflectance

weird_onshore_plumes = dataframe_stats_test_isplume[~dataframe_stats_test_isplume.offshore &amp; \
                                                          (dataframe_stats_test_isplume.B12_mean_noplume &lt; 0.2)].copy()
weird_onshore_plumes[["location_name", "tile", "id_loc_image", "Q", "B12_mean_noplume"]].sort_values("Q", ascending=False)
location_name tile id_loc_image Q B12_mean_noplume
26047 CHN_qq9g4wd9e S2B_MSIL1C_20241023T030709_N0511_R075_T50SMJ_2... b0df8c90-2066-425a-9f39-15c4cf27b69f 305363.966760 0.154821
86220 USA_hkth1ywhh LC09_L1TP_027036_20241109_20241109_02_T1 9780ab2e-7170-4839-b13e-0d2545fd8a02 129194.493294 0.142115
86218 USA_hkth1ywhh S2B_MSIL1C_20241111T170439_N0511_R069_T14SQC_2... f5f18f8b-c0ac-4bc2-885a-e9b83edf9bf4 124929.598045 0.153612
26027 CHN_qq82d97ox S2A_MSIL1C_20241120T032031_N0511_R118_T49SFV_2... 06491efa-726a-4b2f-a771-7ab69e3241b1 120883.138612 0.142582
86732 USA_w7e8ngghj S2B_MSIL1C_20241023T163249_N0511_R083_T16RBV_2... 9123854a-64f6-4791-9255-63ad109e0896 47586.010859 0.052162
88318 VEN_whwgthbp0 S2B_MSIL1C_20241106T144729_N0511_R139_T20PMR_2... fc3ac2a0-816a-437d-99c6-f7210dd6c3bb 44620.753583 0.131862
88320 VEN_whwgthbp0 LC08_L1TP_002053_20241017_20241022_02_T1 9bf6fa08-0a0e-4f56-bec4-879eb69382cf 39890.578127 0.138915
88324 VEN_whwgthbp0 S2B_MSIL1C_20240220T144729_N0510_R139_T20PMR_2... d916b2e9-aa22-46c3-bfd3-07eaad328946 23661.834741 0.165026
88290 VEN_0003 S2A_MSIL1C_20240428T145731_N0510_R039_T20PKS_2... 02e43c1e-4e58-485f-a3e1-34e9cf9aad68 18067.894399 0.155305
75790 T_25 LC08_L1TP_163034_20240416_20240416_02_RT de391981-c893-4381-8b5a-e687f2ee8c8e 17793.194280 0.194405
68719 RUS_0002 S2B_MSIL1C_20240409T081609_N0510_R121_T37TEM_2... 2e0a3c08-e476-49b1-8867-1e5ee0be47c6 17293.285457 0.142648
88294 VEN_0003 S2B_MSIL1C_20240413T145729_N0510_R039_T20PKS_2... 34b6f78b-793c-41a8-82c7-c58ec7ed8d00 16498.828684 0.146223
88295 VEN_0003 LC09_L1TP_003053_20240407_20240407_02_T1 a26e4ed1-9c62-4453-aec3-b4b02f329dbf 14246.804903 0.131819
84847 Te_N_8 LC08_L1TP_163034_20240111_20240111_02_RT dba43e42-a129-4ba0-82fa-043ee604ee03 4052.093228 0.169695
39635 EMIT_CH4_PlumeComplex-395 LC08_L1TP_029038_20241217_20241217_02_RT 059fb206-bec8-4e69-8271-6cc7c9c3f9dd 4032.344957 0.199815
84848 Te_N_8 S2B_MSIL1C_20240109T071259_N0510_R106_T39SYB_2... 82ec739b-f56e-49ca-aba7-48c9a4006ebc 4004.922342 0.175383
80800 T_EMIT_6 S2A_MSIL1C_20240722T070621_N0510_R106_T39SYD_2... cb0620b3-737f-4188-9d6b-3684a06b0354 3803.731149 0.195970
84838 Te_N_8 LC09_L1TP_163034_20240220_20240220_02_T1 b8c83175-65e2-4438-8057-cb827c1e96ba 3640.930005 0.188476
77823 T_7 LC08_L1TP_163033_20240111_20240111_02_RT 98d7ed6d-036e-48ef-bba5-a43772aa2b2a 3530.642339 0.198538
70290 TKM_fpmgnycs1 S2A_MSIL1C_20241107T063051_N0511_R077_T41SNB_2... 645473e2-3282-4c0e-a966-d4340477ad5f 3417.240932 0.189170
23774 Ag_0005 LC09_L1TP_229092_20240422_20240422_02_T1 94d9c57e-1cfc-4982-8464-8d2b1a8e4e30 3313.915688 0.195394
84843 Te_N_8 S2A_MSIL1C_20240203T071111_N0510_R106_T39SYB_2... 70141d73-9205-4225-8f35-094b935dd041 2391.460402 0.160446

Stats size of the plume

dataframe_stats_isplume = dataframe_stats[dataframe_stats.isplume].copy()
 # &amp; (dataframe_stats.npixelsplume == 0)]
dataframe_stats_isplume.shape
(5738, 130)
ax = sns.histplot(data=dataframe_stats_isplume, x="npixelsplume",
                  common_norm=False)
ax.set_xlabel("# pixels plume (10m resolution)")
Text(0.5, 0, '# pixels plume (10m resolution)')
No description has been provided for this image
import numpy as np
ax = sns.histplot(data=dataframe_stats_isplume[dataframe_stats_isplume.npixelsplume &lt; 300], 
             x="npixelsplume",
             bins = np.arange(0,301,50),
             # hue_order=[False, True],
             common_norm=False)
ax.set_xlabel("# pixels plume (10m resolution)")
Text(0.5, 0, '# pixels plume (10m resolution)')
No description has been provided for this image

Average noise by region in CloudSEN12 dataset

from marss2l.plot import map_ch4_background
from importlib import reload
reload(map_ch4_background)

units_out = "ppm x m"     # output units for the color scale, e.g. "ppb", "ppm", "ppm x m"
plot_type = "hexbin"  # "hexbin" or "scatterplot"

map_ch4_background.plot_ch4_background_map(
    cloudsen12_stats_merged[cloudsen12_stats_merged.observability=="clear"],
    units_out=units_out,
    plot_type=plot_type,
    title=r"CloudSEN12 average $\Delta$XCH$_4$ outside plume",
)
<GeoAxes: title={'center': 'CloudSEN12 average $\\Delta$XCH$_4$ outside plume'}>
No description has been provided for this image

Average noise by region in MARS-S2L test dataset

units_out = "ppm x m"     # output units for the color scale, e.g. "ppb", "ppm", "ppm x m"
plot_type = "hexbin"  # "hexbin" or "scatterplot"

map_ch4_background.plot_ch4_background_map(
    dataframe_stats_test[dataframe_stats_test.observability=="clear"],
    units_out=units_out,
    plot_type=plot_type,
    title=r"MARS-S2L test average $\Delta$XCH$_4$ outside plume",
)
<GeoAxes: title={'center': 'MARS-S2L test average $\\Delta$XCH$_4$ outside plume'}>
No description has been provided for this image
units_out = "ppm x m"     # output units for the color scale, e.g. "ppb", "ppm", "ppm x m"
plot_type = "scatterplot"  # "hexbin" or "scatterplot"

map_ch4_background.plot_ch4_background_map(
    dataframe_stats_test_withcloudsen12_obsclear,
    units_out=units_out,
    plot_type=plot_type,
    title=r"MARS-S2L test &amp; CloudSEN12 average $\Delta$XCH$_4$ outside plume",
)
<GeoAxes: title={'center': 'MARS-S2L test & CloudSEN12 average $\\Delta$XCH$_4$ outside plume'}>
No description has been provided for this image
reload(map_ch4_background)  # picks up the count mode (value_column=None)

# number of images per hexbin for the MARS-S2L test dataset
map_ch4_background.plot_ch4_background_map(
    dataframe_stats_test,
    value_column=None,   # count images per cell instead of averaging a value
    plot_type="hexbin",
    vmin=None,
    vmax=None,
    cmap="viridis",
    title=r"MARS-S2L test number of images per hexbin",
)
<GeoAxes: title={'center': 'MARS-S2L test number of images per hexbin'}>
No description has been provided for this image