VSO API Client Tutorial#
NB: to launch this notebook with all the necessary dependencies, you may use this one-liner based on uv:
uvx --with vso-api-client[tutorials] --index vso-api-client=https://git.icare.univ-lille.fr/api/v4/groups/178/-/packages/pypi/simple jupyter lab vso_api_client_tutorial.ipynb
Imports needed to run the notebook#
[27]:
import ast
import time
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.colors as colors
import matplotlib.pyplot as plt
import pandas as pd
import rioxarray
from matplotlib import colormaps
from matplotlib.dates import DateFormatter
from vso_api_client import Client
from vso_api_client.exceptions import APIError, NotFoundError
Instantiate client#
[28]:
client = Client()
List available workflows#
[29]:
workflows = client.get_workflows()
workflows
[29]:
{'workflows': [{'name': 'sentinel1-insar',
'description': 'Compute interferograms based on dynamically fetched Sentinel‑1 inSAR products'},
{'name': 'geo-time-series',
'description': 'Compute time series of various quantities based on geostationary satellite data within circular areas around a given volcano'},
{'name': 'leo-time-series',
'description': 'Compute time series of various quantities based on low Earth orbit satellite data within circular areas around a given volcano'},
{'name': 'flux-time-series',
'description': 'Estimate SO2 flux around a given volcano based on the disk method'}],
'total': 4}
Get a workflow example#
[4]:
examples = client.get_workflow_examples("leo-time-series")
examples
[4]:
{'workflow': 'leo-time-series',
'examples': {'piton-de-la-fournaise': {'summary': 'SO2 mass time series around Piton de la Fournaise',
'description': 'Compute SO2 mass time series from TROPOMI data around Piton de la Fournaise',
'parameters': {'variable': 'TROPOMI_SO2-7km_mass',
'radii': [25, 50, 75, 100, 200, 250, 300, 500],
'volcano': 'Fournaise, Piton de la',
'start_date': '2023-07-01',
'end_date': '2023-07-10',
'input_data_filters': {'du': 0, 'sza': 90, 'tracks': 7},
'include': ['cloud_fraction_mean']}}}}
Submit a job#
[5]:
parameters = {
"variable": "TROPOMI_SO2-7km_mass",
"radii": [100, 200, 300, 400, 500],
"volcano": "Etna",
"start_date": "2025-06-12",
"end_date": "2025-07-01",
"input_data_filters": {"du": 0.5, "sza": 70, "tracks": 22},
"include": ["gridded_data", "cloud_fraction_mean"],
}
[6]:
# Submit the job
job_details = client.submit_job(workflow="leo-time-series", job_parameters=parameters)
# At this point, a browser page will open to log in with Data Terra credentials
job_details
A browser page will open for you to log in (if not, navigate to https://sso.earth-data.fr/realms/gaia-data/device?user_code=NJYW-SMAL), then press any key here
[6]:
{'message': 'Job submitted successfully',
'job_id': 'eb5a29dc-c4a3-41d1-b813-ff29742a6f7d',
'urls': {'info': 'https://ap.icare.univ-lille.fr/vso/v1/jobs/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d',
'status': 'https://ap.icare.univ-lille.fr/vso/v1/jobs/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d/status',
'ended': 'https://ap.icare.univ-lille.fr/vso/v1/jobs/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d/ended',
'progress': 'https://ap.icare.univ-lille.fr/vso/v1/jobs/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d/progress',
'logs': 'https://ap.icare.univ-lille.fr/vso/v1/jobs/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d/logs',
'result': 'https://ap.icare.univ-lille.fr/vso/v1/jobs/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d/result'}}
Monitoring job progress#
[7]:
job_id = job_details["job_id"]
client.get_job_status(job_id)
[7]:
{'job_id': 'eb5a29dc-c4a3-41d1-b813-ff29742a6f7d', 'status': 'COMPLETED'}
[8]:
# Wait for completion
while not client.get_has_job_ended(job_id)["has_ended"]:
time.sleep(2)
try:
progress = client.get_job_progress(job_id)["progress"]
except APIError as e:
if isinstance(e, NotFoundError) and e.message == "Progress artifact not found":
print("Job has not started yet")
continue
else:
raise e
print(f"Progress: {progress} %")
status = client.get_job_status(job_id)["status"]
if status != "COMPLETED":
raise Exception(
f"Job failed with status: {status}, you may contact us for support."
)
print("Job completed!")
Job completed!
Download results#
[9]:
# Download results as json dict
result = client.get_job_result(job_id)
result
[9]:
{'metadata': {'workflow_name': 'leo-time-series',
'workflow_version': '0.1.2',
'job_id': 'eb5a29dc-c4a3-41d1-b813-ff29742a6f7d',
'parameters': {'volcano': 'Etna',
'variable': 'TROPOMI_SO2-7km_mass',
'start_date': '2025-06-12',
'end_date': '2025-07-01',
'radii': [100, 200, 300, 400, 500],
'input_data_filters': {'du': 0.5, 'sza': 70.0, 'tracks': 22.0},
'include': ['gridded_data', 'cloud_fraction_mean']},
'created_at': '2026-05-28 07:59:24+00:00',
'filename': 'TROPOMI_SO2-7km_mass_100-200-300-400-500km_Etna_du-0.5_sza-70_tracks-22_2025-06-12_2025-07-01.json',
'input_files': {'TROPOMI_SO2-7km': 'https://www.icare.univ-lille.fr/cache/services/vso/prod/output/leo-time-series/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d/TROPOMI_SO2-7km_input_files.txt'},
'data_provider': {'TROPOMI': 'ESA-Copernicus'},
'licence': 'CC BY 4.0 - Volcano Space Observatory (Boichu et al., 2025; Boichu and Mathurin, 2022)',
'data_policy': 'https://vso.icare.univ-lille.fr/citation',
'units': {'TROPOMI_SO2-7km_mass': 'kton',
'radius': 'km',
'coverage': '%',
'fraction_filtered_sza': '%',
'fraction_filtered_tracks': '%'},
'gridding_resolution': 5},
'output_files': {'time_series': 'https://www.icare.univ-lille.fr/cache/services/vso/prod/output/leo-time-series/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d/TROPOMI_SO2-7km_mass_100-200-300-400-500km_Etna_du-0.5_sza-70_tracks-22_2025-06-12_2025-07-01.csv',
'gridded_data': 'https://www.icare.univ-lille.fr/cache/services/vso/prod/output/leo-time-series/eb5a29dc-c4a3-41d1-b813-ff29742a6f7d/TROPOMI_SO2-7km_gridded_data_100-200-300-400-500km_Etna_du-0.5_sza-70_tracks-22_2025-06-12_2025-07-01.tif'},
'series': {'time': ['2025-06-12 11:00:00',
'2025-06-12 11:00:00',
'2025-06-12 11:00:00',
'2025-06-12 11:00:00',
'2025-06-12 11:00:00',
'2025-06-13 12:00:00',
'2025-06-13 12:00:00',
'2025-06-13 12:00:00',
'2025-06-13 12:00:00',
'2025-06-13 12:00:00',
'2025-06-14 13:00:00',
'2025-06-14 13:00:00',
'2025-06-14 13:00:00',
'2025-06-14 13:00:00',
'2025-06-14 13:00:00',
'2025-06-15 12:00:00',
'2025-06-15 12:00:00',
'2025-06-15 12:00:00',
'2025-06-15 12:00:00',
'2025-06-15 12:00:00',
'2025-06-16 12:00:00',
'2025-06-16 12:00:00',
'2025-06-16 12:00:00',
'2025-06-16 12:00:00',
'2025-06-16 12:00:00',
'2025-06-17 12:00:00',
'2025-06-17 12:00:00',
'2025-06-17 12:00:00',
'2025-06-17 12:00:00',
'2025-06-17 12:00:00',
'2025-06-18 12:00:00',
'2025-06-18 12:00:00',
'2025-06-18 12:00:00',
'2025-06-18 12:00:00',
'2025-06-18 12:00:00',
'2025-06-19 13:00:00',
'2025-06-19 13:00:00',
'2025-06-19 13:00:00',
'2025-06-19 13:00:00',
'2025-06-19 13:00:00',
'2025-06-20 12:00:00',
'2025-06-20 12:00:00',
'2025-06-20 12:00:00',
'2025-06-20 12:00:00',
'2025-06-20 12:00:00',
'2025-06-21 12:00:00',
'2025-06-21 12:00:00',
'2025-06-21 12:00:00',
'2025-06-21 12:00:00',
'2025-06-21 12:00:00',
'2025-06-22 12:00:00',
'2025-06-22 12:00:00',
'2025-06-22 12:00:00',
'2025-06-22 12:00:00',
'2025-06-22 12:00:00',
'2025-06-23 12:00:00',
'2025-06-23 12:00:00',
'2025-06-23 12:00:00',
'2025-06-23 12:00:00',
'2025-06-23 12:00:00',
'2025-06-24 12:00:00',
'2025-06-24 12:00:00',
'2025-06-24 12:00:00',
'2025-06-24 12:00:00',
'2025-06-24 12:00:00',
'2025-06-25 12:00:00',
'2025-06-25 12:00:00',
'2025-06-25 12:00:00',
'2025-06-25 12:00:00',
'2025-06-25 12:00:00',
'2025-06-26 12:00:00',
'2025-06-26 12:00:00',
'2025-06-26 12:00:00',
'2025-06-26 12:00:00',
'2025-06-26 12:00:00',
'2025-06-27 12:00:00',
'2025-06-27 12:00:00',
'2025-06-27 12:00:00',
'2025-06-27 12:00:00',
'2025-06-27 12:00:00',
'2025-06-28 11:00:00',
'2025-06-28 11:00:00',
'2025-06-28 11:00:00',
'2025-06-28 11:00:00',
'2025-06-28 11:00:00',
'2025-06-29 12:00:00',
'2025-06-29 12:00:00',
'2025-06-29 12:00:00',
'2025-06-29 12:00:00',
'2025-06-29 12:00:00',
'2025-06-30 13:00:00',
'2025-06-30 13:00:00',
'2025-06-30 13:00:00',
'2025-06-30 13:00:00',
'2025-06-30 13:00:00',
'2025-07-01 12:00:00',
'2025-07-01 12:00:00',
'2025-07-01 12:00:00',
'2025-07-01 12:00:00',
'2025-07-01 12:00:00'],
'radius': [100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500,
100,
200,
300,
400,
500],
'npoints': [1364,
5407,
12028,
21057,
32247,
1508,
5941,
13131,
22779,
34545,
1019,
4102,
9274,
16531,
25845,
583,
2685,
6506,
11829,
19022,
675,
2941,
7161,
13115,
20919,
1181,
4724,
10587,
18739,
29026,
1543,
6101,
13455,
23280,
35232,
1214,
4826,
10810,
19095,
29487,
702,
2835,
6676,
12740,
20648,
774,
3112,
6737,
11981,
19137,
997,
3984,
9013,
16168,
25996,
1492,
5900,
13042,
22655,
34388,
1380,
5484,
12193,
21305,
32560,
850,
3443,
7800,
14061,
22920,
812,
3000,
6457,
11516,
18502,
824,
3303,
7651,
14397,
23442,
1354,
5391,
12010,
21022,
32201,
1504,
5953,
13156,
22799,
34583,
1027,
4114,
9292,
16573,
25909,
583,
2688,
6515,
11821,
19048],
'fraction_filtered_tracks': [0.0,
0.0,
0.0,
0.0,
0.8394833948339508,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.8217036035506404,
7.342343957265262,
54.13060582218725,
36.9570321671754,
28.355907939654223,
27.677916360968446,
26.13102403790144,
45.03257328990228,
32.91514598540146,
23.68112543962485,
21.235961804095847,
21.91197879726754,
0.0,
0.0,
0.0,
2.639372369719961,
6.473336555501852,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.5262625240360252,
15.625,
25.33579141427442,
23.9895252191734,
19.22906232168896,
19.189072834722708,
30.39568345323741,
29.846708746618578,
30.703558938490026,
30.338973196116047,
26.994239499484983,
0.0,
0.0,
6.436208865358662,
11.013264351367713,
10.52830838065737,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.520080901473563,
9.101503321291226,
13.762649494020241,
12.748867486390802,
15.85492227979275,
30.683918669131238,
35.352422907488986,
32.54451733833177,
28.38951890699385,
5.287356321839076,
17.671984047856427,
19.488582552878043,
15.983893557422968,
13.892153981780787,
0.0,
0.0,
0.0,
0.0,
0.9199999999999986,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.700639934245286,
7.18277566812352,
54.02208201892744,
36.94581280788177,
28.24099570437273,
27.56740196078431,
26.236300972001704],
'fraction_filtered_sza': [0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0],
'coverage': [100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
92.0,
90.0,
90.42553191489361,
91.0,
91.66666666666667,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
97.78270509977827,
92.18045112781955,
91.67330677290836,
91.16311561299337,
91.93548387096774,
94.89795918367346,
92.95302013422818,
92.43306169965075,
93.86446886446886,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
95.3757225433526,
94.52449567723343,
94.52054794520548,
94.25,
94.14634146341463,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
98.06451612903226,
94.44444444444444,
88.3495145631068,
89.1891891891892,
89.38053097345133,
90.3225806451613],
'cloud_fraction_mean': [0.17266637086868286,
0.07437733560800552,
0.04822738468647003,
0.04041746258735657,
0.047207560390233994,
0.09985102713108063,
0.09401979297399521,
0.08356557786464691,
0.07065242528915405,
0.06235109269618988,
0.0383387990295887,
0.02559114247560501,
0.031045159325003624,
0.03902815282344818,
0.04951892048120499,
0.018821250647306442,
0.03942038491368294,
0.04266053065657616,
0.04373113438487053,
0.044028811156749725,
0.1012926995754242,
0.09117795526981354,
0.09014545381069183,
0.09369444847106934,
0.11269015818834305,
0.19550365209579468,
0.10226650536060333,
0.08611337095499039,
0.08038163930177689,
0.10078805685043335,
0.6138103008270264,
0.36653316020965576,
0.3419477343559265,
0.30985456705093384,
0.2557402551174164,
0.8153957724571228,
0.4339483380317688,
0.2688583433628082,
0.19196449220180511,
0.15800994634628296,
0.4505171775817871,
0.3095053732395172,
0.21965624392032623,
0.16312694549560547,
0.12638933956623077,
0.24247479438781738,
0.1947426050901413,
0.15944311022758484,
0.1330019235610962,
0.12005847692489624,
0.18282796442508698,
0.0987851619720459,
0.06409192085266113,
0.051192980259656906,
0.06752359122037888,
0.14895378053188324,
0.08148082345724106,
0.05542321503162384,
0.05308318883180618,
0.05697648599743843,
0.1104346215724945,
0.12033657729625702,
0.08497162908315659,
0.06621146202087402,
0.05415506288409233,
0.005631296895444393,
0.009064263664186,
0.011569316498935223,
0.01800340972840786,
0.03018360026180744,
0.04041377082467079,
0.035649411380290985,
0.03776947781443596,
0.0352928601205349,
0.029831400141119957,
0.03148772194981575,
0.03879900649189949,
0.03917703032493591,
0.039563775062561035,
0.046521902084350586,
0.10134188830852509,
0.04748145863413811,
0.03305267542600632,
0.030896108597517014,
0.03569331020116806,
0.11565439403057098,
0.08390621095895767,
0.06639721989631653,
0.056825291365385056,
0.05278674140572548,
0.0032150347251445055,
0.013681309297680855,
0.02988635189831257,
0.0535719059407711,
0.058671735227108,
0.06978858262300491,
0.03258959576487541,
0.030244547873735428,
0.03499476984143257,
0.030787186697125435],
'TROPOMI_SO2-7km_mass': [0.04745118319988251,
0.07444483786821365,
0.07837684452533722,
0.07880085706710815,
0.08002392202615738,
0.049063704907894135,
0.06724493205547333,
0.0773736983537674,
0.07773708552122116,
0.07815714180469513,
0.033671699464321136,
0.07014012336730957,
0.07014012336730957,
0.07134100794792175,
0.07244043797254562,
0.02365034446120262,
0.03751270845532417,
0.043070483952760696,
0.04538554698228836,
0.04853912442922592,
0.0055871037766337395,
0.011149895377457142,
0.013075260445475578,
0.017281029373407364,
0.02018137089908123,
0.0025092854630202055,
0.008162792772054672,
0.008552138693630695,
0.00933272484689951,
0.010159683413803577,
0.00344424438662827,
0.00344424438662827,
0.004163655918091536,
0.004565652459859848,
0.005320769734680653,
0.8151025772094727,
2.3903279304504395,
2.436805248260498,
2.4383230209350586,
2.4390950202941895,
0.1030033528804779,
0.2795482277870178,
0.907241702079773,
1.795446753501892,
2.0205557346343994,
0.036777544766664505,
0.051263924688100815,
0.14481082558631897,
0.4409584701061249,
0.5603393912315369,
0.07450223714113235,
0.14870880544185638,
0.1722394824028015,
0.1816132813692093,
0.18556545674800873,
0.06207646057009697,
0.12156035006046295,
0.20227932929992676,
0.2311030924320221,
0.2318463921546936,
0.07118510454893112,
0.1345556080341339,
0.19391018152236938,
0.19518187642097473,
0.19726026058197021,
0.09461771696805954,
0.2600884437561035,
0.2642105221748352,
0.26459938287734985,
0.264957457780838,
0.10414273291826248,
0.21850630640983582,
0.22566653788089752,
0.2405015528202057,
0.24428404867649078,
0.06308102607727051,
0.2385682612657547,
0.32624366879463196,
0.32856279611587524,
0.32929450273513794,
0.022741271182894707,
0.07455367594957352,
0.08899535983800888,
0.09054327011108398,
0.09100085496902466,
0.04377753660082817,
0.0479392409324646,
0.05768890306353569,
0.0612758994102478,
0.06164806708693504,
0.031769879162311554,
0.05032692104578018,
0.05640489608049393,
0.059963811188936234,
0.07487061619758606,
0.02539219707250595,
0.10618607699871063,
0.1133849024772644,
0.11497096717357635,
0.12374713271856308]}}
Display time-series#
[10]:
# Parse results into a DataFrame for easier analysis
df = pd.DataFrame(result["series"])
df["time"] = pd.to_datetime(df["time"], utc=True)
df = df.set_index(["time", "radius"]).sort_index()
df
[10]:
| npoints | fraction_filtered_tracks | fraction_filtered_sza | coverage | cloud_fraction_mean | TROPOMI_SO2-7km_mass | ||
|---|---|---|---|---|---|---|---|
| time | radius | ||||||
| 2025-06-12 11:00:00+00:00 | 100 | 1364 | 0.000000 | 0.0 | 100.000000 | 0.172666 | 0.047451 |
| 200 | 5407 | 0.000000 | 0.0 | 100.000000 | 0.074377 | 0.074445 | |
| 300 | 12028 | 0.000000 | 0.0 | 100.000000 | 0.048227 | 0.078377 | |
| 400 | 21057 | 0.000000 | 0.0 | 100.000000 | 0.040417 | 0.078801 | |
| 500 | 32247 | 0.839483 | 0.0 | 100.000000 | 0.047208 | 0.080024 | |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 2025-07-01 12:00:00+00:00 | 100 | 583 | 54.022082 | 0.0 | 94.444444 | 0.069789 | 0.025392 |
| 200 | 2688 | 36.945813 | 0.0 | 88.349515 | 0.032590 | 0.106186 | |
| 300 | 6515 | 28.240996 | 0.0 | 89.189189 | 0.030245 | 0.113385 | |
| 400 | 11821 | 27.567402 | 0.0 | 89.380531 | 0.034995 | 0.114971 | |
| 500 | 19048 | 26.236301 | 0.0 | 90.322581 | 0.030787 | 0.123747 |
100 rows × 6 columns
[11]:
# Plot the results
fig, ax = plt.subplots(figsize=(10, 6))
ax.xaxis.set_major_formatter(DateFormatter("%m-%d"))
for date, new_df in df.groupby(level=1):
ax.plot(
new_df.index.get_level_values("time").values,
new_df["TROPOMI_SO2-7km_mass"],
marker="o",
linestyle="-",
label=f"Radius = {new_df.index.get_level_values('radius').values[0]} km",
)
ax.set_xlabel("Time")
ax.set_ylabel("SO2 mass")
ax.set_title("SO2 mass burden time series (TROPOMI SO2-7km)")
ax.legend()
plt.show()
Display satellite images#
[12]:
# Read datacube from remote file exposed in the results (GEOTIFF format)
gridded_data_path = result["output_files"]["gridded_data"]
ds = rioxarray.open_rasterio(gridded_data_path)
# Display one layer of the datacube (corresponding to one time step)
index_time = 7
SO2_mass_burden = ds.data[index_time]
selected_time = ast.literal_eval(ds.attrs["timestamps"])[index_time]
easting_bbox = [ds.x[0], ds.x[-1]]
northing_bbox = [ds.y[0], ds.y[-1]]
extent = [easting_bbox[0], easting_bbox[1], northing_bbox[0], northing_bbox[1]]
# Get coordinates of volcano, which is the center of the projection
lon_volc, lat_volc = (
ds.spatial_ref.attrs["longitude_of_projection_origin"],
ds.spatial_ref.attrs["latitude_of_projection_origin"],
)
name_volc = result["metadata"]["parameters"]["volcano"]
# Draw data on a map
plt.figure()
plt.suptitle(f"TROPOMI SO2-7km column amount at {selected_time}", fontsize=14)
ax = plt.axes(projection=ccrs.LambertAzimuthalEqualArea(lon_volc, lat_volc))
ax.add_feature(cfeature.COASTLINE.with_scale("50m"), linewidth=0.75)
ax.gridlines(draw_labels=True, linewidth=0.5, color="gray", alpha=0.5, linestyle="--")
cax = ax.inset_axes((1.2, 0, 0.08, 1.0))
cmap = colormaps.get_cmap("afmhot_r").copy()
cmap.set_bad("white")
im0 = plt.imshow(
SO2_mass_burden,
norm=colors.LogNorm(0.1),
interpolation="none",
extent=extent,
origin="lower",
cmap=cmap,
)
plt.colorbar(
im0, cax=cax, label="SO2-7km column (DU)", orientation="vertical", pad=0.2
)
plt.plot([lon_volc, lat_volc], "^", ms=7, c="yellow", mec="k", label=name_volc)
plt.legend(loc="upper right")
plt.xlim(easting_bbox)
plt.ylim(northing_bbox)
plt.tight_layout()
plt.show()