Bokeh EditTools callback to server - bokeh

I am trying to understand how to use callbacks for the new Bokeh EditTools (e.g. BoxEditTool or similar).
Specifically, I would like to see on the server side the coordinates of the newly added rectangles, but I am not sure how to do this.
I am running the following server app
def app( curdoc ):
TOOLS = "tap"
p = figure(title="Some Figure", tools=TOOLS)
source = ColumnDataSource( {'xs':[1], 'ys':[1], 'width':[.1],'height':[.1]})
r = p.rect('xs','ys','width','height', source=source)
p.add_tools(BoxEditTool( renderers = [r]))
def cb( attr, old, new ):
print(r.data_source.data)
r.data_source.on_change("selected", cb)
curdoc.add_root(column(p))
I do get printout from the cb when I select different rectangles, but the r.data_source.data does not change
Thanks for the help!

The behaviour you're describing is actually a bug in the current distribution of Bokeh (0.13.0). You can read more in the google groups discussion. To summarize, there was a problem with the synchronization of the data at the server, it has been resolved and merged.
Note that the on_change method for the Rect glyph ColumnDataSource should watch the 'data' attribute and not 'selected'.
Other than that your snippet looks good, but if you want a working example you can look here. This code is under development but at this stage it reads images and allows drawing ROIs, as well as a simple mechanism for serializing and loading them.
Hope this helps!

Related

Mapbox Bright wont render: Did I leave a command out?

Using Folium but cant render a map with a "Mapbox Bright" tiling. However I can render a "Stamen Toner" tiling. Am I leaving out a command?
Ran code on both windows and linux platforms,
in the cloud and local,
in both firefox and chrome.
libraries installed via pip install folium or conda install
Code should execute:
import webbrowser
import folium
world_map_stamen = folium.Map(location=[56.130, -106.35], tiles="Stamen Toner",zoom_start=4,height=500, width=1000)
world_map_mapbox = folium.Map(location=[56.130, -106.35], tiles="Mapbox Bright",zoom_start=4,height=500, width=1000)
world_map_stamen.save("mymap_stamen.html")
world_map_mapbox.save("mymap_mapbox.html")
webbrowser.open("mymap_stamen.html")
webbrowser.open("mymap_mapbox.html")
I expected both to work. Only one did. I must be forgetting something?
Found my own answer and this question has been answered elsewhere in various forms....
But it seem like there are two answers:
(1) Mapbox maps are no longer supported in folium 0.9 so Mapbox maps must be called using an attribution and custom tile call:
mymap = folium.Map(location=[30,-83], zoom_start=2,tiles= tileset_id,
attr="any text here")
where tileset_id = "http://api.mapbox.com/v4/mapbox.light/{z}/{x}/{y}.png?access_token=pk.xxx" (where pk.xxx is your API token from mapbox (go sign up))
see https://gis.stackexchange.com/questions/203062/how-do-i-use-mapbox-tiles-with-folium
(2) the tilesets that are free are listed in another post and no longer include mapbox bright. see
https://gis.stackexchange.com/questions/244788/map-ids-to-add-mapbox-basemaps-to-leaflet-or-openlayers

How to modify the DataLabel fill (using a solid fill color)?

I'm trying to edit the data labels for a chart I'm writing on the slide. I can access the text of the datalabel using the methods available but as of yet the datalabel.fill is not existent. Any workarounds welcome if this is not planned on being added to the library in the future.
I've already gone through the source code in the github (https://github.com/scanny/python-pptx) but the datalabel class only has the font, has_text_frame, position, text_frame, _dLbl, _get_or_add_dLbl, _get_or_add_rich, _get_or_add_tx_rich, _get_or_add_txPr, and _remove_tx_rich methods. No fill or line fill methods is available.
The script I'm running does something similar for cells in a table:
cell.fill.solid()
cell.fill.fore_color.rgb = color_list[((col>0)*1)][i%2]
I'm looking at replicating the functionality on datalabels for chart series, with code that looks like this:
label.fill.solid()
label.fill.rgb = RGBColor(0x9B,0xBB,0x59)
label.fill.alpha = Alpha(.2)
label.line.fill.solid()
label.line.rgb = RGBColor(0xF0,0xF0,0x00)
The expected output xml should put the following for data labels:
<c:spPr>
<a:solidFill>
<a:srgbClr val="9BBB59">
<a:alpha val="80000"/>
</a:srgbClr>
</a:solidFill>
<a:ln>
<a:solidFill>
<a:schemeClr val="F0F000"/>
</a:solidFill>
</a:ln>
</c:spPr>
Actual output is non-existent as there is no method to do this directly.
This feature is not yet implemented, but if it was implemented it would be a .format property on the DataLabel object.
Typically users will work around an API gap like this by adding what we typically call a "workaround function" to the client code that manipulates the underlying XML directly, in this case, to add an <c:spPr> subtree in the right place.
python-pptx can generally get you close as far as a parent element is concerned. In this case, it can get you to the <c:dLbl> element like this:
data_label = chart.series[0].points[0].data_label
dLbl = data_label._dLbl
print(dLbl.xml)
The leading underscore in ._dLbl is your hint that you're getting into internals and if things don't go well it's something you're doing wrong, not an issue to be reported.
The dLbl object is an lxml.etree._Element object and can be manipulated with that API. If you have a search on "python-pptx workaround function" you'll find some examples for how to create new elements and put them where you want them.
The .xml property available on any python-pptx XML element object is handy for inspecting the results along the way. opc-diag can also be handy for inspecting PPTX files generated by PowerPoint or python-pptx for analysis or diagnostic purposes.

How to execute callback only when the Bokeh slider is released

I have a slider that affects a line in a plot:
vline = Span(location=0, dimension='height')
plot.renderers.extend([vline])
callback = CustomJS(args=dict(vline=vline), code="vline.location = slider.value;")
slider = Slider(start=-5, end=5, value=0, step=.1, callback=callback)
callback.args["slider"] = slider
I would like to, beyond changing the line, also execute an operation, call it commit_line(), via JS, that POSTs the value (and later updates another plot).
I could make the callback above call commit_line(), but that is unsuitable because it will make a couple hundred calls to the server just by sliding the slider.
In UX, this is typically addressed by executing only the expensive operation on release (of the slider). Can this be achieved in Bokeh sliders? If yes, how?
UPDATE for the current Bokeh v2.3.0 version: You should use:
JS callback:
from bokeh.models import CustomJS, Slider
from bokeh.plotting import show
slider = Slider(start=0, end=10, value=5)
slider.js_on_change('value_throttled', CustomJS(code='console.log(this.value)'))
show(slider)
Python callback:
from bokeh.models import Slider
from bokeh.plotting import curdoc
slider = Slider(start=0, end=10, value=5)
slider.on_change('value_throttled', lambda attr, old, new: print(new))
curdoc().add_root(slider)
Please note that the answer below was given for an older Bokeh version
and doesn't apply anymore for the current Bokeh v2.3.0
Pass callback_policy = "mouseup" parameter to your Slider constructor.
So:
slider = Slider(start = 1,
end = 10,
value = 1,
step = 1,
callback_policy = 'mouseup')
It comes handy when consulting Bokeh documentation to expand the JSON Prototype to find out which attributes a method actually supports, many methods are namely inherited from the base classes. Please note that JSON Prototype refers to the BokehJS model so it is not guaranteed you find all those properties in the DOM model when inspecting the code e.g. in Google Chrome Developers Tools.
In Bokeh 2.2.0, try using the "value_throttled" property:
self.date_range.on_change("value_throttled", callback)
This is working for me for a DateRangeSlider - would expect similar behaviour from other Sliders based on inheritance hierarchy.

RangeSlider unexpeted attribute Bokeh

I am trying to use the RangeSlider within my Bokeh-application, initializing the object as so
from bokeh.models.widgets import RangeSlider
#RangeSlider
slider = RangeSlider(title="OAS slider", start=0, end=1000, value=(0,2000),
step=0.1)
When trying to compile the app I get the following error message:
AttributeError: unexpected attribute 'value' to RangeSlider, possible attributes are
callback, callback_policy, callback_throttle, css_classes, disabled, end,
height, js_callbacks, name, orientation, range, sizing_mode, start, step,
tags, title or width
I could change the code to use range instead as so
#RangeSlider altered inputs
slider = RangeSlider(title="OAS slider", start=0, end=1000, range=(0,2000),
step=0.1)
and it works.
However, as the example on the Bokeh-homepage found here
https://github.com/bokeh/bokeh/blob/master/examples/app/export_csv/main.py
used the value and works, I would be more eager to understand why I get the error message, rather than just changing to range... The example in the link also used the key word format, which obviously also generates the error above.
Could be a version issue. I am running Bokeh version 0.12.4
Thanks
This is a version issue. The RangeSlider was actually mostly broken for a long time, until we switched to a different underlying slider library to implement it. But some changes were necessary to make the switch. The correct property for 0.12.7 and newer is value and I would recommend to use that version or later if you want too use RangeSlider especially (0.12.4 is over a year old.)

R Need to restart RStudio to view and save in a file using dev.copy() and dev.off()

I am trying to create a plot and eventually save it as a file. But because I am making a lot of changes and want to test it out, I want to be able to view and save the plot at the same time. I have looked at this page to do what I want to do but in my system, it does not seem to be working as it is supposed to.
Here are my codes:
png('Save.png')
sample.df <- data.frame(group = c('A','B','A','C','B','A','A','C','B','C','C','C','B'),
X = c(2,11,3,4,1,6,3,7,5,9,10,2,8),
Y = c(3,8,5,2,7,9,3,6,6,1,3,4,10))
plot(Y ~ X, data = sample.df)
dev.copy(png, 'Save.png')
dev.off()
There are several issues (I am new to R so I might be missing something entirely):
(1) When I use png(), I cannot view the plot in RStudio so I used dev.copy() but it does not allow me to view my plot in R studio
(2) Even after I use dev.off(), I cannot view the saved file until I close the RStudio (says "Windows Photo Viewer can't open this picture because the picture is being edited in another program"). I need to restart every time so it is very inconvenient.
What am I doing wrong and how could I view and view saved file without restarting RStudio every time? Thank you in advance!
Addition
Based on Love Tätting's comments, when I run dev.list(), this is what I get.
> png('Save.png')
>
> sample.df <- data.frame(group = c('A','B','A','C','B','A','A','C','B','C','C','C','B'),
+ X = c(2,11,3,4,1,6,3,7,5,9,10,2,8),
+ Y = c(3,8,5,2,7,9,3,6,6,1,3,4,10))
>
> plot(Y ~ X, data = sample.df)
>
> dev.copy(png, 'Save.png')
png
3
> dev.off()
png
2
> dev.list()
png
2
> dev.off()
null device
1
> dev.list()
NULL
Why do I not get RStudioGD?
RStudio has its own device, "RStudioGD". You can see it with dev.list(), where it by default is the first and only one.
R's design for decoupling rendering and backend is by the abstraction of devices. Which ones you can use is platform and environment dependent. dev.list() shows the stack of current devices.
If I understand your problem correctly you want to display the graph first in RStudio, and then decide whether you want to save it or not. Depending on how often you save th image you could use the 'export' button in the plot pane in RStudio and save it manually.
Otherwise, your choice of trying to copy it would be the obvious one for me as well.
To my knowledge the device abstraction in R does not allow one to encapsulate the device as an object, so one for example could make it an argument to a function that does the actual plot. Since dev.set() takes an index as argument, passing the index as argument will be dependent on state of the stack of devices.
I have not come up with a clean solution to this myself and have sometimes retorted to bracketing the plot rendering code with a call to a certain device and saving it right after, and switching device depending on a global.
So, if you can, use RStudios export functionality, otherwise an abstraction would need to maintain the state of the global stack of devices and do extensive testing of its state as it is global and you cannot direct a plot call to a certain device, it simply plots to the current device (to my knowledge).
Edit after OP comment
It seems that it is somewhat different behaviour you are experiencing if you cannot watch the file after dev.off, but also need to quit RStudio. For some type of plot frameworks there is a need to call print on the graphical object to have it actually print to the file. Perhaps this is done by RStudio at shutdown as part of normal teardown procedures of open devices? In that ase the file should be empty if you forcibly look in its contents before quiting RStudio.
The other thing that sometimes work is to call dev.off twice. I don't know exactly why, but sometimes more devices get created than I have anticipated. After you have done dev.off, what does dev.list show?
Edit after OP's edit
I can see that you do, png(); dev.copy(); dev.off(). This will leave you with one more device opened than closed. You will still have the first graphics device that you started open as can be seen when you do the listing. You can simply remove dev.copy(). The image will be saved on dev.off() and should be able to open from the filesystem.
As to why you cannot see the RStudio graphics device, I am not entirely sure. It might be that other code is messing with your device stack. I would check in a clean session if it is there to make sure other code isn't tampering with the device stack. From RStudio forums and other SO questions there seem to have been plot pane related problems in RStudio that have resolved after updating RStudio to the latest. If that is a viable solution for you I would try that.
I've just added support for RStudio's RStudioGD device to the developer's version of R.devices package (I'm the author). This will allow you to do the following in RStudio:
library("R.devices")
sample.df <- data.frame(
group = c('A','B','A','C','B','A','A','C','B','C','C','C','B'),
X = c(2,11,3,4,1,6,3,7,5,9,10,2,8),
Y = c(3,8,5,2,7,9,3,6,6,1,3,4,10)
)
figs <- devEval(c("RStudioGD", "png"), name = "foo", {
plot(Y ~ X, data = sample.df)
})
You can specify any set of output target types, e.g. c("RStudioGD", "png", "pdf", "x11"). The devices that output to file will by default write the files in folder figures/ with filenames as <name>.<ext>, e.g. figures/foo.png in the above example.
The value of the call, figs, holds references to all figures produced, e.g. figs$png. You can open them directly from R using the operator !. For example:
> figs$png
[1] "figures/foo.png"
> !figs$png
[1] "figures/foo.png"
The latter call should show the PNG file using your system's PNG viewer.
Until I submit these updates to CRAN, you can install the developer's version (2.15.1.9000) as:
remotes::install_github("HenrikBengtsson/R.devices#develop")

Resources