holoviz / holoviz/datashader

Possible improvements to antialiased line implementation

Open
#1,148 1 comment 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
3.6k
Forks
376
Avg merge
4h 32m
Merged PRs (30d)
1

Description

The current state of antialiased lines with various reductions was summaries in PR #1146. Test code and images are reproduced here:
```python
import datashader as ds
import datashader.transfer_functions as tf
import numpy as np
import pandas as pd

df = pd.DataFrame(dict(ystart=[0.2, 0, 1, 0.8], yend=[0.2, 1, 0, 0.8], value=[1, 2, 3, 4]))

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, 1]), y=["ystart", "yend"], axis=1, line_width=15)

for i, reduction in enumerate([
ds.any(), ds.count(), ds.sum("value"), ds.min("value"), ds.max("value"),
ds.first("value"), ds.last("value"), ds.mean("value")
]):
agg = cvs.line(agg=reduction, **kwargs)
im = tf.shade(agg, how="linear")
ds.utils.export_image(im, f"temp{i}")
```
Screenshot 2022-11-17 at 11 29 15

Possible improvement (again copied from PR #1146):

There is no workaround for this, it would need a more complicated implementation as we don't store the information required to do this. We would need to separate out the antialias `weighting` (what would conventionally be called the `alpha` but trying not to use that term here) from the normal aggregate numbers. For the `count` of a single line segment the `count` agg would be 1 for every pixel in the line right up to the edges, and the `weighting` would be 1 along the middle of the line, down to just about 0 at the extreme edges. The 2D agg returned to the user would be the product of the two, giving the same number as we currently return (for a single line).

For a compound reduction of a `count` and `sum` we can imaging 3 aggs, `count`, `sum` and `weighting`. For the `count` we'd return `count*weighting` to the user, for the `sum` we'd return `sum*weighting`, and for the `mean` we'd return `(sum/count)*weighing`, giving you exactly what you want.

In general, we couldn't just have a single `weighting` per `canvas.line` call, we'd need a `weighing` per agg. So maybe we'd think of changing each of the current agg's shapes from `(height, width)` to `(height, width, 2)`, so the agg is attached to its weighting.

We would need to decide on appropriate mathematics to combine say `(value1, weighting1)` with `(value2, weighting2)` for a particular pixel. Let's assume we want a linear combination, so the combined value must be `value1*weighting1 + value2*weighting2`. Or is it? It might be more sensible to say we want the combined `value` and `weighting` so that `value*weighting = value1*weighting1 + value2*weighting2` because the `value` needs to be stored unweighted (the whole purpose of this approach is to keep the `weighting` separate from the `value`). This maths is not dissimilar to combined rendering of RGB and A separately, but there we have the concept of rendering on top of existing colors in a non-commutative way. So it is more complicated than that!

In summary, to obtain a mean that more in line with what is expected would require:

- Twice as much memory for the 3D aggs.
- Slightly more complicated code, but only at the very highest and lowest levels as we'd still be scanning the source dataframe just once, only with 3D aggs.
- Thought about appropriate maths to combine values and weights (which may or may not exist)

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reviewing PR #1146 and the reproduced Canvas.line reduction example. Clarify the mathematics for combining values and antialias weighting, including count, sum, and mean, before deciding the implementation scope. Done means antialiased line reductions produce the intended mean and preserve appropriate aggregate behavior across the shown reductions.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data-visualization
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.