Skip to content

Eval model and figure prob vs emission rate

Eval results of the model

This notebook has the stats of the model evaluated against a couple of baselines: the MBMP threshold model and the CH4Net model of Vaughan et al 2024. We reproduce in this notebook figure 2, 3 and several other figures in the supplementary material. In addition in this notebook we have the statistics that are mentioned in the text (precision, recall, average precision, false positive rates...)

This notebook read the cached results from the Hugging Face repository. For re-evaluate the model see README.md.

Install marss2l package

pip install marss2l
%%time
import matplotlib
from marss2l.utils import setup_stream_logger, get_remote_filesystem, pathjoin
from marss2l import loaders
import logging
import os

import uuid
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import PrecisionRecallDisplay, precision_score, recall_score, accuracy_score,\
    average_precision_score, confusion_matrix
from sklearn.metrics import RocCurveDisplay, roc_curve
import numpy as np
from marss2l.plot.colors import C0, C1, C2, C3, C4
import seaborn as sns
import json
from huggingface_hub import hf_file_system
from marss2l.huggingface import REPO_ID

fs = hf_file_system.HfFileSystem()

logger = logging.getLogger(__name__)
setup_stream_logger(logger)


os.makedirs("figures", exist_ok=True)
/home/gonzalo/mambaforge/envs/marss2ltacopy312/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

CPU times: user 9.67 s, sys: 2.8 s, total: 12.5 s
Wall time: 10.8 s

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

dataframe_data_traintest = loaders.read_csv(csv_path,
                                            add_columns_for_analysis=True, fs=fs, 
                                            split="all", 
                                            add_case_study=True, add_loc_type=True)
dataframe_data_traintest.shape
(93538, 59)
# Sanity check: fluxrate is positive and defined always
dataframe_data_traintest.loc[(dataframe_data_traintest.ch4_fluxrate < 0) | dataframe_data_traintest.ch4_fluxrate.isna(),["location_name","satellite","tile_date","observability","isplume","ch4_fluxrate","country","wind_speed"]]
location_name satellite tile_date observability isplume ch4_fluxrate country wind_speed
# Sanity check: fluxrate is zero for no plumes
dataframe_data_traintest[~dataframe_data_traintest.isplume].ch4_fluxrate.sum()
0.0
# Sanity check: All isplume have positive flux rates
dataframe_data_traintest[dataframe_data_traintest.isplume & (dataframe_data_traintest.ch4_fluxrate == 0)]
id_loc_image s2path plumepath cloudmaskpath ch4path wind_u wind_v vza sza percentage_clear ... year_month_day wind_speed isplumeneg date satellite_constellation year_quarter ch4_fluxrate_th interval_ch4_fluxrate interval_ch4_fluxrate_str loc_type

0 rows × 59 columns

Load CSV files with evaluation results

In the next cell we load the evaluation results. These results are loaded from the pre-computed CSV files in the basefolder_experiments path. If you re-evaluated the model following the instructions in the README.md, change the basefolder_experiments to your local path.

pd.options.display.float_format = "{:,.2f}".format
from importlib import reload
from marss2l import validation_utils


# basefolder_experiments = "xxxx/MARS-S2L/train_logs_revision/"
basefolder_experiments = f"datasets/{REPO_ID}/trained_models/"


outs = []
ids_all = None


expload = [
          ("CH4Netsim_20250605", "CH4Net (sim)", "preds_test_2023thr100"),
          ("MARSS2Lnosim_20250605", "MARS-S2L (no sim)", "preds_test_2023thr100"),
          ("MARSS2L_20250326", "MARS-S2L", "preds_test_2023th100"),
          ("MARSS2L_off_20250523", "MARS-S2L (offshore)", "preds_test_2023thr100"),
          ("CH4Net_20250329","CH4Net", "preds_test_2023thr100"),
          ("MBMP","MBMP", "preds_test_2023th100"),
]

config_experiments = dict()
for  train_folder, model_name, csv_file in  expload:
    output, config = validation_utils.load_stats_and_config(train_folder, model_name, csv_file=csv_file,
                                          basefolder_experiments=basefolder_experiments,fs=fs,
                                           logger=logger)
    if config is not None:
        config_experiments[model_name] = config

    ids_iter = set(output["id_loc_image"].values)
    if ids_all is None:
        ids_all = ids_iter
    else:
        ids_all = ids_all.intersection(ids_iter)
    outs.append(output)
print(f"There are {len(ids_all)} common ids")

outs = pd.concat(outs, ignore_index=True)
outs = outs[outs.id_loc_image.isin(ids_all)].copy()

outs.groupby(["model_name","target"])[["id_loc_image"]].count()
2025-12-02 15:12:55,070 - __main__ - INFO - Loading eval results from datasets/UNEP-IMEO/MARS-S2L/trained_models/CH4Netsim_20250605/preds_test_2023thr100.csv
2025-12-02 15:12:56,909 - __main__ - INFO - Loading config from datasets/UNEP-IMEO/MARS-S2L/trained_models/CH4Netsim_20250605/config_experiment.json
2025-12-02 15:12:57,331 - __main__ - INFO - Loading eval results from datasets/UNEP-IMEO/MARS-S2L/trained_models/MARSS2Lnosim_20250605/preds_test_2023thr100.csv
2025-12-02 15:12:59,694 - __main__ - INFO - Loading config from datasets/UNEP-IMEO/MARS-S2L/trained_models/MARSS2Lnosim_20250605/config_experiment.json
2025-12-02 15:13:00,056 - __main__ - INFO - Loading eval results from datasets/UNEP-IMEO/MARS-S2L/trained_models/MARSS2L_20250326/preds_test_2023th100.csv
2025-12-02 15:13:02,286 - __main__ - INFO - Loading config from datasets/UNEP-IMEO/MARS-S2L/trained_models/MARSS2L_20250326/config_experiment.json
2025-12-02 15:13:02,670 - __main__ - INFO - Loading eval results from datasets/UNEP-IMEO/MARS-S2L/trained_models/MARSS2L_off_20250523/preds_test_2023thr100.csv
2025-12-02 15:13:05,072 - __main__ - INFO - Loading config from datasets/UNEP-IMEO/MARS-S2L/trained_models/MARSS2L_off_20250523/config_experiment.json
2025-12-02 15:13:05,814 - __main__ - INFO - Loading eval results from datasets/UNEP-IMEO/MARS-S2L/trained_models/CH4Net_20250329/preds_test_2023thr100.csv
2025-12-02 15:13:08,029 - __main__ - INFO - Loading config from datasets/UNEP-IMEO/MARS-S2L/trained_models/CH4Net_20250329/config_experiment.json
2025-12-02 15:13:08,415 - __main__ - INFO - Loading eval results from datasets/UNEP-IMEO/MARS-S2L/trained_models/MBMP/preds_test_2023th100.csv

There are 43529 common ids

id_loc_image
model_name target
CH4Net 0 41716
1 1813
CH4Net (sim) 0 41716
1 1813
MARS-S2L 0 41716
1 1813
MARS-S2L (no sim) 0 41716
1 1813
MARS-S2L (offshore) 0 41716
1 1813
MBMP 0 41716
1 1813
threshold_mbmp = -.99
threshold_marss2l = 0.5
outs_merge = outs.drop(["location_name", "tile"], axis=1)
outs_same_period_with_fluxrate = pd.merge(outs_merge, dataframe_data_traintest[dataframe_data_traintest.split_name == "test_2023"], 
                                          on ="id_loc_image")
outs_same_period_with_fluxrate = outs_same_period_with_fluxrate.drop("target", axis=1) # Use isplume as GT from dataframe_data_traintest
outs_same_period_with_fluxrate["isplumenum"] = outs_same_period_with_fluxrate["isplume"].astype(int)
# outs_same_period_with_fluxrate["isplumeprednum"] = (outs_same_period_with_fluxrate["scene_pred"] > 0.5).astype(int)
outs_same_period_with_fluxrate["isplumeprednum"] = outs_same_period_with_fluxrate.apply(lambda row: row.scene_pred > threshold_mbmp if row.model_name.startswith("MBMP") else row.scene_pred > threshold_marss2l, axis=1).astype(int)
outs_same_period_with_fluxrate["scenepredcontinuous"] = outs_same_period_with_fluxrate["scene_pred"]
outs_same_period_with_fluxrate.id_loc_image.nunique()
43524

Combine offshore and onshore predictions for MARS-S2L model

marss2l_onshore = outs_same_period_with_fluxrate[((outs_same_period_with_fluxrate.model_name == "MARS-S2L") & ~outs_same_period_with_fluxrate.offshore)].copy()
marss2l_onshore["model_name"] = "MARS-S2L (combined)"
marss2l_offshore = outs_same_period_with_fluxrate[((outs_same_period_with_fluxrate.model_name == "MARS-S2L (offshore)") & outs_same_period_with_fluxrate.offshore)].copy()
marss2l_offshore["model_name"] = "MARS-S2L (combined)"
outs_same_period_with_fluxrate = pd.concat([outs_same_period_with_fluxrate, marss2l_onshore, marss2l_offshore], ignore_index=True)
outs_same_period_with_fluxrate.id_loc_image.nunique()

# Rename MARS-S2L combined and drop offshore
outs_same_period_with_fluxrate = outs_same_period_with_fluxrate[~outs_same_period_with_fluxrate.model_name.isin(["MARS-S2L (offshore)", "MARS-S2L"])].copy()
outs_same_period_with_fluxrate.loc[outs_same_period_with_fluxrate.model_name == "MARS-S2L (combined)","model_name"] = "MARS-S2L"
outs_same_period_with_fluxrate.groupby(["model_name","isplume"])[["id_loc_image"]].count()
id_loc_image
model_name isplume
CH4Net False 41692
True 1832
CH4Net (sim) False 41692
True 1832
MARS-S2L False 41692
True 1832
MARS-S2L (no sim) False 41692
True 1832
MBMP False 41692
True 1832
# Sanity check: all models are evaluated in the same number of images
outs_same_period_with_fluxrate.groupby("model_name")["tile_date"].agg(["min", "max", "count"])
min max count
model_name
CH4Net 2024-01-01 00:05:22.713000+00:00 2024-12-31 17:27:23.051000+00:00 43524
CH4Net (sim) 2024-01-01 00:05:22.713000+00:00 2024-12-31 17:27:23.051000+00:00 43524
MARS-S2L 2024-01-01 00:05:22.713000+00:00 2024-12-31 17:27:23.051000+00:00 43524
MARS-S2L (no sim) 2024-01-01 00:05:22.713000+00:00 2024-12-31 17:27:23.051000+00:00 43524
MBMP 2024-01-01 00:05:22.713000+00:00 2024-12-31 17:27:23.051000+00:00 43524
# Sanity check: all models are evaluated in the same number of images and same number of plumes/noplumes
outs_same_period_with_fluxrate.groupby(["isplume","model_name"])[["id_loc_image"]].count()
id_loc_image
isplume model_name
False CH4Net 41692
CH4Net (sim) 41692
MARS-S2L 41692
MARS-S2L (no sim) 41692
MBMP 41692
True CH4Net 1832
CH4Net (sim) 1832
MARS-S2L 1832
MARS-S2L (no sim) 1832
MBMP 1832
outs_same_period_with_fluxrate.model_name.unique()
array(['CH4Net (sim)', 'MARS-S2L (no sim)', 'CH4Net', 'MBMP', 'MARS-S2L'],
      dtype=object)

PR curves and general metrics

Overall metrics

Final model is MARS-S2L (U326v309)

from marss2l.metrics import get_scenelevel_metrics, get_pixellevel_metrics


mets = []
for idx_threshold, (threshold_marss2l_iter, threshold_mbmp_iter) in enumerate(zip([0.5, 0.9, 0.98],[threshold_mbmp, -0.9, -0.85])):
    # for model in ['MARS-S2L', 'CH4Net', "MBMP"]:
    for model in ['MARS-S2L', 'MARS-S2L (no sim)','CH4Net (sim)', 'CH4Net', "MBMP"]:
        dg = outs_same_period_with_fluxrate[outs_same_period_with_fluxrate.model_name == model]
        threshold = threshold_marss2l_iter if not model.startswith("MBMP") else threshold_mbmp_iter
        mets_iter = get_scenelevel_metrics(dg.scenepredcontinuous, dg.isplumenum, threshold=threshold,
                                           as_percentage=True)
        mets_seg = get_pixellevel_metrics(TP=dg.TP, TN=dg.TN, FP=dg.FP, FN=dg.FN,
                                         as_percentage=True)
        mets_iter.update(mets_seg)

        mets_iter.update({"nsamples": dg.shape[0],
                     "nlocs": dg.location_name.nunique(),
                     "nplumes": dg.isplumenum.sum(),
                     "threshold": threshold,
                          "idx_threshold": idx_threshold,
                     "nnoplume": (1-dg.isplumenum).sum(),
                     "model_name": model})
        mets.append(mets_iter)

mets = pd.DataFrame(mets)# .sort_values(["balanced_accuracy"], ascending=False)
overall_mets = mets[["model_name", "threshold"]+[c for c in mets.columns if c not in ["model_name", "threshold"]]].copy()
overall_mets
model_name threshold average_precision precision recall accuracy binary_cross_entropy fpr balanced_accuracy segmentation_precision segmentation_recall segmentation_accuracy segmentation_f1 segmentation_fpr iou nsamples nlocs nplumes idx_threshold nnoplume
0 MARS-S2L 0.50 63.96 32.92 78.77 92.35 0.23 7.05 85.86 40.22 62.61 99.79 48.98 0.15 32.43 43524 1289 1832 0 41692
1 MARS-S2L (no sim) 0.50 53.30 45.38 60.10 95.28 0.19 3.18 78.46 54.12 43.69 99.85 48.35 0.06 31.88 43524 1289 1832 0 41692
2 CH4Net (sim) 0.50 29.73 16.34 48.80 87.33 0.37 10.98 68.91 21.98 27.26 99.72 24.33 0.16 13.85 43524 1289 1832 0 41692
3 CH4Net 0.50 21.10 16.51 46.62 87.83 0.34 10.36 68.13 15.92 23.12 99.67 18.86 0.20 10.41 43524 1289 1832 0 41692
4 MBMP -0.99 4.26 4.77 78.55 33.11 1.52 68.89 54.83 0.26 3.21 97.84 0.49 2.00 0.24 43524 1289 1832 0 41692
5 MARS-S2L 0.90 63.96 52.83 68.89 96.10 0.23 2.70 83.09 40.22 62.61 99.79 48.98 0.15 32.43 43524 1289 1832 1 41692
6 MARS-S2L (no sim) 0.90 53.30 60.09 49.89 96.50 0.19 1.46 74.22 54.12 43.69 99.85 48.35 0.06 31.88 43524 1289 1832 1 41692
7 CH4Net (sim) 0.90 29.73 29.95 35.75 93.78 0.37 3.67 66.04 21.98 27.26 99.72 24.33 0.16 13.85 43524 1289 1832 1 41692
8 CH4Net 0.90 21.10 29.14 27.46 94.14 0.34 2.93 62.26 15.92 23.12 99.67 18.86 0.20 10.41 43524 1289 1832 1 41692
9 MBMP -0.90 4.26 2.88 9.22 83.07 1.52 13.68 47.77 0.26 3.21 97.84 0.49 2.00 0.24 43524 1289 1832 1 41692
10 MARS-S2L 0.98 63.96 68.92 58.46 97.14 0.23 1.16 78.65 40.22 62.61 99.79 48.98 0.15 32.43 43524 1289 1832 2 41692
11 MARS-S2L (no sim) 0.98 53.30 71.54 40.88 96.83 0.19 0.71 70.08 54.12 43.69 99.85 48.35 0.06 31.88 43524 1289 1832 2 41692
12 CH4Net (sim) 0.98 29.73 45.18 26.58 95.55 0.37 1.42 62.58 21.98 27.26 99.72 24.33 0.16 13.85 43524 1289 1832 2 41692
13 CH4Net 0.98 21.10 41.15 16.38 95.49 0.34 1.03 57.67 15.92 23.12 99.67 18.86 0.20 10.41 43524 1289 1832 2 41692
14 MBMP -0.85 4.26 2.76 4.75 88.94 1.52 7.36 48.69 0.26 3.21 97.84 0.49 2.00 0.24 43524 1289 1832 2 41692
cols_metrics = ['model_name', 'average_precision', 'precision', 'recall', 'accuracy',
        'fpr']
cols_metrics_segmentation = ['segmentation_precision', 'segmentation_recall',
       'segmentation_accuracy', 'segmentation_fpr', 'iou']
models_plot_recall = ["MBMP", "CH4Net", "MARS-S2L"]
overall_mets_table_7 = overall_mets[(overall_mets.idx_threshold == 0) & overall_mets.model_name.isin(models_plot_recall)].copy()
print(overall_mets_table_7[cols_metrics+cols_metrics_segmentation].to_latex(index=False,float_format="%.2f"))
\begin{tabular}{lrrrrrrrrrr}
\toprule
model_name & average_precision & precision & recall & accuracy & fpr & segmentation_precision & segmentation_recall & segmentation_accuracy & segmentation_fpr & iou \\
\midrule
MARS-S2L & 63.96 & 32.92 & 78.77 & 92.35 & 7.05 & 40.22 & 62.61 & 99.79 & 0.15 & 32.43 \\
CH4Net & 21.10 & 16.51 & 46.62 & 87.83 & 10.36 & 15.92 & 23.12 & 99.67 & 0.20 & 10.41 \\
MBMP & 4.26 & 4.77 & 78.55 & 33.11 & 68.89 & 0.26 & 3.21 & 97.84 & 2.00 & 0.24 \\
\bottomrule
\end{tabular}


overall_mets_table_7[cols_metrics+cols_metrics_segmentation]
model_name average_precision precision recall accuracy fpr segmentation_precision segmentation_recall segmentation_accuracy segmentation_fpr iou
0 MARS-S2L 63.96 32.92 78.77 92.35 7.05 40.22 62.61 99.79 0.15 32.43
3 CH4Net 21.10 16.51 46.62 87.83 10.36 15.92 23.12 99.67 0.20 10.41
4 MBMP 4.26 4.77 78.55 33.11 68.89 0.26 3.21 97.84 2.00 0.24
models_plot_recall = ["MBMP", "CH4Net", "MARS-S2L"]
col_metrics_table = ["model_name","threshold","precision", "recall", "fpr"]
overall_mets_table_thresholds = overall_mets.loc[overall_mets.model_name.isin(models_plot_recall)]
print(overall_mets_table_thresholds[col_metrics_table].to_latex(index=False,float_format="%.2f"))
\begin{tabular}{lrrrr}
\toprule
model_name & threshold & precision & recall & fpr \\
\midrule
MARS-S2L & 0.50 & 32.92 & 78.77 & 7.05 \\
CH4Net & 0.50 & 16.51 & 46.62 & 10.36 \\
MBMP & -0.99 & 4.77 & 78.55 & 68.89 \\
MARS-S2L & 0.90 & 52.83 & 68.89 & 2.70 \\
CH4Net & 0.90 & 29.14 & 27.46 & 2.93 \\
MBMP & -0.90 & 2.88 & 9.22 & 13.68 \\
MARS-S2L & 0.98 & 68.92 & 58.46 & 1.16 \\
CH4Net & 0.98 & 41.15 & 16.38 & 1.03 \\
MBMP & -0.85 & 2.76 & 4.75 & 7.36 \\
\bottomrule
\end{tabular}


overall_mets_table_thresholds[col_metrics_table]
model_name threshold precision recall fpr
0 MARS-S2L 0.50 32.92 78.77 7.05
3 CH4Net 0.50 16.51 46.62 10.36
4 MBMP -0.99 4.77 78.55 68.89
5 MARS-S2L 0.90 52.83 68.89 2.70
8 CH4Net 0.90 29.14 27.46 2.93
9 MBMP -0.90 2.88 9.22 13.68
10 MARS-S2L 0.98 68.92 58.46 1.16
13 CH4Net 0.98 41.15 16.38 1.03
14 MBMP -0.85 2.76 4.75 7.36
col_metrics_table
['model_name', 'threshold', 'precision', 'recall', 'fpr']
fig, ax = plt.subplots(1,2,figsize=(8, 4),tight_layout=True, sharey=False)
iaxes_roc = 1
iaxes_pr = 0
overall_mets_indexed = overall_mets.set_index("model_name")

colors = [C0, C4, C2, C3, C1]
# models_plot_prcurve = ["MBMP", "CH4Net", "MARS-S2L"] # "MARS-S2L (no sim)", "CH4Net (sim)"
models_plot_prcurve = ["MBMP", "CH4Net", "MARS-S2L", "MARS-S2L (no sim)", "CH4Net (sim)"] # "MARS-S2L (no sim)", "CH4Net (sim)"
df_show = outs_same_period_with_fluxrate[outs_same_period_with_fluxrate.model_name.isin(models_plot_prcurve)].copy()
for _i_prev, model_name in enumerate(models_plot_prcurve):
    dg = df_show[df_show.model_name == model_name]
    display = PrecisionRecallDisplay.from_predictions(dg.isplumenum, dg.scenepredcontinuous,
                                                      plot_chance_level=_i_prev == 0,
                                                      color=colors[_i_prev],
                                                      ax=ax[iaxes_pr], name=model_name)

    display = RocCurveDisplay.from_predictions(dg.isplumenum, dg.scenepredcontinuous,
                                               plot_chance_level=_i_prev == 0,
                                               color=colors[_i_prev],
                                                ax=ax[iaxes_roc], name=model_name)
    ax[0].scatter([overall_mets_indexed.loc[model_name, "recall"]/100], 
                  [overall_mets_indexed.loc[model_name, "precision"]/100],
                  c=colors[_i_prev],
                  s=100,
                  marker="x")
    ax[1].scatter([overall_mets_indexed.loc[model_name, "fpr"]/100],
                  [overall_mets_indexed.loc[model_name, "recall"]/100], 
                  c=colors[_i_prev],
                  s=100,
                  marker="x")

# ax[iaxes_pr].legend(loc="upper right")
ax[iaxes_pr].get_legend().remove()
ax[iaxes_roc].grid()
ax[iaxes_pr].grid()
ax[iaxes_pr].set_xticks(np.arange(0,1.05,.1))
ax[iaxes_pr].set_yticks(np.arange(0,1.05,.1))
ax[iaxes_pr].set_title("PR-Curve")
ax[iaxes_roc].set_title("ROC curve")
ax[iaxes_roc].set_xticks(np.arange(0,1.05,.1))
ax[iaxes_roc].set_xlabel("FPR")
ax[iaxes_roc].set_ylabel("Recall (TPR)")
ax[iaxes_pr].set_ylabel("Precision")
ax[iaxes_pr].set_xlabel("Recall (TPR)")
_ = ax[iaxes_roc].set_yticks(np.arange(0,1.05,.1))
plt.savefig("figures/pr_and_roc_curves.pdf")
No description has been provided for this image

Compute metrics stratified by type of location

There are two types of locs: 1. Locs that were used for training. 1. Locs that were not used for training.

model_ref = "MARS-S2L"
locs_train = set(config_experiments[model_ref]['all_locs_train'])
locs_film = set()
# if "id zero" in model_ref:
#     locs_film = set()
# else:
#     locs_film = set([k for k,v in config_experiments[model_ref]["film_dict_mapping"].items() if v > 0])

print(len(locs_train), len(locs_film))
outs_same_period_with_fluxrate["loc_type_train"] = outs_same_period_with_fluxrate.location_name.apply(lambda x: "FiLM" if x in locs_film else "some samples" if x in locs_train else "no samples")

aggs_sanity = outs_same_period_with_fluxrate.groupby("loc_type_train")["location_name"].agg(["nunique"])
aggs_sanity["nimages"] = outs_same_period_with_fluxrate.groupby("loc_type_train")["id_loc_image"].nunique()
# aggs_sanity["nplumes"] = outs_same_period_with_fluxrate.groupby("loc_type_train")["isplumenum"].sum()
aggs_sanity.rename(columns={"nunique":"nlocs"})
618 0

nlocs nimages
loc_type_train
no samples 697 15655
some samples 592 27869
# Sanity check
aggs_sanity = outs_same_period_with_fluxrate.groupby("loc_type_train")["location_name"].agg(["nunique"])
aggs_sanity["nimages"] = outs_same_period_with_fluxrate.groupby("loc_type_train")["id_loc_image"].nunique()
aggs_sanity["nplumes"] = outs_same_period_with_fluxrate[outs_same_period_with_fluxrate.model_name == model_ref].groupby("loc_type_train")["isplumenum"].sum()
aggs_sanity.rename(columns={"nunique":"nlocs"})
nlocs nimages nplumes
loc_type_train
no samples 697 15655 229
some samples 592 27869 1603
from itertools import product

mets = []
for (model, loc_type), dg in outs_same_period_with_fluxrate.groupby(["model_name","loc_type_train"]):
    threshold = threshold_marss2l if not model.startswith("MBMP") else threshold_mbmp
    mets_iter = get_scenelevel_metrics(dg.scenepredcontinuous, dg.isplumenum, as_percentage=True,threshold=threshold)
    mets_seg = get_pixellevel_metrics(TP=dg.TP, TN=dg.TN, FP=dg.FP, FN=dg.FN, as_percentage=True)
    mets_iter.update(mets_seg)
    mets_iter.update({"nsamples": dg.shape[0],
                 "nlocs": dg.location_name.nunique(),
                 "nplumes": dg.isplumenum.sum(),
                 "nnoplume": (1-dg.isplumenum).sum(),
                 "loc_type": loc_type,
                 "model_name": model})
    mets.append(mets_iter)


mets = pd.DataFrame(mets).sort_values(["loc_type","balanced_accuracy"], ascending=False)
overall_mets_strat_type_of_loc = mets[["model_name"]+[c for c in mets.columns if c != "model_name"]].copy()
models_show_by_type_of_loc = ["MBMP", "CH4Net", "MARS-S2L", "MARS-S2L (no sim)", "CH4Net (sim)"]
overall_mets_strat_type_of_loc.loc[overall_mets_strat_type_of_loc.model_name.isin(models_show_by_type_of_loc),
                                   ['loc_type'] + cols_metrics].set_index("loc_type")
model_name average_precision precision recall accuracy fpr
loc_type
some samples MARS-S2L 68.69 41.60 78.98 92.41 6.77
some samples MARS-S2L (no sim) 60.46 55.34 62.07 94.94 3.06
some samples CH4Net (sim) 38.88 23.86 52.65 87.61 10.26
some samples CH4Net 31.45 23.60 51.15 87.66 10.11
some samples MBMP 5.76 6.41 79.91 31.72 71.23
no samples MARS-S2L 44.85 13.20 77.29 92.23 7.55
no samples MARS-S2L (no sim) 27.02 16.88 46.29 95.88 3.38
no samples CH4Net (sim) 3.30 2.59 21.83 86.82 12.21
no samples MBMP 1.38 1.55 69.00 35.58 64.92
no samples CH4Net 2.19 2.00 14.85 88.12 10.79
print(overall_mets_strat_type_of_loc.loc[overall_mets_strat_type_of_loc.model_name.isin(models_show_by_type_of_loc),
                                   ['loc_type'] + cols_metrics].set_index("loc_type").to_latex(float_format="%.2f"))
\begin{tabular}{llrrrrr}
\toprule
 & model_name & average_precision & precision & recall & accuracy & fpr \\
loc_type &  &  &  &  &  &  \\
\midrule
some samples & MARS-S2L & 68.69 & 41.60 & 78.98 & 92.41 & 6.77 \\
some samples & MARS-S2L (no sim) & 60.46 & 55.34 & 62.07 & 94.94 & 3.06 \\
some samples & CH4Net (sim) & 38.88 & 23.86 & 52.65 & 87.61 & 10.26 \\
some samples & CH4Net & 31.45 & 23.60 & 51.15 & 87.66 & 10.11 \\
some samples & MBMP & 5.76 & 6.41 & 79.91 & 31.72 & 71.23 \\
no samples & MARS-S2L & 44.85 & 13.20 & 77.29 & 92.23 & 7.55 \\
no samples & MARS-S2L (no sim) & 27.02 & 16.88 & 46.29 & 95.88 & 3.38 \\
no samples & CH4Net (sim) & 3.30 & 2.59 & 21.83 & 86.82 & 12.21 \\
no samples & MBMP & 1.38 & 1.55 & 69.00 & 35.58 & 64.92 \\
no samples & CH4Net & 2.19 & 2.00 & 14.85 & 88.12 & 10.79 \\
\bottomrule
\end{tabular}


# locs_type = ["few samples", "no samples", "FiLM"]
locs_type = ["some samples", "no samples"]
fig, ax = plt.subplots(1, len(locs_type),figsize=(len(locs_type) * 5, 5))


colors = [C0, C2, C2, C1, C1]

models_show = ["MBMP", "CH4Net", "MARS-S2L"]
for i, loc_type_show in enumerate(locs_type):
    outs_same_period_with_fluxrate_loc = outs_same_period_with_fluxrate[outs_same_period_with_fluxrate.loc_type_train == loc_type_show]
    for _i_prev, (model_name, out_same_period) in enumerate(outs_same_period_with_fluxrate_loc.groupby("model_name")):
        if model_name not in models_show:
            continue

        display = PrecisionRecallDisplay.from_predictions(out_same_period.isplumenum, out_same_period.scenepredcontinuous,
                                                          plot_chance_level=_i_prev == 0,c=colors[_i_prev],
                                                          ax=ax[i], name=model_name)


    ax[i].set_title(f"Loc type: {loc_type_show}")
    ax[i].set_xticks(np.arange(0,1.05,.1))
    ax[i].set_yticks(np.arange(0,1.05,.1))
    ax[i].legend(loc="upper right")
    ax[i].grid()
No description has been provided for this image

Metrics plumes by flux rate

# Sanity check interval of plumes
outs_same_period_with_fluxrate.groupby(["isplume","interval_ch4_fluxrate_str"])[["id_loc_image"]].nunique()
/tmp/ipykernel_122349/151046986.py:2: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.
  outs_same_period_with_fluxrate.groupby(["isplume","interval_ch4_fluxrate_str"])[["id_loc_image"]].nunique()

id_loc_image
isplume interval_ch4_fluxrate_str
False [0, 0] 41692
(0, 0.5] 0
(0.5, 1] 0
(1, 1.5] 0
(1.5, 2] 0
(2, 2.5] 0
(2.5, 3] 0
(3, 4] 0
(4, 5] 0
(5, 6] 0
(6, 7] 0
(7, 8] 0
(8, 9] 0
(9, 10] 0
(10, 15] 0
(15, 20] 0
>20 0
True [0, 0] 0
(0, 0.5] 12
(0.5, 1] 82
(1, 1.5] 152
(1.5, 2] 149
(2, 2.5] 177
(2.5, 3] 159
(3, 4] 226
(4, 5] 162
(5, 6] 112
(6, 7] 92
(7, 8] 80
(8, 9] 53
(9, 10] 53
(10, 15] 148
(15, 20] 95
>20 80

Fig prob vs emission rate

from marss2l import plot
# from importlib import reload
# reload(plot)

model_names_plot = ["CH4Net", "MARS-S2L"] # "CH4Net",
df_plot = outs_same_period_with_fluxrate.loc[outs_same_period_with_fluxrate.model_name.isin(model_names_plot)]
fig, ax = plot.plot_prob_vs_emission_rate(df_plot)
No description has been provided for this image
from marss2l import plot
from marss2l.plot import prob_vs_emission_rate
from importlib import reload
# reload(plot)
reload(prob_vs_emission_rate)

model_names_plot = ["MARS-S2L"] # "CH4Net",
df_plot = outs_same_period_with_fluxrate.loc[outs_same_period_with_fluxrate.model_name.isin(model_names_plot)]
fig, ax = prob_vs_emission_rate.plot_prob_vs_emission_rate(df_plot, figsize=(9,4))
No description has been provided for this image

Recall vs Fluxrate

from marss2l.plot import recall_fluxrate_plot
from marss2l.plot import plot_recall_fpr_fluxrate

import numpy as np

from importlib import reload

reload(recall_fluxrate_plot)
models_plot_recall = ["MBMP", "CH4Net", "MARS-S2L"]

plt.figure(figsize=(10,3), layout="constrained")
fig, axs = recall_fluxrate_plot.plot_recall_fpr_fluxrate(outs_same_period_with_fluxrate, order_models=models_plot_recall,
                                                        loc_legend="center right", add_legend=False)

axs[1].set_title("Global results")
axs[0].set_yticks(np.arange(0,.55,.10))
# axs[1].set_yticks(np.arange(.5,.95,.1).tolist() + np.arange(.95,1.04,.05).tolist())

plt.savefig("figures/fig2_overall.pdf")
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(

<Figure size 1000x300 with 0 Axes>
No description has been provided for this image

Non-cummulative

plt.figure(figsize=(10,3), layout="constrained")
fig, axs = recall_fluxrate_plot.plot_recall_fpr_fluxrate(outs_same_period_with_fluxrate, order_models=models_plot_recall,
                                                        loc_legend="center right", add_legend=False,
                                                         cummulative=False)

axs[1].set_title("Global results")
axs[0].set_yticks(np.arange(0,.55,.10))
# axs[1].set_yticks(np.arange(.5,.95,.1).tolist() + np.arange(.95,1.04,.05).tolist())

plt.savefig("figures/fig2_overall_noncum.pdf")
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(

<Figure size 1000x300 with 0 Axes>
No description has been provided for this image

Results in case studies

pd.options.display.max_rows = 200
mets = []
for (model, case_study), dg in outs_same_period_with_fluxrate.groupby(["model_name","case_study"]): 
    # if case_study not in countries:
    #     continue

    # if "(id zero)" in model:
    #     continue

    n_locs_few_samples = dg[dg.loc_type_train == "some samples"].location_name.nunique()
    n_locs_no_samples = dg[dg.loc_type_train == "no samples"].location_name.nunique()
    # n_locs_film = dg[dg.loc_type == "FiLM"].location_name.nunique()
    threshold = threshold_marss2l if not model.startswith("MBMP") else threshold_mbmp
    mets_iter = get_scenelevel_metrics(dg.scenepredcontinuous, dg.isplumenum, as_percentage=True,threshold=threshold)

    mets_seg = get_pixellevel_metrics(TP=dg.TP, TN=dg.TN, FP=dg.FP, FN=dg.FN, as_percentage=True)
    mets_iter.update(mets_seg)

    mets_iter.update({
        "case_study": case_study,
        "model_name": model,
        "nimages": dg.shape[0],
        "nlocs": dg.location_name.nunique(),
        "nplumes": dg.isplumenum.sum(),
        "nlocs samples train": n_locs_few_samples,
        "nlocs no samples at train time": n_locs_no_samples,
        # "nlocs FiLM": n_locs_film,
        "nnoplume": (1-dg.isplumenum).sum()})
    mets.append(mets_iter)

mets = pd.DataFrame(mets).sort_values(["case_study","model_name"])
mets_case_studies = mets[['case_study', 'model_name', 'precision', 'recall', 'fpr',"balanced_accuracy",
       'average_precision', 'nimages','nplumes', # 'nlocs FiLM'
       'nnoplume', 'nlocs',
       'nlocs samples train', 'nlocs no samples at train time']].sort_values(["nimages","balanced_accuracy"], ascending=False).copy()

mets_case_studies
/home/gonzalo/mambaforge/envs/marss2ltacopy312/lib/python3.12/site-packages/sklearn/metrics/_classification.py:1565: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 due to no predicted samples. Use `zero_division` parameter to control this behavior.
  _warn_prf(average, modifier, f"{metric.capitalize()} is", len(result))
/home/gonzalo/git/marss2l/marss2l/metrics.py:94: RuntimeWarning: invalid value encountered in scalar divide
  f1 = 2 * precision * recall / (precision + recall)
/home/gonzalo/git/marss2l/marss2l/metrics.py:94: RuntimeWarning: invalid value encountered in scalar divide
  f1 = 2 * precision * recall / (precision + recall)
/home/gonzalo/git/marss2l/marss2l/metrics.py:94: RuntimeWarning: invalid value encountered in scalar divide
  f1 = 2 * precision * recall / (precision + recall)
/home/gonzalo/git/marss2l/marss2l/metrics.py:94: RuntimeWarning: invalid value encountered in scalar divide
  f1 = 2 * precision * recall / (precision + recall)
/home/gonzalo/git/marss2l/marss2l/metrics.py:94: RuntimeWarning: invalid value encountered in scalar divide
  f1 = 2 * precision * recall / (precision + recall)
/home/gonzalo/git/marss2l/marss2l/metrics.py:94: RuntimeWarning: invalid value encountered in scalar divide
  f1 = 2 * precision * recall / (precision + recall)
/home/gonzalo/git/marss2l/marss2l/metrics.py:94: RuntimeWarning: invalid value encountered in scalar divide
  f1 = 2 * precision * recall / (precision + recall)

case_study model_name precision recall fpr balanced_accuracy average_precision nimages nplumes nnoplume nlocs nlocs samples train nlocs no samples at train time
35 Turkmenistan MARS-S2L 49.60 80.75 8.14 86.31 75.41 9438 852 8586 130 115 15
48 Turkmenistan MARS-S2L (no sim) 63.31 67.84 3.90 81.97 70.47 9438 852 8586 130 115 15
22 Turkmenistan CH4Net (sim) 28.13 64.08 16.25 73.92 50.87 9438 852 8586 130 115 15
9 Turkmenistan CH4Net 26.15 63.50 17.80 72.85 40.79 9438 852 8586 130 115 15
61 Turkmenistan MBMP 11.54 81.92 62.30 59.81 10.68 9438 852 8586 130 115 15
36 United States of America MARS-S2L 26.97 86.01 4.22 90.90 75.13 8043 143 7900 305 229 76
49 United States of America MARS-S2L (no sim) 48.67 51.05 0.97 75.04 48.99 8043 143 7900 305 229 76
62 United States of America MBMP 2.07 100.00 85.70 57.15 2.11 8043 143 7900 305 229 76
23 United States of America CH4Net (sim) 8.55 13.99 2.71 55.64 9.59 8043 143 7900 305 229 76
10 United States of America CH4Net 6.67 8.39 2.13 53.13 3.55 8043 143 7900 305 229 76
31 Libya MARS-S2L 12.86 66.93 9.08 78.93 30.85 6473 127 6346 282 26 256
44 Libya MARS-S2L (no sim) 16.08 53.54 5.59 73.97 22.95 6473 127 6346 282 26 256
18 Libya CH4Net (sim) 5.49 46.46 16.01 65.22 11.93 6473 127 6346 282 26 256
57 Libya MBMP 3.14 79.53 49.10 65.21 4.36 6473 127 6346 282 26 256
5 Libya CH4Net 3.52 20.47 11.24 54.62 3.62 6473 127 6346 282 26 256
26 Algeria MARS-S2L 49.79 78.33 6.00 86.17 72.93 4251 300 3951 75 53 22
39 Algeria MARS-S2L (no sim) 52.79 63.00 4.28 79.36 62.47 4251 300 3951 75 53 22
0 Algeria CH4Net 21.67 56.33 15.46 70.43 28.82 4251 300 3951 75 53 22
13 Algeria CH4Net (sim) 18.49 47.33 15.84 65.74 29.49 4251 300 3951 75 53 22
52 Algeria MBMP 9.59 71.33 51.05 60.14 8.63 4251 300 3951 75 53 22
27 Arabian peninsula MARS-S2L 26.54 75.44 6.93 84.25 54.26 3547 114 3433 89 31 58
40 Arabian peninsula MARS-S2L (no sim) 34.51 42.98 2.71 70.14 32.20 3547 114 3433 89 31 58
14 Arabian peninsula CH4Net (sim) 15.81 45.61 8.07 68.77 17.43 3547 114 3433 89 31 58
1 Arabian peninsula CH4Net 8.54 39.47 14.04 62.72 8.46 3547 114 3433 89 31 58
53 Arabian peninsula MBMP 2.94 60.53 66.36 47.09 2.71 3547 114 3433 89 31 58
37 Uzbekistan & Kazakhstan MARS-S2L 14.04 74.42 7.87 83.28 36.94 2535 43 2492 75 28 47
50 Uzbekistan & Kazakhstan MARS-S2L (no sim) 27.69 41.86 1.89 69.99 24.10 2535 43 2492 75 28 47
24 Uzbekistan & Kazakhstan CH4Net (sim) 1.67 11.63 11.80 49.92 2.29 2535 43 2492 75 28 47
11 Uzbekistan & Kazakhstan CH4Net 0.82 4.65 9.67 47.49 2.62 2535 43 2492 75 28 47
63 Uzbekistan & Kazakhstan MBMP 1.31 58.14 75.64 41.25 1.09 2535 43 2492 75 28 47
29 Iran (Islamic Republic of) MARS-S2L 26.83 78.57 6.47 86.05 64.56 2388 70 2318 95 7 88
42 Iran (Islamic Republic of) MARS-S2L (no sim) 52.17 51.43 1.42 75.00 59.36 2388 70 2318 95 7 88
16 Iran (Islamic Republic of) CH4Net (sim) 8.28 17.14 5.74 55.70 7.93 2388 70 2318 95 7 88
55 Iran (Islamic Republic of) MBMP 3.22 97.14 88.18 54.48 2.78 2388 70 2318 95 7 88
3 Iran (Islamic Republic of) CH4Net 4.63 14.29 8.89 52.70 5.01 2388 70 2318 95 7 88
6 Offshore CH4Net 21.05 92.31 6.18 93.06 59.04 2224 39 2185 56 29 27
19 Offshore CH4Net (sim) 18.28 87.18 6.96 90.11 62.53 2224 39 2185 56 29 27
32 Offshore MARS-S2L 17.80 87.18 7.19 90.00 52.83 2224 39 2185 56 29 27
45 Offshore MARS-S2L (no sim) 22.45 84.62 5.22 89.70 52.76 2224 39 2185 56 29 27
58 Offshore MBMP 1.76 100.00 99.82 50.09 4.79 2224 39 2185 56 29 27
33 Rest MARS-S2L 4.59 62.50 5.71 78.40 51.79 1830 8 1822 84 27 57
46 Rest MARS-S2L (no sim) 7.14 25.00 1.43 61.79 18.10 1830 8 1822 84 27 57
59 Rest MBMP 0.49 87.50 77.99 54.75 0.95 1830 8 1822 84 27 57
7 Rest CH4Net 0.98 12.50 5.54 53.48 0.61 1830 8 1822 84 27 57
20 Rest CH4Net (sim) 0.00 0.00 5.60 47.20 0.66 1830 8 1822 84 27 57
28 Egypt MARS-S2L 11.69 75.00 8.25 83.37 33.99 1672 24 1648 47 15 32
41 Egypt MARS-S2L (no sim) 20.27 62.50 3.58 79.46 21.60 1672 24 1648 47 15 32
15 Egypt CH4Net (sim) 5.19 62.50 16.63 72.94 6.02 1672 24 1648 47 15 32
2 Egypt CH4Net 1.82 4.17 3.28 50.44 1.95 1672 24 1648 47 15 32
54 Egypt MBMP 0.98 37.50 55.16 41.17 1.14 1672 24 1648 47 15 32
34 Syrian Arab Republic MARS-S2L 51.06 72.73 15.30 78.71 65.16 550 99 451 11 2 9
47 Syrian Arab Republic MARS-S2L (no sim) 73.47 36.36 2.88 66.74 53.70 550 99 451 11 2 9
8 Syrian Arab Republic CH4Net 24.44 11.11 7.54 51.79 17.72 550 99 451 11 2 9
21 Syrian Arab Republic CH4Net (sim) 13.24 9.09 13.08 48.00 16.76 550 99 451 11 2 9
60 Syrian Arab Republic MBMP 15.47 54.55 65.41 44.57 14.19 550 99 451 11 2 9
30 Iraq MARS-S2L 12.50 71.43 7.68 81.88 54.47 463 7 456 32 29 3
43 Iraq MARS-S2L (no sim) 50.00 42.86 0.66 71.10 47.98 463 7 456 32 29 3
56 Iraq MBMP 1.67 85.71 77.41 54.15 1.40 463 7 456 32 29 3
17 Iraq CH4Net (sim) 0.00 0.00 7.02 46.49 2.22 463 7 456 32 29 3
4 Iraq CH4Net 0.00 0.00 10.31 44.85 2.94 463 7 456 32 29 3
38 Venezuela MARS-S2L 31.25 83.33 10.58 86.38 84.90 110 6 104 8 1 7
51 Venezuela MARS-S2L (no sim) 50.00 16.67 0.96 57.85 27.06 110 6 104 8 1 7
12 Venezuela CH4Net 0.00 0.00 0.00 50.00 21.00 110 6 104 8 1 7
64 Venezuela MBMP 5.45 100.00 100.00 50.00 9.17 110 6 104 8 1 7
25 Venezuela CH4Net (sim) 0.00 0.00 3.85 48.08 12.72 110 6 104 8 1 7
print(mets_case_studies.loc[mets_case_studies.model_name != "MARS-S2L (first submission)",
      ['case_study','model_name', 'average_precision', 'precision', 'recall', "fpr"]].to_latex(index=False,float_format="%.2f"))
\begin{tabular}{llrrrr}
\toprule
case_study & model_name & average_precision & precision & recall & fpr \\
\midrule
Turkmenistan & MARS-S2L & 75.41 & 49.60 & 80.75 & 8.14 \\
Turkmenistan & MARS-S2L (no sim) & 70.47 & 63.31 & 67.84 & 3.90 \\
Turkmenistan & CH4Net (sim) & 50.87 & 28.13 & 64.08 & 16.25 \\
Turkmenistan & CH4Net & 40.79 & 26.15 & 63.50 & 17.80 \\
Turkmenistan & MBMP & 10.68 & 11.54 & 81.92 & 62.30 \\
United States of America & MARS-S2L & 75.13 & 26.97 & 86.01 & 4.22 \\
United States of America & MARS-S2L (no sim) & 48.99 & 48.67 & 51.05 & 0.97 \\
United States of America & MBMP & 2.11 & 2.07 & 100.00 & 85.70 \\
United States of America & CH4Net (sim) & 9.59 & 8.55 & 13.99 & 2.71 \\
United States of America & CH4Net & 3.55 & 6.67 & 8.39 & 2.13 \\
Libya & MARS-S2L & 30.85 & 12.86 & 66.93 & 9.08 \\
Libya & MARS-S2L (no sim) & 22.95 & 16.08 & 53.54 & 5.59 \\
Libya & CH4Net (sim) & 11.93 & 5.49 & 46.46 & 16.01 \\
Libya & MBMP & 4.36 & 3.14 & 79.53 & 49.10 \\
Libya & CH4Net & 3.62 & 3.52 & 20.47 & 11.24 \\
Algeria & MARS-S2L & 72.93 & 49.79 & 78.33 & 6.00 \\
Algeria & MARS-S2L (no sim) & 62.47 & 52.79 & 63.00 & 4.28 \\
Algeria & CH4Net & 28.82 & 21.67 & 56.33 & 15.46 \\
Algeria & CH4Net (sim) & 29.49 & 18.49 & 47.33 & 15.84 \\
Algeria & MBMP & 8.63 & 9.59 & 71.33 & 51.05 \\
Arabian peninsula & MARS-S2L & 54.26 & 26.54 & 75.44 & 6.93 \\
Arabian peninsula & MARS-S2L (no sim) & 32.20 & 34.51 & 42.98 & 2.71 \\
Arabian peninsula & CH4Net (sim) & 17.43 & 15.81 & 45.61 & 8.07 \\
Arabian peninsula & CH4Net & 8.46 & 8.54 & 39.47 & 14.04 \\
Arabian peninsula & MBMP & 2.71 & 2.94 & 60.53 & 66.36 \\
Uzbekistan & Kazakhstan & MARS-S2L & 36.94 & 14.04 & 74.42 & 7.87 \\
Uzbekistan & Kazakhstan & MARS-S2L (no sim) & 24.10 & 27.69 & 41.86 & 1.89 \\
Uzbekistan & Kazakhstan & CH4Net (sim) & 2.29 & 1.67 & 11.63 & 11.80 \\
Uzbekistan & Kazakhstan & CH4Net & 2.62 & 0.82 & 4.65 & 9.67 \\
Uzbekistan & Kazakhstan & MBMP & 1.09 & 1.31 & 58.14 & 75.64 \\
Iran (Islamic Republic of) & MARS-S2L & 64.56 & 26.83 & 78.57 & 6.47 \\
Iran (Islamic Republic of) & MARS-S2L (no sim) & 59.36 & 52.17 & 51.43 & 1.42 \\
Iran (Islamic Republic of) & CH4Net (sim) & 7.93 & 8.28 & 17.14 & 5.74 \\
Iran (Islamic Republic of) & MBMP & 2.78 & 3.22 & 97.14 & 88.18 \\
Iran (Islamic Republic of) & CH4Net & 5.01 & 4.63 & 14.29 & 8.89 \\
Offshore & CH4Net & 59.04 & 21.05 & 92.31 & 6.18 \\
Offshore & CH4Net (sim) & 62.53 & 18.28 & 87.18 & 6.96 \\
Offshore & MARS-S2L & 52.83 & 17.80 & 87.18 & 7.19 \\
Offshore & MARS-S2L (no sim) & 52.76 & 22.45 & 84.62 & 5.22 \\
Offshore & MBMP & 4.79 & 1.76 & 100.00 & 99.82 \\
Rest & MARS-S2L & 51.79 & 4.59 & 62.50 & 5.71 \\
Rest & MARS-S2L (no sim) & 18.10 & 7.14 & 25.00 & 1.43 \\
Rest & MBMP & 0.95 & 0.49 & 87.50 & 77.99 \\
Rest & CH4Net & 0.61 & 0.98 & 12.50 & 5.54 \\
Rest & CH4Net (sim) & 0.66 & 0.00 & 0.00 & 5.60 \\
Egypt & MARS-S2L & 33.99 & 11.69 & 75.00 & 8.25 \\
Egypt & MARS-S2L (no sim) & 21.60 & 20.27 & 62.50 & 3.58 \\
Egypt & CH4Net (sim) & 6.02 & 5.19 & 62.50 & 16.63 \\
Egypt & CH4Net & 1.95 & 1.82 & 4.17 & 3.28 \\
Egypt & MBMP & 1.14 & 0.98 & 37.50 & 55.16 \\
Syrian Arab Republic & MARS-S2L & 65.16 & 51.06 & 72.73 & 15.30 \\
Syrian Arab Republic & MARS-S2L (no sim) & 53.70 & 73.47 & 36.36 & 2.88 \\
Syrian Arab Republic & CH4Net & 17.72 & 24.44 & 11.11 & 7.54 \\
Syrian Arab Republic & CH4Net (sim) & 16.76 & 13.24 & 9.09 & 13.08 \\
Syrian Arab Republic & MBMP & 14.19 & 15.47 & 54.55 & 65.41 \\
Iraq & MARS-S2L & 54.47 & 12.50 & 71.43 & 7.68 \\
Iraq & MARS-S2L (no sim) & 47.98 & 50.00 & 42.86 & 0.66 \\
Iraq & MBMP & 1.40 & 1.67 & 85.71 & 77.41 \\
Iraq & CH4Net (sim) & 2.22 & 0.00 & 0.00 & 7.02 \\
Iraq & CH4Net & 2.94 & 0.00 & 0.00 & 10.31 \\
Venezuela & MARS-S2L & 84.90 & 31.25 & 83.33 & 10.58 \\
Venezuela & MARS-S2L (no sim) & 27.06 & 50.00 & 16.67 & 0.96 \\
Venezuela & CH4Net & 21.00 & 0.00 & 0.00 & 0.00 \\
Venezuela & MBMP & 9.17 & 5.45 & 100.00 & 100.00 \\
Venezuela & CH4Net (sim) & 12.72 & 0.00 & 0.00 & 3.85 \\
\bottomrule
\end{tabular}


Fig 2. Results by case study

import matplotlib.gridspec as gridspec

case_studies = loaders.ORDER_CASE_STUDIES[:-1]
fig = plt.figure(figsize=(14, 2 * 6), layout="constrained")  # Wider figure to accommodate 4 columns
gs = gridspec.GridSpec(6, 4, width_ratios=[1, 5, 1, 5], figure=fig)

# models_plot_recall = ["MBMP", "CH4Net", "MARS-S2L"]
model_names_plot = models_plot_recall


# Initialize arrays to track shared axes for each column
ax1_col1, ax_col1 = None, None  # For left side (columns 0-1)
ax1_col2, ax_col2 = None, None  # For right side (columns 2-3)

for i, case_study in enumerate(case_studies[::2] + case_studies[1::2]):
    # Calculate position in the grid
    row = i % 6  # Rows 0-5
    col_offset = (i // 6) * 2  # 0 for first 6 case studies, 2 for next 6

    # Get the appropriate shared axes based on which side we're plotting
    if col_offset == 0:  # Left side
        ax1 = fig.add_subplot(gs[row, col_offset], sharex=ax1_col1)
        ax = fig.add_subplot(gs[row, col_offset + 1], sharex=ax_col1)
        # Update shared axes references for left side
        if ax1_col1 is None:
            ax1_col1, ax_col1 = ax1, ax
    else:  # Right side
        ax1 = fig.add_subplot(gs[row, col_offset], sharex=ax1_col2)
        ax = fig.add_subplot(gs[row, col_offset + 1], sharex=ax_col2)
        # Update shared axes references for right side
        if ax1_col2 is None:
            ax1_col2, ax_col2 = ax1, ax

    # Plot the data
    df_plot = outs_same_period_with_fluxrate[outs_same_period_with_fluxrate.case_study == case_study]
    loc_legend = "center left" if i == 0 else "upper left"
    fig, axs = recall_fluxrate_plot.plot_recall_fpr_fluxrate(
        df_plot, 
        order_models=model_names_plot,
        loc_legend=loc_legend,
        yticks_recall=np.arange(0,1.1, 0.2),
        add_legend=(i == 0) or (i == 6),  # Only add legend for the first two plots
        fig=fig, 
        axs=(ax1, ax)
    )
    ax1.set_ylim(0,1)
    axs[1].set_title(case_study)

    if i != 5 and i != 11:
        axs[0].xaxis.set_visible(False)
        axs[1].xaxis.set_visible(False)

plt.savefig("figures/fig2_case_studies_new.pdf")
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(

No description has been provided for this image

Non-cummulative

import matplotlib.gridspec as gridspec

case_studies = loaders.ORDER_CASE_STUDIES[:-1]
fig = plt.figure(figsize=(14, 2 * 6), layout="constrained")  # Wider figure to accommodate 4 columns
gs = gridspec.GridSpec(6, 4, width_ratios=[1, 5, 1, 5], figure=fig)

# models_plot_recall = ["MBMP", "CH4Net", "MARS-S2L"]
model_names_plot = models_plot_recall


# Initialize arrays to track shared axes for each column
ax1_col1, ax_col1 = None, None  # For left side (columns 0-1)
ax1_col2, ax_col2 = None, None  # For right side (columns 2-3)

for i, case_study in enumerate(case_studies[::2] + case_studies[1::2]):
    # Calculate position in the grid
    row = i % 6  # Rows 0-5
    col_offset = (i // 6) * 2  # 0 for first 6 case studies, 2 for next 6

    # Get the appropriate shared axes based on which side we're plotting
    if col_offset == 0:  # Left side
        ax1 = fig.add_subplot(gs[row, col_offset], sharex=ax1_col1)
        ax = fig.add_subplot(gs[row, col_offset + 1], sharex=ax_col1)
        # Update shared axes references for left side
        if ax1_col1 is None:
            ax1_col1, ax_col1 = ax1, ax
    else:  # Right side
        ax1 = fig.add_subplot(gs[row, col_offset], sharex=ax1_col2)
        ax = fig.add_subplot(gs[row, col_offset + 1], sharex=ax_col2)
        # Update shared axes references for right side
        if ax1_col2 is None:
            ax1_col2, ax_col2 = ax1, ax

    # Plot the data
    df_plot = outs_same_period_with_fluxrate[outs_same_period_with_fluxrate.case_study == case_study]
    loc_legend = "center left" if i == 0 else "upper left"
    fig, axs = recall_fluxrate_plot.plot_recall_fpr_fluxrate(
        df_plot, 
        order_models=model_names_plot,
        loc_legend=loc_legend,
        yticks_recall=np.arange(0,1.1, 0.2),
        cummulative=False,
        add_legend=(i == 0) or (i == 6),  # Only add legend for the first two plots
        fig=fig, 
        axs=(ax1, ax)
    )
    ax1.set_ylim(0,1)
    axs[1].set_title(case_study)

    if i != 5 and i != 11:
        axs[0].xaxis.set_visible(False)
        axs[1].xaxis.set_visible(False)

plt.savefig("figures/fig2_case_studies_new_noncummulative.pdf")
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(
/home/gonzalo/git/marss2l/marss2l/plot/recall_fluxrate_plot.py:240: UserWarning: The palette list has more values (4) than needed (3), which may not be intended.
  sns.lineplot(

No description has been provided for this image

Prob. vs fluxrate case studies

model_names_plot = ["MARS-S2L", "CH4Net"] # "CH4Net",
for case_study, dg in outs_same_period_with_fluxrate.groupby("case_study"): 
    df_plot = dg.loc[dg.model_name.isin(model_names_plot)]
    fig, ax = plot.plot_prob_vs_emission_rate(df_plot)
    ax[1].set_title(case_study)
    plt.show(fig)
    plt.close(fig)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Histograms predicted probability in the case studies

from marss2l import plot
from importlib import reload

reload(plot)


model = "MARS-S2L"
outs_same_period_with_fluxrate["target"] = outs_same_period_with_fluxrate["isplumenum"]

for case_study, dg in outs_same_period_with_fluxrate.groupby("case_study"):  
    if case_study  == "None":
        continue

    fig, axs = plt.subplots(2,1, figsize=(6,8), sharex=True, sharey='row')
    dg = outs_same_period_with_fluxrate[(outs_same_period_with_fluxrate.model_name == model) &amp; (outs_same_period_with_fluxrate.case_study == case_study)]
    plot.plot_row(dg, model_name="MARS-S2L", axs=axs)
    plt.suptitle(case_study)
    plt.show()
    plt.close(fig)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image