# Copyright 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
import io
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import matplotlib.patheffects
import re
from google.colab import files
df = pd.read_csv(io.StringIO('''
Name,First published,Z500 3 day,IFS Z500 3 day,Skill relative to IFS
Dueben & Bauer 2018,Oct 2018,480,80,16.7
Weyn et al 2019,Jul 2019,70,25,35.7
WeatherBench,Feb 2020,626,154,24.6
Rasp & Thuerey 2020,Aug 2020,268,154,57.5
Weyn et al 2020,Aug 2020,373,154,41.3
Weyn et al 2021,June 2021,270,154,57.0
Clare et al 2021,Oct 2021,375,154,41.1
Keisler 2022,Feb 2022,175,135,77.1
FourCastNet,Feb 2022,220,135,61.4
Pangu-Weather,Nov 2022,133,135,101.5
GraphCast,Dec 2022,124,135,108.9
FengWu,Apr 2023,135,135,100.0
FuXi,Jun 2023,125,135,108.0
SFNO,Jun 2023,130,135,103.8
NeuralGCM (0.7 deg),Nov 2023,115,135,117.4
GenCast,Dec 2023,130,135,103.8
Stormer,Dec 2023,125,135,108.0
WindBorne,Feb 2024,122.85,135,109.9
HEAL-ViT,Feb 2024,120,135,112.5
SwinV2,Apr 2024,124,135,108.9
ArchesWeather,May 2024,135,135,100.0
Aurora,May 2024,130,135,103.8
AIFS,Jun 2024,16.4,16.8,102.1
FuXi-ENS,Aug 2024,122,132,108.2
ECMWF ENS Mean,Jan 2020,132,135,102.2727273
'''), header=0)
df['First published'] = pd.to_datetime(df['First published'])
<ipython-input-3-eaad74acf0aa>:29: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format. df['First published'] = pd.to_datetime(df['First published'])
fig, ax = plt.subplots(figsize=(7, 4.5))
x = df['First published']
y = df['Skill relative to IFS']
def plot_all(ax):
ax.axhline(100, color='C1', zorder=-1)
ax.scatter(x[:-1], y[:-1])
ax.step(x[:-1].tolist() + [pd.Timestamp('20250101')], np.maximum.accumulate(y)[:-1].tolist() + [y[:-1].values.max()], where='post')
for i, txt in enumerate(df['Name'][:-1]):
txt = re.sub(r'\s\d{4}', '', txt)
txt = txt.replace(' (0.7 deg)', '').replace(' & ', ' &\n')
txt = txt.replace('Pangu-Weather', 'Pangu')
ax.annotate(
txt,
(x[i], y[i]),
xytext=(0, 5),
size=8,
textcoords='offset points',
horizontalalignment='right' if txt == 'Pangu' else 'center',
annotation_clip=True,
path_effects=[matplotlib.patheffects.withStroke(linewidth=2, foreground="white")],
)
plot_all(ax)
plt.ylabel('Z500 RMSE skill vs. ECMWF HRES')
plt.xlabel('Date of release')
plt.xlim(pd.Timestamp('20180401'), pd.Timestamp('20241201'))
plt.ylim(0, None)
sns.despine()
subax = ax.inset_axes((0.81, 0.13, 0.5, 0.6))
plot_all(subax)
sub_times = pd.date_range('2022', '2025', freq='12MS')
subax.set_xticks(sub_times, sub_times.strftime('%Y-%m'))
subax.set_xlim(pd.Timestamp('20220701'), pd.Timestamp('20241201'))
subax.set_ylim(98, 120)
subax.axhline(100, color='C1', zorder=-1)
ax.indicate_inset_zoom(subax, edgecolor="gray", clip_on=False, zorder=-1)
plt.title('State of the art in AI weather prediction', y=1.02)
fig.text(0.97, 0.02, 'Authors:\nshoyer@google.com\nsrasp@google.com', fontsize=8)
fig.savefig('/tmp/fig.png', dpi=200, bbox_inches='tight')
files.download("/tmp/fig.png")