D3 Range Based Filter - javascript

I am working on a D3 bar chart that would visualize a few ranges (massaged data already coming from somewhere else) and allow the user to select a number of ranges for filtering of their search criteria.
Fiddle here:
http://jsfiddle.net/qear2g9b/
The mechanics of it work pretty well I think. The part I am running into problems with, is capturing user input and mapping it to the data.
Once finished, the user should be able to select and drag a range (along the x axis) for the categories they would like to see. I am using d3.brush to let the user select an area on the chart (I haven't looked into how to get it to select the entire chart height yet). On endbrush I am capturing coordinates that I need to map back to the categories that were on the x axis.
Since it is an ordinal scale, it doesn't have invert, so I am kind of suck. Any help would be much appreciated.
Code snippet below:
function brushend() {
console.log("BRUSH END");
console.log(brush.extent());
var pos = brush.extent();
var out = [];
for (var i = 0; i<pos.length;i++) {
for (var j = 0; j<pos[i].length;j++) {
console.log(pos[i][j] + " " + x.invert(pos[i][j])); // Doesn't work because x doesn't have invert method
}
}
}

Related

Get visible points for a series in LightningChartJs

Exists a function in LightningChartJs to get all visible points from a line or point series in a chart?
If I zoom the chart I want to show something if no visible points available. In some cases I have breaks in my data.
For now I have to check the range and filter all points within this range, but that seems not to be very performant. I guess LC is aware of all the visible points and can give me that.
I would very much welcome any thoughts on the subject or other solutions. Thanks.
LightningChart JS doesn't track the data points that are visible at any time. So the method that you have used to solve the issue is the best way currently.
Something like this seems to be reasonably performant.
function getDataInRange(data, rangeStart, rangeEnd){
const inRangeData = []
const dataLength = data.length
let curPoint
for(let i = 0; i < dataLength; i += 1){
curPoint = data[i]
if(curPoint.x >= rangeStart && curPoint.x <= rangeEnd){
inRangeData.push(curPoint)
}
}
return inRangeData
}
On my personal machine it can process 1 million points in ~10ms ± 2ms. If you only want to know that a point is visible in the range then you could just break the loop as soon as a single point is in the visible range.
Late to the game but for anybody googling:
If you already have a chart defined and it happens to be named 'chart' (otherwise change chart to your chart's object name), you can track the visible start and end data points like this:
axisX = chart.getDefaultAxisX()
window.axisXScaleChangeToken = axisX.onScaleChange((s, e) => {
window.axisXVisibleDataRangeStart = s
window.axisXVisibleDataRangeEnd = e
})
let visiblePoints = [];
for(let i of cur.data){
if(i[0] > window.axisXVisibleDataRangeStart && i[0] < window.axisXVisibleDataRangeEnd) visiblePoints.push(i)
}
Every time the X axis is scaled/zoomed/moved, axisXVisibleDataRangeStart and axisXVisibleDataRangeEnd will change. You're then iterating over where your data points are stored (cur.data in my case and the example) and comparing: If timestamp is within range, push to visiblePoints.
(I am using OHLC where data[0] is the timestamp. Your comparison might be to an object array where {x:} is the value youre looking to compare. You get the idea.)
To remove the listener and stop the logging:
axisX.offScaleChange(window.axisXScaleChangeToken)

To show difference between two bars in high charts?

I want to show difference values in a new line between the two bar charts in high chart plugins, I've create simple bar chart in high charts, but I need to show difference between two bars in the new line.
I'm explaining this in below image, please refer following image.
please help me to fix this ,
Image 2,
i want to show that information in below format/design, is it possible in high charts?
Image 2
I've got as far as extracting the data from the table to calculate the differences. However, as the example has some negative differences e.g. -1, it will depend what graph you would like to put this information on as it would need to have a negative y axis.
The following jQuery code will exact all values, find the difference between the first and second and then add this to an array called diffChart.
var graphs = $('#datatable tbody tr');
var diffChart = [];
for (var i = 0, len = graphs.length; i < len; i++) {
var target = $('#datatable tbody tr').eq(i);
var bar1 = target.find('td').eq(0).text();
var bar2 = target.find('td').eq(1).text();
var diff = Number(bar1) - Number(bar2);
diffChart.push(diff);
}
You can view an example of the console log output in this jsfiddle
Sorry I couldn't be of much help past this.

dimple.js plots the wrong values

We are trying to develop a chart which plots a weather file with its corresponding relative humidity and temperature values. So far the chart generates itself correctly, and plots the current weather data based on your location, but it does not plot typical yearly weather data for the current location.
The correct array is written to console, but when handed to dimple to plot, the data that ends up on the chart is not the same as the data logged in console. it is usually significantly higher.
We are having trouble with the code starting on line 171.
See below link:
http://jsfiddle.net/jamesrowse/bnq419qx/1/
This could be a problem with a conflict between d3.csv and dimple, or dimple being handed such a large number of points to plot.
It is just the function starting from line 171 ending on line 193 that is giving us issues:
d3.csv("http://psychrometric.s3-website-us-east-1.amazonaws.com/HourlyWeatherFiles/GBR_London.Gatwick.037760_IWEC.csv", function (data) {
// console.log(data);
var hourlydata = [];
for (var i = 0; i < data.length; i++) {
//console.log(data[i]);
var rh = parseFloat(data[i].rh);
var dbt = parseFloat(data[i].dbt);
hourlydata.push({
"Relative Humidity": rh,
"Dry-Bulb Temperature": dbt,
"Moisture Content": psy.convert(rh, dbt, "rh", "w")
});
}
console.log("*********************************");
console.log(hourlydata);
var hourlySeries = myChart.addSeries("Relative Humidity", dimple.plot.bubble, [xAxis, yAxis]);
hourlySeries.data = hourlydata;
hourlySeries.radius= 3;
drawChart();
});
Any help would be appreciated
It is aggregating your series. It appears the default aggregation is to sum all records whenever the x-axis values match before displaying. You can override that behavior by defining an aggregation on your series as described here: https://github.com/PMSI-AlignAlytics/dimple/wiki/dimple.series#aggregate
Another thing you might want to explore is the 'stacked' option, though that doesn't appear to help for reasons I can't understand at the moment: https://github.com/PMSI-AlignAlytics/dimple/wiki/dimple.series#stacked

How to make a game out of an html table?

I'm basically trying to make a game that involves a grid. Here's what I have so far (it'll help to see the game before I explain what I need to happen):
Javascript (see jsfiddle for html):
var score = 0;
var points = function(val, box) {
var noise = Math.round(Math.round(0.1*val*Math.random()*2) - 0.1*val);
score = score + (val + noise);
var square = document.getElementById(box);
square.innerHTML = val + noise;
square.style.display='block';
setTimeout(function() {
square.style.display='none';
}, 400);
document.getElementById("out").innerHTML = score;
}
http://jsfiddle.net/stefvhuynh/aTQW5/1/
The four red squares at the bottom left of the grid needs to be the starting point in the game. When you click on one of those boxes, you can then travel along the grid by clicking adjacent boxes. Basically, I need to make it so that the player can only travel up, down, left, and right from the box that they just clicked on. I don't want the points function to be invoked when the player clicks on a box that they're not supposed to click on.
Additionally, I need to make it so that the player can't click on another box until 400 ms have elapsed.
I'm relatively new to programming so any help at all would be great. I would also appreciate tips on how to make the program more efficient, if there's a way to do that.
General idea:
I'd suggest having a similar id for all your boxes, such as box_x_y, and storing a list of strings, let's say allowedSquares.
You would then be able to write a function which, upon clicking on a box, would check if it's id is in allowedSquares, and if it is, call points(val, box) then update the contents of allowedSquares to reflect the change of position.
The point of using a standard id convention for all your boxes is that you could write getPosition(box) and getBox(intX, intY) that would parse the id strings to return you the box position, or vice-versa.
You can even make the updateAllowedSquares(clickedBox) function change the color of adjacent boxes to show they're allowed next steps.
EDIT: Some example code:
Disclaimer: these are not the code lines you're looking for.
This is only a starting kit for you, which assumes a 3x3 grid with a single-square bottom right starting position. You will have to adapt this code a bit. Also, I predict something will go wrong concerning going out of bounds. I'll let you think with this a bit, as I prefer giving food for thoughts over complete solutions in those cases...
var allowedSquares = ["box_2_2"]; // Initial list
function decodePositionFromID(boxId) {
return boxId.split("_").slice(1,2);
}
function getIDfromXY(x, y) {
return "box_" + x + "_" + y;
}
function updateAllowedSquaresList(boxID) {
// 1 - We clear the array.
allowedSquares.length = 0;
// 2 - We get the adjacent boxes IDs.
var xyArray = decodePositionFromID(boxId);
var upperBoxID = getIDfromXY(xyArray[0], xyArray[1]-1);
// Rince, repeat, and add some gameboard boundaries checks.
// 3 - We add the new IDs to the list.
allowedSquares.push(upperBoxID, ...);
}
function boxClick(val, boxID) {
// We check if the box is a valid square to play.
if (allowedSquares.indexOf(boxID) != -1) {
points(val, boxID);
updateAllowedSquaresList(boxID);
}
}

Simplifying SVG path strings by reducing number of nodes

I am generating a large SVG path string that represents a line chart.
Beneath the chart I have a slider for selecting a time range slice. Behind the slider is a mini preview of the whole line chart.
I am currently scaling down the path to generate the preview however in doing so I am ending up with tens of nodes per pixel and therefore far more detail then is necessary. Of course this gives the browser more rendering to do than it has to.
There is plenty of info available on compressing svg strings (gzipping etc), though little on algorithms that actually simplify the path by reducing the nodes.
I am using Raphaeljs and am looking for a javascript based solution. Any ideas?
Simplify.js is probably what you're looking after.
Given your line chart consists of straight line segments only (which by definition it should), you can use it like this:
var tolerance = 3
var pathSegArray = []
for (var i=0; i<path.pathSegList.numberOfItems; i++) {
pathSegArray.push(path.pathSegList.getItem(i))
}
var newPathArray = simplify(pathSegArray,tolerance)
var newD = "M";
for (i=0; i<newPathArray.length; i++) {
newD += newPathArray[i].x + " " + newPathArray[i].y + " "
}
path.setAttribute("d",newD)

Categories