Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Antialiased line support for where reductions #1269

Merged
merged 4 commits into from
Aug 16, 2023
Merged

Antialiased line support for where reductions #1269

merged 4 commits into from
Aug 16, 2023

Conversation

ianthomas23
Copy link
Member

This PR adds antialiased line support for where reductions on CPU, with and without dask, of the following:

ds.where(ds.min("value"), "other")
ds.where(ds.max("value"), "other")
ds.where(ds.first("value"), "other")
ds.where(ds.last("value"), "other")
ds.where(ds.min_n("value", n=n), "other")
ds.where(ds.max_n("value", n=n), "other")
ds.where(ds.first_n("value", n=n), "other")
ds.where(ds.last_n("value", n=n), "other")

all of which return values from the "other" column, and the same calls but without "other" which return row indexes.

Also, all of the above within a categorical by reduction such as

ds.by("cat", ds.where(ds.first_n("value", n=n)))

Example code:

import datashader as ds
import datashader.transfer_functions as tf
import numpy as np
import pandas as pd

df = pd.DataFrame(dict(y0=[0.5, 1.0, 0.0 ], y1=[1.0, 0.0, 0.5], y2=[0.0, 0.5, 1.0], value=[2, 3, 1], other=[33, 22, 11],))
cvs = ds.Canvas(plot_width=200, plot_height=150, x_range=(-0.1, 1.1), y_range=(-0.1, 1.1))
kwargs = dict(source=df, x=np.asarray([0, 0.5, 1]), y=["y0", "y1", "y2"], axis=1, line_width=15)

reductions = dict(
    where_max_i=ds.where(ds.max("value")),
    where_max_other=ds.where(ds.max("value"), "other"),
    where_min_i=ds.where(ds.min("value")),
    where_min_other=ds.where(ds.min("value"), "other"),
    where_first_i=ds.where(ds.first("value")),
    where_first_other=ds.where(ds.first("value"), "other"),
    where_last_i=ds.where(ds.last("value")),
    where_last_other=ds.where(ds.last("value"), "other"),
)

for name, reduction in reductions.items():
    agg = cvs.line(agg=reduction, **kwargs)
    limits = (np.nanmin(agg), np.nanmax(agg))
    im = tf.shade(agg, how="linear", span=limits)
    filename = f"temp_{name}"
    print("Writing file", filename, "limits", limits)
    ds.utils.export_image(im, filename, background="white")

Example outputs returning row indexes for max, min, first and last respectively (integers in the range -1 to 2 inclusive):
temp_where_max_i temp_where_min_i temp_where_first_i temp_where_last_i

If you don't want to work out the maths yourself, just note that these are examples are setup such that the outputs should all have different overlaps.

Example outputs when returning values from the "other" column (floats which are either 11, 22 or 33, or np.nan):
temp_where_max_other temp_where_min_other temp_where_first_other temp_where_last_other

The colors here are in the opposite orders to the equivalent row index examples above, but the overlaps are the same.

The edges are hard (not antialiased) when returning row indexes because there is no such thing as a fractional row index. The edges are also hard when returning values from the "other" column as these values are derived from the row indexes. Returning antialiased edges for the latter is currently not possible given how the antialiased lines are implemented, but is a possible area for improvement in the future.

In terms of implementation, the second stage antialiased accumulation here reuses the where combine() functions to keep code duplication to a minimum.

@ianthomas23 ianthomas23 added this to the v0.15.2 milestone Aug 15, 2023
@codecov
Copy link

codecov bot commented Aug 15, 2023

Codecov Report

Merging #1269 (b3e2f5a) into main (fe567d0) will increase coverage by 0.11%.
The diff coverage is 89.28%.

@@            Coverage Diff             @@
##             main    #1269      +/-   ##
==========================================
+ Coverage   83.40%   83.51%   +0.11%     
==========================================
  Files          35       35              
  Lines        9110     9117       +7     
==========================================
+ Hits         7598     7614      +16     
+ Misses       1512     1503       -9     
Files Changed Coverage Δ
datashader/core.py 88.25% <ø> (ø)
datashader/utils.py 76.64% <ø> (-0.25%) ⬇️
datashader/reductions.py 80.62% <80.76%> (+0.55%) ⬆️
datashader/compiler.py 89.39% <96.66%> (+0.22%) ⬆️

... and 1 file with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@ianthomas23 ianthomas23 merged commit ea163e9 into holoviz:main Aug 16, 2023
@ianthomas23 ianthomas23 deleted the aa_where branch August 16, 2023 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant