from plotnine import *
from plotnine.data import mpg
Operators: +, >>, |, /
Plotnine overloads the +
and >>
operators to make it easier to compose and pass data to plots. It also overloads the |
and /
operators to compose multiple plots together. You might also see &
, and *
used for adding components to composed plots.
This page covers the basics of the +
and >>
operators, along with an explanation for why they exist.
The +
operator
Use +
to add geoms, scales, and themes to a plot.
("displ", "hwy"))
ggplot(mpg, aes(+ geom_point(aes(fill="class")) # first geom
+ theme_minimal() # theme
)
The >>
operator
Use the >>
operator to pipe data into a plot.
(
mpg# piped into plot
>> ggplot(aes("displ", "hwy", fill="class")) + geom_point()
)
Why operators?
Composable and extendable
Operators enable plot actions to use syntax that’s composable and extendable. This means two things:
- composable: you can add additional components like geoms to a plot.
- extendable: components defined in other libraries—like new kinds of geoms—can be added to a plot using the same
+
syntax.
For example, suppose you defined your own Plotnine theme, as shown below:
def my_theme(base_size=11):
return (
=base_size) # start with grey theme
theme_grey(base_size+ theme(axis_text_x=element_text(angle=90)) # customize x-axis
)
You can use this theme with the +
operator, just like the built-in Plotnine themes:
("displ", "hwy", fill="class"))
ggplot(mpg, aes(+ geom_point()
+ my_theme(base_size=16) # apply custom theme
)
Notice that the custom my_theme()
component was added to the plot, in the same way anything else is (e.g. geom_point()
).
Keep method chains going
The >>
operator allows you to keep method chains going, without needing to create intermediate variables. This is especially useful when using Polars DataFrames, where you often want to do small bits of data wrangling before piping into the plot.
import polars as pl
= pl.from_pandas(mpg)
pl_mpg
(
pl_mpg#
# label high mpg cars
=pl.col("hwy") > 30)
.with_columns(good_mpg#
# remove compact cars
filter(pl.col("class") != "compact")
.#
# pipe into plot
>> ggplot(aes("displ", "hwy", fill="good_mpg")) + geom_point()
)
Is overloading operators “Pythonic”?
Sometimes people ask whether overloading the +
and >>
operators is “Pythonic” – meaning that it follows standard conventions for Python code. This is a tricky question to answer, but there are two cases that point to “yes”:
- The builtin
pathlib
library overloads/
to good effect. - Tools like Polars use operators to compose selectors.
pathlib
example
from pathlib import Path
"a/b") / "c" Path(
PosixPath('a/b/c')
In this case, the /
operator makes it quick to add to a path (by returning a new Path object). Similarly, the Plotnine >>
operator makes it easy to go from DataFrame method chaining into a plot.
Polars example
import polars as pl
import polars.selectors as cs
= pl.DataFrame({"ttl_a": [1], "ttl_b": [2], "ttly": [3]})
df
# get cols starting with "ttl" but not "ttly"
= cs.starts_with("ttl") - cs.by_name("ttly")
selector
df.select(selector)
ttl_a | ttl_b |
---|---|
i64 | i64 |
1 | 2 |
Each selector (like starts_with
) specifies a way to select columns, while operators like -
provide ways to combine them. Similarly, each geom in Plotnine specifies a piece to include in a plot, while the +
operator makes it easy to assemble pieces.