Uh oh!
There was an error while loading. Please reload this page.
❄️ Happy holidays from UltraPlot! #438
Closed
cvanelteren
announced in
Announcements
Replies: 2 comments
snippetimportcartopy.crsasccrsimportcartopy.featureascfeatureimportnumpyasnpimportxarrayasxrimportultraplotasupltdefmain():
uplt.rc["formatter.log"] =Truelayout= [[1, 1, 1], [2, 3, 4]]
fig, axs=uplt.subplots(
layout,
share=0,
figsize=(10, 8),
proj=["cyl", "cartesian", "cartesian", "cartesian"],
)
axs.format(abc=True, abcloc="ul")
# Curved quiver on a geo wind map.u_url= (
"https://psl.noaa.gov/thredds/dodsC/Datasets/""ncep.reanalysis/surface/uwnd.sig995.2025.nc"
)
v_url= (
"https://psl.noaa.gov/thredds/dodsC/Datasets/""ncep.reanalysis/surface/vwnd.sig995.2025.nc"
)
ds_u=xr.open_dataset(u_url)
ds_v=xr.open_dataset(v_url)
ds=xr.merge([ds_u, ds_v])
ds=ds.assign_coords(lon=((ds.lon+180) %360) -180).sortby("lon")
when="2025-01-15T12:00"lon_bounds= (-160, -60)
lat_bounds= (15, 60)
dsi=ds.sel(
time=when,
lat=slice(lat_bounds[1], lat_bounds[0]),
lon=slice(lon_bounds[0], lon_bounds[1]),
)
U=dsi["uwnd"].coarsen(lat=2, lon=2, boundary="trim").mean()
V=dsi["vwnd"].coarsen(lat=2, lon=2, boundary="trim").mean()
ifU.lat.values[0] >U.lat.values[-1]:
U=U.sortby("lat")
V=V.sortby("lat")
speed=np.hypot(U, V)
lon1d=U.lon.valueslat1d=U.lat.valuesU2d=U.valuesV2d=V.valuesdefmake_cell_center_seed_points(x1d, y1d, grains=8):
ifx1d.size<2ory1d.size<2:
eps=1e-9xs=np.linspace(
float(x1d.min()) +eps, float(x1d.max()) -eps, max(1, grains)
)
ys=np.linspace(
float(y1d.min()) +eps, float(y1d.max()) -eps, max(1, grains)
)
Xs, Ys=np.meshgrid(xs, ys)
returnnp.c_[Xs.ravel(), Ys.ravel()]
xcent=0.5* (x1d[:-1] +x1d[1:])
ycent=0.5* (y1d[:-1] +y1d[1:])
nx=int(np.clip(grains, 1, xcent.size))
ny=int(np.clip(grains, 1, ycent.size))
xi=np.linspace(0, xcent.size-1, nx).astype(int)
yi=np.linspace(0, ycent.size-1, ny).astype(int)
Xs, Ys=np.meshgrid(xcent[xi], ycent[yi])
returnnp.c_[Xs.ravel(), Ys.ravel()]
cq_seeds=make_cell_center_seed_points(lon1d, lat1d, grains=20)
ax_geo=axs[0]
ax_geo.set_extent(
[lon_bounds[0], lon_bounds[1], lat_bounds[0], lat_bounds[1]],
crs=ccrs.PlateCarree(),
)
cq=ax_geo.curved_quiver(
lon1d,
lat1d,
U2d,
V2d,
color=speed.values,
cmap="viko",
arrow_at_end=True,
arrowsize=2,
grains=40,
scale=20,
start_points=cq_seeds,
transform=ccrs.PlateCarree(),
linewidth=3.5,
)
# Add simple map contextax_geo.format(
title="Near-surface winds",
lonlabels=True,
latlabels=True,
land=True,
coast=True,
ocean=True,
oceancolor="ocean blue",
landcolor="mushroom",
)
# Beeswarm plot.rng=np.random.default_rng(2)
n_points, n_cats=40, 4levels=np.tile(np.arange(n_cats, dtype=float), (n_points, 1))
data=rng.normal(loc=np.arange(n_cats) *1.5, scale=0.6, size=(n_points, n_cats))
feature_values=rng.standard_normal(size=(n_points, n_cats))
axs[1].beeswarm(
data,
levels=levels,
feature_values=feature_values,
ss=22,
orientation="vertical",
cmap="viko",
colorbar="lr",
colorbar_kw=dict(title="SHAP value"),
discrete=False,
)
axs[1].format(
title="Beeswarm (SHAP-style)",
xlabel="Group",
ylabel="Value",
xticks=np.arange(n_cats),
xticklabels=["A", "B", "C", "D"],
)
# Lollipop graph.labels= ["Atlas", "Nova", "Sol", "Lumen", "Echo"]
x=np.arange(len(labels))
y=np.array([2.2, 5.4, 3.1, 6.2, 4.5])
cmap=uplt.Colormap("set3")
colors=cmap(np.linspace(0.1, 0.9, len(x)))
axs[2].lollipop(
x,
y,
width=0.6,
color=colors,
marker="o",
s=140,
edgecolor="k",
linewidth=1.5,
stemwidth=2.4,
stemcolor="gray6",
)
axs[2].format(
title="Lollipop",
xlabel="Series",
ylabel="Score",
xticks=x,
xticklabels=labels,
ygrid=True,
ygridcolor="gray9",
)
# CFTime axis with log-scaled values.time=xr.cftime_range("2024-01-01", periods=49, freq="30D", calendar="360_day")
values=np.geomspace(1, 1e4, time.size)
axs[3].plot(time, values, lw=2)
axs[3].format(
title="CFTime + log y",
yscale="log",
xlabel="Date (360_day)",
ylabel="Magnitude",
)
fig.colorbar(cq.lines, ax=ax_geo, label="Near-surface wind speed (m/s)")
fig.format(suptitle="UltraPlot 2025 Showcase")
fig.savefig("showcase2025.png")
uplt.show()
if__name__=="__main__":
main() |
0 replies
UltraPlot has become part of my daily workflow. |
0 replies
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
It’s been a huge year of steady, focused development. Since January last year we went from 0 to 241 stars, crossed 134k+ downloads, and pushed test coverage to ~80%. Thank you to everyone who tried the library, filed issues, and helped shape the roadmap.
What shipped this year
curved_quiver,beeswarm,lollipop graphs,network plotting.Where we’re going in 2026
Thank you for a great year of building. Here’s to an even sharper UltraPlot in 2026. 🥂
All reactions