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

Unable to update Arrow #7118

Closed
pallgj opened this issue Oct 27, 2017 · 12 comments · Fixed by #8474
Closed

Unable to update Arrow #7118

pallgj opened this issue Oct 27, 2017 · 12 comments · Fixed by #8474

Comments

@pallgj
Copy link
Contributor

pallgj commented Oct 27, 2017

ALL software version info (bokeh, python, notebook, OS, browser, any other relevant packages)

Bokeh 0.12.10, Tornado 4.5.2, Windows 10, Chrome

Description of expected behavior and the observed behavior

I'm working with a histogram that contains arrow annotations, and they should update when a button is pressed (the end and start levels of the arrow). For some reason, the arrows won't update.

Complete, minimal, self-contained example code that reproduces the issue

The following code is an example where the error occurs. Press 'run' button.

from bokeh.models import ColumnDataSource, DataRange1d
from bokeh.plotting import figure
from bokeh.layouts import layout
from bokeh.io import curdoc
import numpy as np
from bokeh.models.widgets import Button
from bokeh.models import Arrow, OpenHead

source = ColumnDataSource(data=dict(top=[], left=[], right=[]))
variable_list = list(np.random.randint(11, size=100)) #dummy data
hist, edges = np.histogram(variable_list, density=True, bins='auto')
source.data = dict(top=hist, left=edges[:-1], right=edges[1:])

p = figure(x_range=(0,10), y_range=DataRange1d(start=0))
p.quad(bottom=0, left="left", right="right", top="top", color="white", line_color="#3A5785", source=source)

arrow = Arrow(end=OpenHead(size=15, line_color='black'), line_color='black', x_start=1, x_end=9, y_start=0.05, y_end=0.05)
p.add_layout(arrow)

def btn():
    variable_list = list(np.random.randint(11, size=100)) #dummy data
    hist, edges = np.histogram(variable_list, density=True, bins='auto')
    source.data = dict(top=hist, left=edges[:-1], right=edges[1:])
    arrow.y_end = 0.1

button = Button(label='run')
button.on_click(btn)

l = layout([[p, button]], sizing_mode='fixed')

curdoc().add_root(l)

The following code is a modified example from the Bokeh gallery where the error doesn't occur.

import numpy as np
from bokeh.models import Arrow, OpenHead
from bokeh.plotting import figure, show, output_file

x = np.linspace(0.1, 5, 100)

p = figure(title="log axis example", y_axis_type="log", y_range=(0.001, 10**22))
p.line(x, np.sqrt(x), legend="y=sqrt(x)", line_color="tomato", line_dash="dotdash")

arrow1 = Arrow(end=OpenHead(size=15, line_color='black'), line_color='black', x_start=1, x_end=4, y_start=10**13, y_end=10**13)
arrow2 = Arrow(end=OpenHead(size=15, line_color='black'), line_color='black', x_start=1, x_end=4, y_start=10**13, y_end=10**13)
p.add_layout(arrow1)
p.add_layout(arrow2)

arrow1.y_end = 10**16

output_file("logplot.html", title="log plot example")

show(p)

By modifying code 2 into having a button, like code 1 did, the same error persists.

import numpy as np
from bokeh.models import Arrow, OpenHead
from bokeh.plotting import figure, show, output_file
from bokeh.models.widgets import Button
from bokeh.models import ColumnDataSource
from bokeh.layouts import layout
from bokeh.io import curdoc

x = np.linspace(0.1, 5, 100)

p = figure(title="log axis example", y_axis_type="log", y_range=(0.001, 10**22))

source = ColumnDataSource(data=dict(x=x, y=np.sqrt(x)))
p.line('x', 'y', source=source, line_color="tomato", line_dash="dotdash")

arrow1 = Arrow(end=OpenHead(size=15, line_color='black'), line_color='black', x_start=1, x_end=4, y_start=10**13, y_end=10**13)
arrow2 = Arrow(end=OpenHead(size=15, line_color='black'), line_color='black', x_start=1, x_end=4, y_start=10**13, y_end=10**13)
p.add_layout(arrow1)
p.add_layout(arrow2)


def btn():
    variable_list = list(np.random.randint(11, size=100)) #dummy data
    hist, edges = np.histogram(variable_list, density=True, bins='auto')
    source.data = dict(x=x, y=np.sqrt(x))
    arrow1.y_end = 10**16

button = Button(label='run')
button.on_click(btn)

l = layout([[p, button]], sizing_mode='fixed')

curdoc().add_root(l)

If you comment out the first three lines in the btn() function in code 1, the problem persists, so it's not because of ColumnDataSource being updated. By setting arrow.y_end = 0.1 outside the btn() function, the code works. So it seems that you can't update an arrow by use of a function, which hasn't been an issue for me when updating factors. Is this an issue with the Arrow component?

Stack traceback and/or browser JavaScript console output

[bokeh] setting log level to: 'info'
connection.js:192 [bokeh] Websocket connection 0 is now open
widget_box.js:109 [bokeh] WidgetBox mode is fixed, but no width specified. Using default of 300.
embed.js:263 Bokeh items were rendered successfully

Screenshots or screencasts of the bug in action

@pallgj
Copy link
Contributor Author

pallgj commented Oct 27, 2017

This is definitely a bug. I found an example for redrawing annotations on the mailing list, modified it slightly by adding an arrow:

from bokeh.io import curdoc
from bokeh.layouts import row, widgetbox
from bokeh.models import Slider, Span, Label, Arrow, OpenHead
from bokeh.plotting import figure
 
slider = Slider(start=0, end=10, value=3, step=0.1, title='Slider')
 
plot = figure(width=700, height=250, x_range=(0,10), y_range=(-1, 1))
span = Span(location=slider.value, dimension='height')
plot.add_layout(span)
label = Label(x=slider.value, y=0, x_units='data', y_units='data',
                 text="Minimum")
plot.add_layout(label)
arrow = Arrow(end=OpenHead(size=15, line_color='black'), line_color='black', 
	x_start=0, x_end=slider.value, y_start=0, y_end=0)
plot.add_layout(arrow)
 
def update_annotations(attr, old, new):
    span.location = new
    label.x = new
    arrow.x_end = new
 
slider.on_change('value', update_annotations)
 
curdoc().add_root(row(plot, widgetbox(slider)))

The slider redraws span and the label, but doesn't redraw the arrow.

@pallgj
Copy link
Contributor Author

pallgj commented Oct 27, 2017

Update: I found a way around it by using a separate ColumnDataSource for the arrow, see code below. I won't close the issue since I still consider not being able to update by arrow.x_end a bug. There may not be a need to fix it though since it can be modified this way.

from bokeh.io import curdoc
from bokeh.layouts import row, widgetbox
from bokeh.models import Slider, Span, Label, Arrow, OpenHead, ColumnDataSource
from bokeh.plotting import figure
 
slider = Slider(start=0, end=10, value=3, step=0.1, title='Slider')
 
plot = figure(width=700, height=250, x_range=(0,10), y_range=(-1, 1))
span = Span(location=slider.value, dimension='height')
plot.add_layout(span)
label = Label(x=slider.value, y=0, x_units='data', y_units='data',
                 text="Minimum")
plot.add_layout(label)

arrowsource = ColumnDataSource(data=dict(x_end=[slider.value]))
arrow = Arrow(end=OpenHead(size=15, line_color='black'), line_color='black', 
	x_start=0, x_end='x_end', y_start=0, y_end=0, source=arrowsource)
plot.add_layout(arrow)
 
def update_annotations(attr, old, new):
    span.location = new
    label.x = new
    arrowsource.data = dict(x_end=[new])
 
slider.on_change('value', update_annotations)
 
curdoc().add_root(row(plot, widgetbox(slider)))

@bryevdv
Copy link
Member

bryevdv commented Mar 17, 2018

Sorry this missed triage earlier, agree it is a bug

@bryevdv bryevdv added this to the 0.12.x milestone Mar 17, 2018
@bryevdv bryevdv modified the milestones: 0.13.x, short-term Sep 11, 2018
@anthonydouc
Copy link
Contributor

Following diff solves the issue, although not exactly pleasant to allow for updating all 4 coordinates.

index 7c2f2d8..ca8ade7 100644
--- a/bokehjs/src/lib/models/annotations/arrow.ts
+++ b/bokehjs/src/lib/models/annotations/arrow.ts
@@ -35,6 +35,10 @@ export class ArrowView extends AnnotationView {
     this.connect(this.model.source.streaming, () => this.set_data(this.model.source))
     this.connect(this.model.source.patching, () => this.set_data(this.model.source))
     this.connect(this.model.source.change, () => this.set_data(this.model.source))
+    this.connect(this.model.properties.x_start.change, () =>this.set_data(this.model.source))
+    this.connect(this.model.properties.x_end.change, () =>this.set_data(this.model.source))
+    this.connect(this.model.properties.y_start.change, () =>this.set_data(this.model.source))
+    this.connect(this.model.properties.y_end.change, () =>this.set_data(this.model.source))
   }

@sam0458
Copy link

sam0458 commented Sep 20, 2019

This example with Arrow and Slider does not update Arrow in both 1.0.4 and 1.3.4 versions. "Segment' works.
How to update Arrow from function?

@bryevdv
Copy link
Member

bryevdv commented Sep 20, 2019

@sam0458 The example in #7118 (comment) works for me with 1.3.4 The example updating from a source does not. Please open a new issue for the latter case (will be easier for us to track in a new issue that links back here)

@sam0458
Copy link

sam0458 commented Sep 20, 2019

Thanks. I will open the new issue. At least not from source works.

@sam0458
Copy link

sam0458 commented Sep 20, 2019 via email

@bryevdv
Copy link
Member

bryevdv commented Sep 20, 2019

I think you would have to stick to a version before this regression.

@anthonydouc
Copy link
Contributor

Might be able to look into this if its not already.

@sam0458
Copy link

sam0458 commented Oct 16, 2019 via email

@anthonydouc
Copy link
Contributor

Ok if you dont get around to it in the next few weeks I will take a look.

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

Successfully merging a pull request may close this issue.

4 participants