nuclear_explosions/notebooks/sns_objects-style.qmd
2024-06-22 23:11:49 +02:00

76 lines
2.1 KiB
Plaintext

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()
)
```