Skip to content

Commit

Permalink
Transform aesthetic parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
has2k1 committed Dec 10, 2024
1 parent 0d6fabb commit d45cdba
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 5 deletions.
10 changes: 10 additions & 0 deletions doc/changelog.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ title: Changelog
- Fixed [](:class:`~plotnine.geom_text`) with `adjust_text` for some
cases where the text are placed outside the panels. {{< issue 899 >}}

- The default aesthetics and aesthetic parameters of geoms (and stats) are
now transformed. So you can now set date values as aesthetic parameters.
e.g.

```python
geom_point(y=datetime(2024, 12, 11))
```

if the `y` aesthetic is mapped to datetime column in another layer.

## v0.14.3
(2024-11-26)
[![](https://zenodo.org/badge/DOI/10.5281/zenodo.14224336.svg)](https://doi.org/10.5281/zenodo.14224336)
Expand Down
2 changes: 1 addition & 1 deletion plotnine/geoms/geom.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def use_defaults(
data :
Data used for drawing the geom.
aes_modifiers :
Aesthetics
Aesthetics to evaluate
Returns
-------
Expand Down
2 changes: 1 addition & 1 deletion plotnine/ggplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ def _build(self):
layout.setup_panel_params(self.coordinates)

# fill in the defaults
layers.use_defaults_after_scale()
layers.use_defaults_after_scale(scales)

# Allow stats to modify the layer data
layers.finish_statistics()
Expand Down
17 changes: 14 additions & 3 deletions plotnine/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ def use_defaults(
self,
data: pd.DataFrame,
aes_modifiers: dict[str, Any],
scales: Scales | None = None,
) -> pd.DataFrame:
"""
Prepare/modify data for plotting
Expand All @@ -382,7 +383,17 @@ def use_defaults(
Expression to evaluate and replace aesthetics in
the data.
"""
return self.geom.use_defaults(data, aes_modifiers)
old_columns = data.columns
data = self.geom.use_defaults(data, aes_modifiers)
if scales is not None:
# The default aesthetics and the aesthetic parameters are
# specified in userspace. When we add them we have to
# transform them.
new_columns = data.columns.difference(old_columns)
_data = scales.transform_df(self.data[new_columns])
for col in new_columns:
data[col] = _data[col]
return data

def finish_statistics(self):
"""
Expand Down Expand Up @@ -468,9 +479,9 @@ def compute_position(self, layout: Layout):
for l in self:
l.compute_position(layout)

def use_defaults_after_scale(self):
def use_defaults_after_scale(self, scales: Scales):
for l in self:
l.use_defaults(l.data, l.mapping._scaled)
l.data = l.use_defaults(l.data, l.mapping._scaled, scales)

def transform(self, scales: Scales):
for l in self:
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions tests/test_scale_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
scale_x_discrete,
scale_x_log10,
scale_y_continuous,
scale_y_log10,
)
from plotnine.scales.scales import make_scale

Expand Down Expand Up @@ -876,3 +877,33 @@ def test_discrete_scale_for_empty_layer():
)

p.draw_test()


def test_transform_aes_defaults_and_params():
data = pd.DataFrame({"x": range(5), "y": 10 ** np.arange(5)})
# Another set of points that should be inline with the first set
# both with and without the scale_y_log10.
data2 = pd.DataFrame({"x": [3.2, 3.4, 3.6, 3.8]})
yparam = list(10 ** data2["x"])

p = (
ggplot(data, aes("x", "y"))
+ geom_point()
+ geom_point(data=data2, y=yparam, color="red")
+ scale_y_log10()
)
assert p == "transform_aes_defaults_and_params"


def test_transform_datetime_aes_param():
data = pd.DataFrame(
{"x": range(5), "y": [datetime(2024, i, 1) for i in range(1, 6)]}
)
yparam: list[datetime] = list(data["y"] + timedelta(days=30))

p = (
ggplot(data, aes("x", "y"))
+ geom_point()
+ geom_point(y=yparam, color="red")
)
assert p == "transform_datetime_aes_param"

0 comments on commit d45cdba

Please sign in to comment.