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

Possible improvements to antialiased line implementation #1148

Open
ianthomas23 opened this issue Nov 17, 2022 · 1 comment
Open

Possible improvements to antialiased line implementation #1148

ianthomas23 opened this issue Nov 17, 2022 · 1 comment
Milestone

Comments

@ianthomas23
Copy link
Member

The current state of antialiased lines with various reductions was summaries in PR #1146. Test code and images are reproduced here:

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)
@ianthomas23 ianthomas23 added this to the v0.14.x milestone Nov 17, 2022
@ianthomas23
Copy link
Member Author

It might be possible to implement the 3 agg approach just for mean reductions. This could be a good test to see how easy it is to implement and to identify drawbacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant