constructed with seaborn object-style plots instead. These kind of plots are much more structured for the workflow I use and the way I think about plotting, clearly delineating between a plot; some visual on the plot; some statistical transformation; some movement, labeling or scaling operation. They are also, however, fairly new and still considered experimental. They also don't allow *quite* the customization that the other plots do, and seem either a little buggy or I have not fully understood them yet in regards to ticks and labels. ```{python} # | label: fig-groundlevel-so # | fig-cap: "Nuclear explosions, 1945-98" import seaborn.objects as so import matplotlib.dates as mdates above_cat = pl.Series( [ "ATMOSPH", "AIRDROP", "TOWER", "BALLOON", "SURFACE", "BARGE", "ROCKET", "SPACE", "SHIP", "WATERSUR", "WATER SU", ] ) df_groundlevel = ( df.with_columns( above_ground=pl.col("type").map_elements( lambda x: True if x in above_cat else False, return_dtype=bool )) .group_by(pl.col("year", "country", "above_ground")) .agg(count=pl.len()) .sort("year") ) fig, ax = plt.subplots() ax.xaxis.set_tick_params(rotation=90) from seaborn import axes_style p = ( so.Plot(df_groundlevel, x="year", y="count", color="country") .add( so.Bars(), so.Stack(), data=df_groundlevel.filter(pl.col("above_ground") == True).sort("country"), ) .add( so.Bars(), so.Stack(), data=df_groundlevel.filter(pl.col("above_ground") == False).with_columns( count=pl.col("count") * -1 ).sort("country"), ) .label(x="Year", y="Count") .scale( x=so.Continuous().tick(locator=mdates.YearLocator(base=5), minor=4).label(like="{x:.0f}"), # x=so.Nominal().tick(locator=mdates.YearLocator(base=5), minor=4), # this might work in the future ) .theme({ **axes_style("darkgrid"), "xtick.bottom": True, "ytick.left": True }) .on(ax) .plot() ) ```