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

'shade' function doesn't correctly implement 'span' #368

Closed
bjfar opened this issue Jun 2, 2017 · 1 comment · Fixed by #680
Closed

'shade' function doesn't correctly implement 'span' #368

bjfar opened this issue Jun 2, 2017 · 1 comment · Fixed by #680
Assignees

Comments

@bjfar
Copy link

bjfar commented Jun 2, 2017

When I use the span argument to shade, for example in the following callback function for Bokeh:

def create_image(x_range, y_range, w, h):
    cvs = ds.Canvas(x_range=x_range, y_range=y_range, plot_width=200, plot_height=200)
    agg = cvs.points(df, 'x', 'y', ds.min('z'))
    img = tf.shade(agg, cmap=chi2cmap, how='linear', span=[mn,mx])
    #return tf.dynspread(img, threshold=0.9, max_px=10)
    return img

then I expect the colormap to be absolutely normalised according to the min and max 'z' values supplied in span. However, Datashader doesn't do this, it seems to offset the colors by the minimum value of 'z' in the data. This can be observed by dynamically zooming with bokeh, one seems the colors change rather than remain constant.

Looking at the code, I think it is because of the following lines in https://github.com/bokeh/datashader/blob/master/datashader/transfer_functions.py:

def _interpolate(agg, cmap, how, alpha, span):
    if agg.ndim != 2:
        raise ValueError("agg must be 2D")
    interpolater = _normalize_interpolate_how(how)
    data = agg.data
    if np.issubdtype(data.dtype, np.bool_):
        mask = ~data
        interp = data
    else:
        if np.issubdtype(data.dtype, np.integer):
            mask = data == 0
        else:
            mask = np.isnan(data)

        masked = data[~mask]
        if len(masked) == 0:
            return Image(agg.data.view(np.uint32), coords=agg.coords, dims=agg.dims, attrs=agg.attrs)

        offset = masked.min()

        interp = data - offset
        
    data = interpolater(interp, mask)
...

Here it seems that some offset is indeed applied according the to minimum of the dataset. I assume this is what is screwing up the interpretation of span. Probably the offset just needs to be added back in after the interpolation is applied? Anyway I tried modifying as follows:

data = interpolater(interp, mask)
--->
data = interpolater(interp, mask) + offset

and it seems to produce the correct result for my case.

@nanodan
Copy link

nanodan commented Oct 19, 2017

Hey I was having the same issue and your fix worked for me, thanks. This should probably be submitted as a pull request.

Another issue with span is that the values have to be "clamped" to lie within the span range or I get an "blank" plot - just white.

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

Successfully merging a pull request may close this issue.

4 participants