I am trying to plot a trajectory in real-time using Javascript and Highcharts. The data will come from external sensors but for the moment I was practicing with this example:
http://jsfiddle.net/0fp1gzw8/1/
As you can see, the JS snippet tries to plot a circle using a cosine and a sine function:
load: function () {
var series = this.series[0];
setInterval(function () {
a = a + 0.1;
x = Math.sin(a),
y = Math.cos(a);
series.addPoint([x, y], true);
}, 100);
}
The problem is that once the point has crossed the x axes, the line segment is no more drawn between two consecutive samples, instead it connects the new sample with one of the old ones already plotted before:
How can I solve this and get a clean x-y plot?
Thanks
Highcharts expects spline/line chart data to always be sorted by the x value. With this expectation, when you call addPoint it looks like it draws the line segment to the previous x-value not the previously added point.
If you switch your code to use setData:
var data = [];
var series = this.series[0];
setInterval(function () {
a = a + 0.1;
x = Math.sin(a),
y = Math.cos(a);
data.push([x,y]);
series.setData(data, true);
}, 100);
it draws the line segments correctly but you get lots of these errors in the console:
Highcharts error #15: www.highcharts.com/errors/15
You might have better luck switching to a scatter chart that doesn't have this limitation. If you need the line segments, you could add them yourself with the Renderer.
Related
I am trying to recreate this visualization using p5.js. I have some trouble understanding how to create the coordinates for the new points and plot them on my canvas.
The data is a series of negative-positive values that need to be plotted below and above an X-axis respectively (from left to right). This is a sample:
"character","roll_value"
"Daphne Blake",0
"Daphne Blake",-1
"Daphne Blake",-1
"Daphne Blake",-5
"Daphne Blake",-3
"Daphne Blake",2
So I know that I have to map the values between a certain negative and positive height so I've demarcated those heights as follows:
let maxNegativeHeight = sketch.height - 120;
let maxPositiveHeight = sketch.height/4;
For mapping the input I thought of creating a new function called mapToGraph which takes in the roll_value, the old X position, max height and min height. This would map the old values to a new incremented X position and a vertical height:
const mapToGraph = (value, oldXPos, maxHeight, minHeight) => {
const newXPos = oldXPos + 10;
const newYPos = sketch.map(value, 0, maxHeight, minHeight, maxHeight);
return [newXPos, newYPos];
};
In my draw function, I am drawing the points as follows:
sketch.draw = () => {
for(let i = 0; i < data.getRowCount(); i++) {
let character = data.getString(i, "character");
if(character === 'Daphne Blake'){
console.log(character);
// Draw a horizontal line in the middle of the canvas
sketch.stroke('#F18F01');
sketch.line(0, sketch.height/2, sketch.width, sketch.height/2);
// Plot the data points
let value = data.getNum(i, "roll_value");
let [newX, newY] = mapToGraph(value, 0, maxNegativeHeight, maxPositiveHeight);
console.log(newX, newY);
sketch.strokeWeight(0.5);
sketch.point(newX, newY);
}
}
};
However, this does not plot any points. My console.log shows me that I am not processing the numbers correctly, since all of them look like this:
10 -3
cardThree.js:46 Daphne Blake
cardThree.js:55 10 -4
cardThree.js:46 Daphne Blake
cardThree.js:55 10 -4
cardThree.js:46 Daphne Blake
What am I doing wrong? How can I fix this and plot the points like the visualization I linked above?
Here is the full code of what I've tried (live link to editor sketch).
This is the full data
In your code newX is always 10 since you always pass 0 as the second argument to mapToGraph. Additionally the vertical displacement is always very small and often negative. Since you are using newY directly rather than relative to the middle of the screen many of the points are off screen.
I would like to add an horizontal line to an AmCharts4 Dumbbell plot. Since the x-axis is categorical, is it possible? The line must have different settings than the lines of the grid (e.g. larger, dashed, colored).
Found the way here.
var range = valueAxis.axisRanges.create();
range.value = 1000;
range.grid.stroke = am4core.color("#396478");
range.grid.strokeWidth = 2;
range.grid.strokeOpacity = 1;
range.grid.strokeDasharray = "6,3";
This works for other kinds of charts, of course.
I'm using D3 (v3) to build a plot with two axis. One of them it isn't working correctly when I add two or more objects. My piece of code is:
//Set upperLevelyScale
var previousValues = 0;
var upperLevelyScale = d3.scale.ordinal()
.domain(Object.keys(valuesY_numbers).sort())
.rangePoints((function(){
var values = Object.values(valuesY_numbers).map(function(x){
previousValues += (x * itemSize);
return previousValues});
values.unshift(0);
return values;
})());
when domain is ["MyValue1"] and rangePoints is [0, 170], the tick of the axis shows perfectly at the middle of the axis. But if domain is ["MyValue1", "MyValue2"] and rangePoints is [0,170,320] the ticks are not really covering their part but other.
What I'm trying to set up is just: MyValue1 is from 0 to 170, MyValue2 is from 170 to 320, etc. I have tried with '.range' also but still not working.
Thanks in advance.
I want to print two area charts in one diagram using dimple.js. I did it like this:
var svg = dimple.newSvg("#chart", svgWidth, svgHeight);
var chart = new dimple.chart(svg, data);
var xAxis = chart.addCategoryAxis("x", "DayOfMonth");
xAxis.title = null;
xAxis.addOrderRule("Date");
var yAxis = chart.addMeasureAxis("y", "Amount");
yAxis.title = null;
var series = chart.addSeries("Type", dimple.plot.area);
series.interpolation = "cardinal";
chart.draw();
Here is a JSFiddle I created: http://jsfiddle.net/7LoLLkfp/1/
The problem is that the two charts are above each other. When you look at the last value for DayOfMonth 20. Views should be at 6 and Likes should be at 4. In my case likes are drawn at 6 + 4 = 10.
How can I correctly draw two area charts in one diagram without stacking them above each other?
Set series.stacked to false e.g.
var series = chart.addSeries("Type", dimple.plot.area);
series.interpolation = "cardinal";
series.stacked = false;
chart.draw();
If you want to change the order set an addOrderRule
series.addOrderRule(["Views", "Likes"]);
or
series.addOrderRule(["Likes", "Views"]);
I think the issue is using stacked area charts. To display the area it will stack one on top of the other. You are probably better using a different chart type such as line
I have converted a line chart into a cumulative line chart and its y values are not displayed correctly. The range of the y axis should be 80.00 - 140.00 but instead I get -0.08 - 0.20. Has anyone managed to tweak their normalization code below to make it work with all kinds of ranges?
line.values = line.values.map(function(point, pointIndex) {
point.display = {
'y': (lines.y()(point, pointIndex) - v) / (1 + v)
};
return point;
})
Any help will be greatly appreciated.
I know that this question is somewhat old, but I am convinced that the normalization code for the cumulative line chart is not conceptually correct. Furthermore, the NVD3 cumulative line chart implementation is actually an index chart implementation (see Mike Bostock's example). A cumulative line chart would be more like this, I think. The cumulative chart can be easily achieved using the NVD3 line chart and some quick modifications to the underlying data.
If we take Bostock to be correct, and we really do wish to achieve an indexed line chart, then the indexify function in NVD3 should be changed to:
/* Normalize the data according to an index point. */
function indexify(idx, data) {
if (!indexifyYGetter) indexifyYGetter = lines.y();
return data.map(function(line, i) {
if (!line.values) {
return line;
}
var indexValue = line.values[idx];
if (indexValue == null) {
return line;
}
var v = indexifyYGetter(indexValue, idx);
// TODO: implement check below, and disable series if series
// causes a divide by 0 issue
if ((Math.abs(v) < 1e-6) && !noErrorCheck) {
// P.S. You may have to set a higher threshold (~1e-6?).
// I don't know I didn't run any tests...
line.tempDisabled = true;
return line;
}
line.tempDisabled = false;
line.values = line.values.map(function(point, pointIndex) {
point.display = {
'y': (indexifyYGetter(point, pointIndex) - v) / v
};
return point;
});
return line;
})
}
I asked a related question to the authors of NVD3 and plan to submit a pull request. Note that percentage change charts are really only meaningful when all of the underlying data is positive. When you start throwing negative values into the mix, percentage change loses all of its meaning.
What I found works is to insert another point with a y value of 0 at the beginning of the sequence of points.
Given a list of data points in the form [ [x1,y1], [x2,y2], ... [xn,yn]] ],
something like values.upshift([0,0]) works for me (the x value is arbitrary, but i just use 0 or values[0][0]) to insert to the front of the list.
(I'm getting the same thing with that chart. I'm still looking into it, but I hope this helped.)