Bokeh: CustomJS TextInput callback to adjust x axis range - javascript

I'm trying to make a web page that has a plot powered by an AjaxDataSource object. However, I'd like to have a TextInput widget that can be used to changed the xrange of this plot. Below is a snippet:
source = AjaxDataSource(data={"time": [], "temperature": [], "id": []},
data_url='http://localhost:6543/AJAXdata',
polling_interval=100,
mode='append')
livePlot = figure(x_axis_type="datetime",
x_range=[startDt, endDt],
y_range=(0,25),
y_axis_label='Temperature (Celsius)',
title="Sea Surface Temperature at 43.18, -70.43",
plot_width=800)
livePlot.line("time", "temperature", source=source)
....
updateStartJS = CustomJS(args=dict(xrange=livePlot.x_range), code="""
var startStr = cb_obj.value
alert(startStr)
var newStartMilliSeconds = Date.parse(startStr)
alert(newStartMilliSeconds)
alert(xrange)
alert(xrange.start)
xrange.start = newStartMilliSeconds
alert(xrange.start)
xrange.change.emit();
""")
startInput = TextInput(value=startDt.strftime(dateFmt), callback=updateStartJS)
See this file and the bokeh_ajax() function for the complete implementation: https://github.com/hhprogram/PyramidSite/blob/master/webgraphing/views/ajaxView.py
When I run it and change the corresponding 'Start' textInput box. The CustomJS runs accordingly and per the alerts I have seen that it is capturing the correct new data (assuming you put in an ISO Formatted date like YYYY-mm-dd) but it fails to update the plot axis range (ie the plot doesn't change at all). How would I implement this? (I want to maintain the plots to have underlying AjaxDataSources as well and not use bokeh server - I already know how to implement this type of axis change functionality if running a bokeh server.)

For anyone curious, found my issue. Think the main problem was I was not putting the widget which I wanted to use to control the plot xrange and the actual plot itself within the same layout object. Therefore, when I was calling components on the plot object it didn't include the widget. Then when I included the widget with the plot it worked. See below updates and the updated github repo:
(credit to this post for significantly helping me: Flask + Bokeh AjaxDataSource)
complete file: https://github.com/hhprogram/PyramidSite/blob/master/webgraphing/views/ajaxView.py)
code snippet:
source = AjaxDataSource(data={"time": [], "temperature": [], "id": []},
data_url='http://localhost:6543/AJAXdata',
polling_interval=100,
mode='append')
livePlot = figure(x_axis_type="datetime",
x_range=[startDt, endDt],
y_range=(0,25),
y_axis_label='Temperature (Celsius)',
title="Sea Surface Temperature at 43.18, -70.43",
plot_width=800)
livePlot.line("time", "temperature", source=source)
jsResources = INLINE.render_js()
cssResources = INLINE.render_css()
updateStartJS = CustomJS(args=dict(plotRange=livePlot.x_range), code="""
var newStart = Date.parse(cb_obj.value)
plotRange.start = newStart
plotRange.change.emit()
""")
updateEndJS = CustomJS(args=dict(plotRange=livePlot.x_range), code="""
var newEnd = Date.parse(cb_obj.value)
plotRange.end = newEnd
plotRange.change.emit()
""")
startInput = TextInput(value=startDt.strftime(dateFmt), title="Enter Date in format: YYYY-mm-dd")
startInput.js_on_change('value', updateStartJS)
endInput = TextInput(value=endDt.strftime(dateFmt), title="Enter Date in format: YYYY-mm-dd")
endInput.js_on_change('value', updateEndJS)
textWidgets = row(startInput, endInput)
# NOTE: this is important. Need to have the widgets and plot within same object that is the argument for components() method
layout = column(textWidgets, livePlot)
script, div = components(layout)

Related

How to move the mouse with webshot function inside a dygraph widget

I'm stuck because I can not achive what I want with a dygraph widget created in R.
I have this time series.
#library(xts)
dts <- xts::xts(c(10508,8465,3175,3816,4532,2735,2534,9541,8253,9962),
order.by = seq(from = as.Date("2022-02-01"), to = as.Date("2022-11-01"), by = "month"))
I can plot it in a dygraph widget
#library(dygraph)
object <- dygraph((dts),
ylab = "") %>%
dyRangeSelector(height = 20, strokeColor = "") %>%
dyOptions(fillGraph = FALSE, stackedGraph = FALSE, drawGrid = FALSE, strokeWidth = 3) %>%
dyHighlight(highlightSeriesOpts = list(strokeWidth = 3,highlightCircleSize = 10))
and save it in a html page.
#library(htmlwidgets)
saveWidget(object, "temp.html", selfcontained = FALSE)
Now, I would like to take a screenshot of the plot. I know I can do it with
webshot::webshot(url = "images/temp.html", file = "screenshot.png")
No problem with that. But I should hover the mouse near the last data point before the screenshot, because I would like the chart to show the information of the last point in the legend.
I have tried with
webshot::webshot(url = "images/temp.html", file = "screenshot.png"),
eval = "this.mouse.click(1781, 109);")
I got the X,Y coordinates injecting the following code in the inspection frame of the page.
<html onclick="display(event)">
function display(event) {
let X = event.clientX;
let X = event.clientX;
alert = (X + Y);
}
But it does not seem to work.
I get
but I would like something like this
Actually, I would like to hover the last point regardless the time series.
I know it could be done with ggplot and save me a lot of steps but the dygraph is mandatory and I would like to get the static plot from it.
I know also that it is maybe more of a javascript or casperjs question. If so I wouldn't mind repeat the question in the appropriate forum.
In advance, thank you very much for your help.

How to match up category labels with multiple series?

I'm working on a project to brush up on my JS, and I'm finding Highcharts rather challenging. What I've done is set up project that pulls in current JSON data from an API, and displays results on a map. When you click on a state, you can view the historical data for that state. if you shift click, you can view more than one state.
My x-axis is formatted with dates from each state, as not each state began tracking data at the same time. When multiple states are selected, the information is incorrect because even though they all have the same date for the most recent data point (today), the first data point in the date array varies. For instance, if you click New York, their first data point starts on 3/04, but if you click Connecticut, the first data point starts on 3/07.
Is there a way I can reconcile this? Can I have my categories start from the most recent data point and work backwards, so the data points for today are concurrent?
Here's my pen: https://codepen.io/maxpalmer/pen/rNVRzVX?editors=0010
Stackoverflow is requiring I post some code, so here is the function I wrote that reassembles the api data into an array for each state for the area chart:
for (i = 0; i < stateAbbrevs.length; i++){
var values = new Array(), categories = new Array();
// var categories = new Array();
var state = stateAbbrevs[i];
var stateObj = jsonData.filter(obj => obj.state == state);
for (x = 0; x < stateObj.length; x++) {
var value = stateObj[x].positive;
var date = formatDate(stateObj[x].date);
var name = stateNames[i];
values.push(value);
categories.push(date);
}
values.reverse();
categories.reverse();
historicData[state] = {
name: name,
data: values,
categories: categories
};
}
}```
Ah, found it in the myriad Highcharts documentation. Comes down to reversing my data array, and then reversing it in the highcharts x-axis options.
https://api.highcharts.com/highcharts/xAxis.reversed

HighChart with more than 50 data points breaks

I am trying to create a bubble chart using the JS HighChart in Angular2+. Whenever there are more than 50 data points (bubbles), the graph breaks. There are the correct number of bubbles in the correct positions (x,y plots) with all different colors but the sizes are all the same even though the z-values are all different. (I am outputing the z-values in a tooltip and the z-values are accurate)
This function is how I am passing in data to the high-chart configuration.
setSeries() {
this.objData = []
this.Data.forEach(element => {
var x= element['xVal'];
var y = element['yVal'];
var z = element['zVal'].toFixed(0);
var name = element['seriesName'].trim();
var newData =[{
x:x,
y:y,
z:+z,
}]
// SetSeriesData is how i am creating the obj to pass into series=[] in highchart configuration
if(i<50) //If I comment this condition, the graph breaks. Right now, the graph is working properly
this.setSeriesData(sumData, name, this.objData)
i++
})
this.options.series = this.objData;
this.generateChart();
}
This is my setSeriesData function.
setSeriesData(graphData: any, dataName: any, objData: any){
var obj = {};
obj['name'] = dataName;
obj['data'] = graphData;
obj['events'] = {click: function(e) {
//takes me to another link
}};
objData.push(obj)
}
In the above function, I configured the chart so that when you click the bubble, it takes you to another page. When the data points >50, this click functionality is not working either. In addition, the fillOpacity is not correct.
Just a few things to point out
1. I am using Angular 2+
2. The discovered issues are, fillOpacity, click, and size based on z-value.
3. It works perfectly when the data points are less than 50
How can I fix this?

Why google candlestick fallingColor and risingColor are not working for this?

I am working on Google Visulization charts .
I am trying to draw candlestick charts with sample data , the issue i am facing is that the falling color and raising color are being represented in single color only
This is my code
var mydata = [['13-Oct',1109.95,1132,1097.95,1113.45],['14-Oct',1113.45,1117,1095.6,1101.15],['15-Oct',1116,1132,1092.1,1129.2],['16-Oct',1130,1182.4,1130,1170.3],['19-Oct',1174,1182.2,1144.5,1162.15]];
function drawChart() {
var data = google.visualization.arrayToDataTable(mydata, true);
var options = {
legend:'none',
colors:['red','brown'],
candlestick: {
fallingColor:{ fill: "orange", strokeWidth:0.5,stroke:'black'},
risingColor:{fill:"yellowgreen",strokeWidth:0.5,stroke:'black'}}
};
var chart = new google.visualization.CandlestickChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
and this is my fiddle
http://jsfiddle.net/pdmpb9w1/7/
Could you please let me know how to resolve this issue ??
Like Kevin Brown said, the problem is with your data. Your data should be structured like so:
var mydata = [
//category start err start end end err
['13-Oct', 1109.95, 1132, 1097.95, 1113.45],
['14-Oct', 1113.45, 1117, 1095.6, 1101.15],
['15-Oct', 1116, 1132, 1092.1, 1129.2],
['16-Oct', 1130, 1182.4, 1130, 1170.3],
['19-Oct', 1174, 1182.2, 1144.5, 1162.15]
];
As you can see, all the values in the end column are smaller than the values in the start column, so all the candlesticks are colored as though falling.
On top of that, all your start err values are smaller than your start value, so you're not seeing the error/tolerance line because its hidden behind the bar. Vice versa for the end values.
I have no idea how your data should be ordered, but if I had to guess it would be something like this:
var mydata = [
// note the first two numbers are swapped with the second two
['13-Oct', 1097.95, 1113.45, 1109.95, 1132],
['14-Oct', 1095.6, 1101.15, 1113.45, 1117],
['15-Oct', 1092.1, 1129.2, 1116, 1132],
['16-Oct', 1130, 1170.3, 1130, 1182.4],
['19-Oct', 1144.5, 1162.15, 1174, 1182.2]
];
Which would render the following:
JSFiddle

Manually Add Nodes to JavaScript InfoVis Toolkit Force Directed Graph

I am attempting to use the JavaScript InfoVis Toolkit found here: JS InfoVis ToolKit to create a Force Directed Graph. We don't really want to use a JSON to "feed" the data to the graph -- instead we would rather manually add nodes.
I have put together the following code -- but when I attempt to draw the graph my root node is not found in line 7118 of jit.js (var root = aGraph.getNode(id);). I have omitted the specifics on my ForceDirected options -- but those should not affect the result.
fd = new $jit.ForceDirected({...})
//Create main node
var rootNode = { id: "root", name: "Actors", data: { "$color": "#557EAA"} }
fd.root = rootNode;
fd.graph.addNode(rootNode);
$.each(array, function (index, art) {
var pubId = art.pubMedId.toString();
var labelText = "Article " + pubId;
var node = { id: pubId.toString(), name: labelText, data: { "$color": "#557EAA"} }
//Create Nodes -- connect them to main node for now
fd.graph.addNode(node);
fd.graph.addAdjacence(rootNode, node, {});
text = text + art.pubMedId + ',';
});
//Display graph
fd.plot();
Does anyone have experience doing this?? Looking for guidance. I have debugged in FireBug and everything appears to be loaded into the graph correctly (ie - all nodes exist). I am at a loss.
Instead of fd.root = rootNode;, you want to use fd.root = rootNode.id;. I was surprised by this as well.
Additionally, you'll probably want to initialize the Graph before adding the root node:
fd.graph = new $jit.Graph(fd.graphOptions, fd.config.Node, fd.config.Edge, fd.config.Label);
Note: tested with version 2.0.1.

Categories

Resources