On Jan 2, 2018, at 03:22, chupach <[email protected]> wrote:
Thanks Bryan, works now beautifully ! (and much simpler as well)
Show now lines in relative units without flickering
updated example:
import numpy as np
from bokeh.document import Document
from bokeh.embed import file_html
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.resources import INLINE
from bokeh.sampledata.stocks import AAPL, GOOG
from bokeh.util.browser import view
JS_CODE_MYLINE = """
import {RBush} from "core/util/spatial"
import {Line, LineView} from "models/glyphs/line"
import * as p from "core/properties"
export class MyLineView extends LineView
clip: (x,x0,x1) ->
if (x < x0)
x = x0
else if (x > x1)
x = x1
return x
_map_data: () ->
r = @renderer
y0 = r.yscale.source_range.start
y1 = r.yscale.source_range.end
istart = @clip(Math.ceil(r.xscale.source_range.start),0,@sx.length-1)
ynorm = @_y[istart]
y =
for i in [0...@_y.length]
y.push(@_y[i]/ynorm)
[@sx, @sy] = @map_to_screen(@_x, y)
export class MyLine extends Line
default_view: MyLineView
type: 'MyLine'
@define {
normalize: [ p.Bool, false ]
}
"""
from bokeh.core.properties import Float,Bool
from bokeh.models import Line
from bokeh.util.compiler import CoffeeScript
class MyLine(Line):
__implementation__ = CoffeeScript(JS_CODE_MYLINE)
normalize = Bool(False)
y1, y2 = AAPL['adj_close'], GOOG['adj_close']
n = min(len(y1),len(y2))
cds1 = ColumnDataSource(data=dict(x=np.arange(n),y=y1[-n:] ))
cds2 = ColumnDataSource(data=dict(x=np.arange(n),y=y2[-n:] ))
plot = figure(width=600,height=300,tools=['box_zoom','wheel_zoom','xwheel_pan'])
L1 = MyLine(x="x", y="y", normalize=True,line_color='red'); plot.add_glyph(cds1, L1)
L2 = MyLine(x="x", y="y", normalize=True); plot.add_glyph(cds2, L2)
plot.y_range.start=0
plot.y_range.end=20
doc = Document()
doc.add_root(plot)
if __name__ == "__main__":
doc.validate()
filename = "ynorm_line.html"
with open(filename, "w") as f:
f.write(file_html(doc, INLINE, "line custom model with ynorm"))
print("Wrote %s" % filename)
view(filename)
On Monday, January 1, 2018 at 10:20:20 PM UTC+1, Bryan Van de ven wrote:
Hi,
A CustomJS transform is applied any time the data->screen mapping happens. So it should happen on any pan/zoom etc. If you need it to happen in other situations where a screen remap would not normally happen, then I think a Custom extension such as you have is probably the way to go.
As for what is going wrong with you code, one issue appears to be that you are using the default DataRange1d models that attempt to auto-range based on the supplied data. This combination is not really consistent, since you are basically trying to do something similar on your own in the glyph _render call. However, I'm not really sure what you are actually trying to accomplish, so I can't spend more time digging into it. However, I would say that trying to transform things in _render is probably not the best strategy in general. The _render method assumes everything is already mapped, so doing your own updates there is likely to confuse other codepaths that rely on that assumption (e.g. data ranges and others). You might want to consider overriding the _map_data method instead.
Thanks,
Bryan
> On Dec 18, 2017, at 06:31, chupach <[email protected]> wrote:
>
> Hello
>
> is it possible to have the CustomJSTransform applied every time the plot is rendered ?
> (to extend github example bokeh/examples/plotting/file/customjs_transform.py in order to dynamically render relative values)
>
> At the moment i use a custom extension for Line that transforms sx,sy dynamically, but the problem is that the lines disappear during the zoom, which is not nice visually.
>
> Also, in the custom line extension, using simply invert/compute does not work, have to recalculate sx,sy from scratch.
> It should be simpler than that, but i don't know how !?
>
> The complete example below.
>
>
> import numpy as np
>
> from bokeh.document import Document
>
> from bokeh.embed import file_html
>
> from bokeh.models import ColumnDataSource, CustomJSTransform
>
> from bokeh.plotting import figure
>
> from bokeh.resources import INLINE
>
> from bokeh.sampledata.stocks import AAPL, GOOG
>
> from bokeh.util.browser import view
>
>
>
>
>
> JS_CODE_MYLINE = """
>
> import {RBush} from "core/util/spatial"
>
> import {Line, LineView} from "models/glyphs/line"
>
> import * as p from "core/properties"
>
>
>
> export class MyLineView extends LineView
>
> clip: (x,x0,x1) ->
>
> if (x < x0)
>
> x = x0
>
> else if (x > x1)
>
> x = x1
>
> return x
>
>
>
> _render: (ctx, indices, {sx, sy}) ->
>
> normalize = @model.properties.normalize.value()
>
> if !normalize
>
> super(ctx, indices, {sx, sy})
>
> return null
>
>
>
> r = @renderer
>
>
>
> sy0 = r.yscale.target_range.end
>
> sy1 = r.yscale.target_range.start
>
> h = ctx.canvas.height
>
> offset = sy1 - (h - sy0)
>
>
>
> y0 = r.yscale.source_range.start
>
> y1 = r.yscale.source_range.end
>
>
>
> istart = @clip(Math.ceil(r.xscale.source_range.start),0,sx.length-1)
>
> iend = @clip(Math.floor(r.xscale.source_range.end),0,sx.length-1)
>
>
>
> ynorm = 1
>
> for i in [istart...iend+1]
>
> v = @_y[i]
>
> if v != 0
>
> ynorm = v
>
> break
>
>
>
> for i in indices
>
> sy[i] = ( (sy1-sy0) / (y1-y0) )*(@_y[i]/ynorm-y0) + sy0 - offset
>
>
>
> super(ctx, indices, {sx, sy})
>
> return null
>
>
>
> export class MyLine extends Line
>
> default_view: MyLineView
>
> type: 'MyLine'
>
> @define {
>
> normalize: [ p.Bool, false ]
>
> }
>
> """
>
>
>
> from bokeh.core.properties import Float,Bool
>
> from bokeh.models import Line
>
> from bokeh.util.compiler import CoffeeScript
>
>
>
> class MyLine(Line):
>
> __implementation__ = CoffeeScript(JS_CODE_MYLINE)
>
> normalize = Bool(False)
>
>
>
>
>
>
>
> y1, y2 = AAPL['adj_close'], GOOG['adj_close']
>
> n = min(len(y1),len(y2))
>
> cds1 = ColumnDataSource(data=dict(x=np.arange(n),y=y1[-n:] ))
>
> cds2 = ColumnDataSource(data=dict(x=np.arange(n),y=y2[-n:] ))
>
>
>
> plot = figure(width=600,height=300,tools=['box_zoom','xwheel_zoom','xwheel_pan'])
>
>
>
> L1 = MyLine(x="x", y="y", normalize=True,line_color='red'); plot.add_glyph(cds1, L1)
>
> L2 = MyLine(x="x", y="y", normalize=True); plot.add_glyph(cds2, L2)
>
>
>
> doc = Document()
>
> doc.add_root(plot)
>
>
>
> if __name__ == "__main__":
>
> doc.validate()
>
> filename = "ynorm_line.html"
>
> with open(filename, "w") as f:
>
> f.write(file_html(doc, INLINE, "line custom model with ynorm"))
>
> print("Wrote %s" % filename)
>
> view(filename)
>
>
>
>
> --
> You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+un...@continuum.io.
> To post to this group, send email to bo...@continuum.io.
> To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/aae39068-82f6-4b69-8e6e-20079ac39c79%40continuum.io\.
> For more options, visit https://groups.google.com/a/continuum.io/d/optout\.
--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/c4b6a2c5-f8e5-4c17-9ffa-f1580ea25132%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.