My goal here is to create x,y,z scatterplots in HoloViews, where the plots are produced with Datashader, with the points aggregated by minimizing over 'z', and with the points colored according to 'z'. Ultimately this is for doing things like producing profile likelihood plots.
I made good progress generating plots with HoloViews + Datashader, even linking the plots in cool ways (see e.g. How to do linked data selections in HoloViews with Datashader + Bokeh backend), however I can't figure out how to control the point colors and aggregation method.
Below is some code (run in a Jupyter notebook) that does (almost) what I want in "plain vanilla" Datashader + Bokeh. How can I achieve the same thing via HoloViews, so that I can take advantage of the nice features in that package?
Note in particular that I want colors assigned to specific z values, I do not want it to be automatically normalised or any such thing. I tried to achieve this in the below code by setting the 'span' argument in the 'shade' function, though it doesn't quite work, because when I zoom in on the plot I see new green areas appear, which indicates that the absolute normalisation of the colors is not staying constant. Anyway it should be close enough to illustrate what I am after.
import pandas as pd
from bokeh.plotting import figure, output_notebook
import datashader as ds
from datashader.bokeh_ext import InteractiveImage
from datashader import transfer_functions as tf
output_notebook(hide_banner=True)
import matplotlib.colors as colors
#Define colormap
mn=0
mx=5
s0=0./(mx-mn)
s1=1./(mx-mn)
s2=2./(mx-mn)
s3=3./(mx-mn)
s4=4./(mx-mn)
s5=5./(mx-mn)
cdict = {
'red' : ((s0, 0., 0.), (s1, 1., 1.), (s2, 1., 1.), (s3, 1., 1.), (s4, .5, .5), (s5, .2, .2)),
'green': ((s0, 1., 1.), (s1, 1., 1.), (s2, .5, .5), (s3, 0., 0.), (s4, 0., 0.), (s5, 0., 0.)),
'blue' : ((s0, 0., 0.), (s1, 0., 0.), (s2, 0., 0.), (s3, 0., 0.), (s4, 0., 0.), (s5, 0., 0.))
}
chi2cmap = colors.LinearSegmentedColormap('chi2_colormap', cdict, 1024)
chi2cmap.set_bad('w',1.)
# Create some data to plot
x = np.arange(0,10,1e-2)
y = np.arange(0,10,1e-2)
X,Y = np.meshgrid(x,y)
x = X.flatten()
y = Y.flatten()
z = 5 * np.sin(x) * np.cos(y)
#------ Create pandas dataframe object from the data ------
print "Creating Pandas dataframe object"
df = pd.DataFrame.from_dict({"x": x, "y": y, "z": z})
# Create 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
# Export image
#ds.utils.export_image(img, "test", fmt=".png", export_path=".", background="white")
# Interactive image via bokeh
p = figure(tools='pan,wheel_zoom,box_zoom,reset', background_fill_color="white",
plot_width=500, plot_height=500, x_range=(np.min(x),np.max(x)), y_range=(np.min(y),np.max(y)))
p.axis.visible = False
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
InteractiveImage(p, create_image)
with output