Using CDSView in bokehjs api - bokeh

I would like to give a bokeh visualization to a friend to let him explore data.
For simplicity, I intend to give him a .html file: all callbacks must be in JS.
But I have not found how to use CDSView in bokehjs api
Here is an example with different -not working- leads:
from bokeh.plotting import figure
from bokeh.io import output_file, save
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, CDSView, GroupFilter
from bokeh.models import CheckboxGroup, CustomJS
template = """
{% block postamble %}
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-2.4.2.min.js"></script>
{% endblock %}
"""
output_file(filename="Visu.html", title='Visualisation', mode='cdn')
# get data
source = ColumnDataSource(dict(
x=[1, 2, 3, 1, 2, 3],
y=[1, 4, 9, 1, 2, 3],
category=['square', 'square', 'square', 'lin', 'lin', 'lin']))
view = CDSView(source=source,
filters=[
GroupFilter(column_name='category', group="lin"),
])
# plot
plot = figure(title="Comparison")
plot.scatter(x="x", y="y", source=source, view=view)
# code for selection of data in js
labels = ["lin", "square"]
checkbox_group = CheckboxGroup(labels=labels, active=[0])
my_js_code = """
// clear array of glyphs (=remove curves)
plot.renderers.length = 0;
// draw selection
let selected = checkboxes.active.map(i=>checkboxes.labels[i]);
for(let indice in selected) {
let name = selected[indice];
// create new view
var my_view = new Bokeh.CDSView({
source: my_source,
filters: [new Bokeh.GroupFilter({column_name: 'category', group: name})]
});
// -- ADDING new curve
// Does not work : "plot.scatter not a function"
//plot.scatter({field: "x"}, {field: "y"}, {source:my_source, view: my_view});
// Work, but no CDSView
var new_glyph = new Bokeh.Scatter({
x: { field: "x" },
y: { field: "y" },
view: my_view // useless
});
plot.add_glyph(new_glyph, my_source); // no CDSView : draw whole source
// plot.add_glyph(new_glyph, my_source, my_view); // no error, but doesn't work : draw whole source
//plot.add_glyph(new_glyph, my_source, view=my_view); // ReferenceError: assignment to undeclared variable view
}
// update
plot.change.emit();
"""
checkbox_group.js_on_change("active", CustomJS(code=my_js_code, args=dict(my_source=source, plot=plot, checkboxes=checkbox_group)))
save(row(checkbox_group, plot), "visu.html", template=template)
How could we use CDSView in JS callback ?
Thanks for your suggestions !

Related

How to get WFS from Geoserver localhost:8080 to OpenLayers localhost:1234

I am trying to get the map of contiguous US that appears as a pre-installed topp:states layer in my local laptop installation of Geoserver 2.19.1. I want it to appear as a vector layer on a localhost port. I actually started with the openlayers example at https://openlayers.org/en/latest/examples/vector-wfs.html, and got that example to work nicely, appearing as it should at http://localhost:1234, but for other layers, taken from external websites. With some effort I found the needed modifications that I expected to work for the Geoserver topp:states layer obtained from localhost:8080, but I just couldn't seem to make it appear at localhost:1234
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON';
import Map from 'ol/Map';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import {Stroke, Style} from 'ol/style';
import {Vector as VectorLayer} from 'ol/layer';
import {bbox as bboxStrategy} from 'ol/loadingstrategy';
var vectorSource = new VectorSource({
format: new GeoJSON(),
url: 'http://localhost:8080/geoserver/wfs?service=WFS&' +
'version=1.1.0&request=GetFeature&typename=topp:states&'+
'outputFormat=application/json&srsname=EPSG:3857&' +
'bbox=24.9,-124.8,49.5,-66.0',
});
var vector = new VectorLayer({
source: vectorSource,
style: new Style({
stroke: new Stroke({
color: 'rgba(0, 0, 0, 1.0)',
width: 2,
}),
}),
});
var map = new Map({
layers: [vector],
target: document.getElementById('map'),
view: new View({
center: [-10000000,4500000.0],
zoom: 4,
}),
});
Any help would be much appreciated.

Add custom values to Legend in lightningchart

I can create legends like below
Is there any way , I can add custom text dynamically in the place of Bollinger band ? For example I want to show live price every second in legend.
Also how do I programatically enable and disable a legend.
Thank you
You can store the legendbox entry returned by the legendBox.add() method. This entry has a method entry.setText() that can be used to set the text of the legend box entry to be what ever you want.
const legendBox = chart.addLegendBox()
const entry = legendBox.add(series, undefined, 'Legend Box')
entry.setText('Custom text here')
By storing the entry reference you can call the setText method when ever you want to update the text.
See the below example in which the legend box entry text is updated every time new data is added.
// Extract required parts from LightningChartJS.
const {
lightningChart,
DataPatterns,
Themes
} = lcjs
// Import data-generator from 'xydata'-library.
const {
createProgressiveTraceGenerator
} = xydata
// Create a XY Chart.
const chart = lightningChart().ChartXY({
// theme: Themes.dark
})
// Create progressive line series.
const series = chart.addLineSeries({
dataPattern: DataPatterns.horizontalProgressive
})
const lb = chart.addLegendBox()
lb.setPosition({
x: 50,
y: 50
})
const entry = lb.add(series, undefined, 'Legend Box')
// Generate traced points stream using 'xydata'-library.
createProgressiveTraceGenerator()
.setNumberOfPoints(1000)
.generate()
.toStream()
.forEach(data => {
series.add(data)
entry.setText(`Custom text: ${series.getLastPoint().y.toFixed(1)}`)
})
<script src="https://unpkg.com/#arction/xydata#1.4.0/dist/xydata.iife.js"></script>
<script src="https://unpkg.com/#arction/lcjs#2.2.1/dist/lcjs.iife.js"></script>
You can disable the legend box by calling legendbox.dispose(). This will remove the legendbox completely. To then enable the legendbox again you can call legendbox.restore() which will restore the legendbox as it was.

Open URL from bokeh, not using the taptool

I am looking to open a URL from bokeh using OpenURL, but from within a callback for a button, not using taptool. The code below reproduces the issue I'm running into i.e. I can open new tabs when using taptool with OpenURL, but nothing happens when I use OpenURL in a button callback.
(Much of the example is from the bokeh docs: http://docs.bokeh.org/en/0.12.5/docs/user_guide/examples/interaction_open_url.html)
from bokeh.models import ColumnDataSource, OpenURL, TapTool
from bokeh.models.widgets import Button
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import column, widgetbox
from bokeh.io import curdoc
p = figure(plot_width=400, plot_height=400,
tools="tap", title="Click the Dots")
source = ColumnDataSource(data=dict(
x=[1, 2, 3, 4, 5],
y=[2, 5, 8, 2, 7],
color=["navy", "orange", "olive", "firebrick", "gold"]
))
p.circle('x', 'y', color='color', size=20, source=source)
url = "http://www.colors.commutercreative.com/#color/"
taptool = p.select(type=TapTool)
taptool.callback = OpenURL(url=url)
button = Button(label="Generate", button_type="success")
def button_callback():
print('button callback')
OpenURL(url="http://www.google.com")
button.on_click(button_callback)
doc = curdoc()
doc.add_root(column([p,widgetbox(button)]))
doc.title = "Hello World"
Thank you!
OpenURL is a custom version of CustomJS, so it runs only in JavaScript. It's also a class and not a function - you can't just construct an object of class OpenURL, you also have to use its other methods to make it work.
With that being said, you cannot use it with Button since OpenURL expects a data source to replace all the placeholders in the URL. And Button can't have a data source.
Instead, what you need is a regular CustomJS:
b.js_on_click(CustomJS(args=dict(urls=['https://www.google.com',
'https://stackoverflow.com/']),
code="urls.forEach(url => window.open(url))"))
Note that how the solution above will work depends on your browser. E.g. in my case Google Chrome was opening only the first URL, and I had to explicitly allow pop-ups for the generated web page before it started to also open the second URL.
And you don't need bokeh serve to make it work - it will work even on a static web page generated by a call to save or show.

How to use FabricJS in Jupyter Notebook widget

I'm trying to build a widget in Jupyter Notebook that uses Fabric.js (http://fabricjs.com/), however I'm getting an error that is a blocker for me. The most basic solution I need is just to make the widget output a canvas with an interactive red rectangle, like what you find on the Fabric.js homepage:
What I've tried so far:
I started from the basic "Hello World" tutorial (https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Custom.html) which is the basis for the four cells below, and I tried to add a simple example from the fabric node webpage to create a red rectangle. Here are the cells I have in Jupyter notebook:
Cell 1:
%%HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min.js" type="text/javascript"></script>
Cell 2:
import ipywidgets as widgets
from traitlets import Unicode, validate
class HelloWidget(widgets.DOMWidget):
_view_name = Unicode('HelloView').tag(sync=True)
_view_module = Unicode('hello').tag(sync=True)
_view_module_version = Unicode('0.1.0').tag(sync=True)
Cell 3:
%%javascript
require.undef('hello');
define('hello', ["#jupyter-widgets/base"], function(widgets) {
var HelloView = widgets.DOMWidgetView.extend({
render: function() {
var canvas = document.createElement('canvas');
canvas.id = 'canvas';
canvas.width = 1000;
canvas.height = 500;
var ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
this.el.appendChild(canvas);
var fabricCanvas = new fabric.Canvas(canvas);
var rect = new fabric.Rect({
top : 100,
left : 100,
width : 60,
height : 70,
fill : 'red'
});
fabricCanvas.add(rect);
},
});
return {
HelloView : HelloView
};
});
Cell 4:
HelloWidget()
However, I unfortunately get the following error in the JS console and it doesn't make the red square:
Please help me fix the code to make it work!
My problem was I didn't understand how require.js works... :/
Here's how I fixed the problem:
%%javascript
require.undef('hello');
require.config({
//Define 3rd party plugins dependencies
paths: {
fabric: "https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min"
}
});
define('hello', ["#jupyter-widgets/base", 'fabric'], function(widgets) {...

My own defined colors for graphs in Kintone

I'd like to set my own defined colors for graphs that appear in Kintone.
I've found out for pie charts, you can upload the below CSS code to the App to have some areas of the pie to become a color of your choice.
.highcharts-series-group .highcharts-series path:nth-of-type(even){
fill:pink;
}
What I'd really like to do though, is apply the same thing to the Line charts in kintone.
I've tried the below CSS:
.highcharts-tracker path {
fill: red;
}
This only changes the points plotted on the graph, but not the lines in between the points.
How can I identify the lines in this graph so that I can end up with lines of the color of my choice??
Updated 6/24/18
Like you mentioned, the code that I showed you displays only on the record detail page. However, if you just make the process to run on the record list event "app.record.index.show", you can show the graph on the top of the record list page.
Also, it will be better to use kintone.app.getHeaderSpaceElement() to append a graph on the record list page.
The following page is an example of how to append something on the record list page using the kintone.app.getHeaderSpaceElement():
kintone developer network - kintone x OpenStreetMap
https://developer.kintone.io/hc/en-us/articles/115003669514
The following page is about the record list header element:
kintone developer network - Get Record List Header Element
https://developer.kintone.io/hc/en-us/articles/213148937-Get-Record-List#getHeaderSpaceElement
=================================================
Original Reply
It's better off not editing the DOM because it might not work after any kintone updates. I recommend creating a custom graph using Chart.js, a javscript library. The following page helps you how to do so.
Example Code
(function() {
"use strict";
// Events for adding and editing records
var eventsCreateShow = ['app.record.create.show', 'app.record.edit.show',
'app.record.index.create.show', 'app.record.index.edit.show'];
kintone.events.on(eventsCreateShow, function(event) {
// Hide the "Chart" Group field
kintone.app.record.setFieldShown('Chart', false);
});
// Display the chart on the record details page (PC and mobile)
var eventsDetailShow = ['app.record.detail.show', 'mobile.app.record.detail.show'];
kintone.events.on(eventsDetailShow, function(event) {
var record = event.record;
var data = {
labels: ["Language Arts", "Math", "Science", "Social Studies", "P.E."],
datasets: [
{
label: "My First dataset",
fillColor: "rgba(0,140,232,.4)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
data: [
record['language_arts']['value'],
record['math']['value'],
record['science']['value'],
record['social_studies']['value'],
record['pe']['value']
]
}
]
};
// Set Chart.js options
var options = {
scaleShowLine: true,
angleShowLineOut: true,
scaleShowLabels: true,
scaleBeginAtZero: true,
angleLineColor: "rgba(0,0,0,.1)",
angleLineWidth: 1,
pointLabelFontFamily: "'Arial'",
pointLabelFontStyle: "normal",
pointLabelFontSize: 16,
pointLabelFontColor: "#666",
pointDot: true,
pointDotRadius: 5,
pointDotStrokeWidth: 1,
pointHitDetectionRadius: 20,
datasetStroke: true,
datasetStrokeWidth: 3,
datasetFill: true,
responsive: true
};
var elRadar;
var elCanvas = document.createElement('canvas');
elCanvas.id = 'canvas';
// Display radar chart onto the Blank space
// Edit display size depending on PC or mobile
if (event.type === 'mobile.app.record.detail.show') {
elRadar = kintone.mobile.app.getHeaderSpaceElement();
elCanvas.style.position = 'relative';
elCanvas.style.top = '10px';
elCanvas.style.left = '10px';
elCanvas.height = '300';
elCanvas.width = '300';
} else {
elRadar = kintone.app.record.getSpaceElement('Radar');
elCanvas.height = '400';
elCanvas.width = '400';
}
elRadar.appendChild(elCanvas);
var myChart = new Chart(elCanvas.getContext("2d")).Radar(data, options);
});
})();
Ref:kintone developer network - Display radar charts with chart.js
https://developer.kintone.io/hc/en-us/articles/115006413388-Display-radar-charts-with-chart-js
I hope this helps

Resources