Dynamically Add Data Points To Rickshaw Graph - javascript

So I'm using the Rickshaw graphing library and I was wondering how to dynamically add points to a graph.
I have a graph instantiated like this:
#seriesData = [ [], [], [] ]
random = new Rickshaw.Fixtures.RandomData(150)
for (var i = 0; i < 50; i++) {
random.addData(self.seriesData)
}
#graph = new Rickshaw.Graph(
element: document.getElementById("chart")
width: 550
height: 300
renderer: 'area'
series: [
{
color: "#c05020"
data: self.seriesData[0]
name: 'One'
}, {
color: "#30c020"
data: self.seriesData[1]
name: 'Two'
}, {
color: "#2791d7"
data: self.seriesData[2]
name: 'Three'
}
]
)
#graph.render()
hoverDetail = new Rickshaw.Graph.HoverDetail(
graph: self.graph
)
legend = new Rickshaw.Graph.Legend(
graph: self.graph
element: document.getElementById('legend')
)
shelving = new Rickshaw.Graph.Behavior.Series.Toggle(
graph: self.graph
legend: legend
)
axes = new Rickshaw.Graph.Axis.Time(
graph: self.graph
)
axes.render()
And I have data coming in through socket.io like this:
app.on('data',
(one, two, three) =>
// Dynamically add data points to graph
)
And I was wondering how to append these three points to the graph. I can't find any good documentation for this library. I know it's built on top of d3.js, but I'm not sure how to incorporate these methods into my graph.
Any help would be appreciated.

I envision two scenario that could solve your question:
Using the fixed Window Series for Streaming Data
leveraging the fact that arrays in javascript are passed by reference. A demo is available here
.
var data = [
{
data: [ { x: 0, y: 120 }, { x: 1, y: 890 }, { x: 2, y: 38 }, { x: 3, y: 70 }, { x: 4, y: 32 } ],
color: "#c05020"
}, {
data: [ { x: 0, y: 80 }, { x: 1, y: 200 }, { x: 2, y: 100 }, { x: 3, y: 520 }, { x: 4, y: 133 } ],
color: "#30c020"
}
];
var graph = new Rickshaw.Graph( {
element: document.getElementById("chart"),
renderer: 'line',
height: 300,
width: 800,
series: data
} );
var y_ticks = new Rickshaw.Graph.Axis.Y( {
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis'),
} );
graph.render();
$('button#add').click(function() {
data.push({
data: [ { x: 0, y: 200 }, { x: 1, y: 390 }, { x: 2, y: 1000 }, { x: 3, y: 200 }, { x: 4, y: 230 } ],
color: "#6060c0"
});
graph.update();
});

Related

Update tooltip data without reloading whole chart in Canvasjs

I want to update my Tooltip in my canvas js Chart without reloading the whole chart.
let arr = this.graph_arr;
let a = [];
let b = [];
arr.map((val) => {
val.data.map((val2) => {
b.push({
x: new Date(val2.date),
y: val2.revenue,
cn: val2.check_in,
rp: val2.rev_par,
arr: val2.avrr,
adr: val2.avg_daily_rate,
date: moment(val2.date).format('Do, MMMM'),
day: moment(val2.date).format('dddd')
})
})
a.push({
type: "spline",
name: val.channel_img.split('.')[0].toUpperCase(),
markerSize: 1,
showInLegend: true,
dataPoints: b,
label: val.channel_img,
})
b = [];
})
let chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
theme: "light2",
axisY2: {
valueFormatString: "1'%'"
},
axisY: {
suffix: "%"
},
axisX: {
gridThickness: 1,
valueFormatString: "DD/MMM"
},
legend: {
cursor: "pointer",
itemclick: this.toogleDataSeries
},
toolTip: {
shared: false,
content: this.selected == 'arr' ?
`<div style='\"'width: 210px;'\"'>ARR: {arr}, date: {date} </div>` :
this.selected == 'adr' ?
`<div style='\"'width: 210px;'\"'>ARR: {arr}, date: {date] </div>` : null,
cornerRadius: '8'
},
data: a
});
chart.render();
I have this Custom Tooltip. I want to change data in it from a dropdown without reloading. Currently I am using ternary operator and reloading chart. I want to change Tooltip content without reloading when user select from dropdown.
You can programmatically show toolip by using showAtX method. Below is an example:
var chart = new CanvasJS.Chart("chartContainer", {
title:{
text: "Show Tooltip based on dropdown"
},
data: [
{
type: "column",
dataPoints: [
{ x: 10, y: 71 },
{ x: 20, y: 55 },
{ x: 30, y: 50 },
{ x: 40, y: 65 },
{ x: 50, y: 95 },
{ x: 60, y: 68 },
{ x: 70, y: 28 },
{ x: 80, y: 34 },
{ x: 90, y: 14 }
]
}
]
});
chart.render();
var xVal = document.getElementById("xVal");
//Pass dataPoints as option to drop-down
for(var i=0; i<chart.options.data[0].dataPoints.length;i++){
var xValOption = document.createElement("option");
xValOption.text = chart.options.data[0].dataPoints[i].x = chart.options.data[0].dataPoints[i].x;
xVal.appendChild(xValOption);
}
xVal.addEventListener( "change", showTooltip);
//
function showTooltip(e){
if(xVal.value)
chart.toolTip.showAtX(Number(xVal.value));
else
chart.toolTip.hide();
}
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<div id="chartContainer" style="height: 360px; width: 80%; float: left"></div>
<div style="float: right; width: 15%">
Show Tooltip for <select id="xVal">
<option>Select</option>
</select>
</div>

Chart.js Multiple charts with one common legend

There are multiple charts on one page.
Each chart line is common.
I want to display a legend that is common to multiple charts like the figure.It shows and hides all chart lines with OnClick like the default legend.
THIS PICT IS FAKE
Is that possible? how?
I had tried Chart.js sync legend toggle on multiple charts, One legend, multiple charts Chart JS and etc.
But, those solutions have one chart with legend, and that legend affects other charts.
Should I hide the chart and show only the legend?
Should I draw a chart with no data?
I would be grad if you could tell me
HTML
<script src="https://rawgit.com/nnnick/Chart.js/v1.0.2/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.0.0-beta/Chart.js"></script>
<div>
<canvas id="myChartA"></canvas>
</div>
<div>
<canvas id="myChartB"></canvas>
</div>
JS
var ctxA = document.getElementById("myChartA").getContext("2d");
var ctxB = document.getElementById("myChartB").getContext("2d");
let data_A1 = [{
x: "2019-01-01 00:01:38",
y: "13.0"
},
{
x: "2019-01-01 01:01:39",
y: "11.0"
},
{
x: "2019-01-01 02:01:40",
y: "16.0"
},
{
x: "2019-01-01 03:01:41",
y: "15.0"
},
{
x: "2019-01-01 04:01:42",
y: "14.0"
}
];
var data_A2 = [{
x: "2019-01-01 00:01:42",
y: 14.671
}, {
x: "2019-01-01 01:01:42",
y: 13.691
}, {
x: "2019-01-01 02:01:42",
y: 16.691
}, {
x: "2019-01-01 03:01:42",
y: 17.691
}, {
x: "2019-01-01 04:01:42",
y: 18.691
}];
let data_B1 = [{
x: "2019-01-02 00:01:38",
y: "12.0"
},
{
x: "2019-01-02 01:01:39",
y: "11.0"
},
{
x: "2019-01-02 02:01:40",
y: "13.0"
},
{
x: "2019-01-02 03:01:41",
y: "14.0"
},
{
x: "2019-01-02 04:01:42",
y: "16.0"
}
];
var data_B2 = [{
x: "2019-01-02 00:00:00",
y: 14.671
}, {
x: "2019-01-02 01:01:42",
y: 13.691
}, {
x: "2019-01-02 02:01:42",
y: 16.691
}, {
x: "2019-01-02 03:01:42",
y: 15.691
}, {
x: "2019-01-02 04:01:42",
y: 14.691
}];
var myChartA = new Chart(ctxA, {
type: 'line',
data: {
datasets: [{
label: '1st Data',
data: data_A1,
borderColor: '#0f0',
showLine: true
}, {
label: '2nd Data',
data: data_A2,
borderColor: '#f00',
showLine: true
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
displayFormat: 'h:mm',
}
}]
}
}
});
var myChartB = new Chart(ctxB, {
type: 'line',
data: {
datasets: [{
label: '1st Data',
data: data_B1,
borderColor: '#0f0',
showLine: true
}, {
label: '2nd Data',
data: data_B2,
borderColor: '#f00',
showLine: true
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
displayFormat: 'h:mm',
}
}]
}
}
});
You can create a common legend and through generateLegend api, if both the datasets are similar.
First disable the default legends though the options
legend: {
display: false
}
Then use generateLegend() api to get the data labels and set it to a common element.
<ul class="legend">
</ul>
Then add event listeners to the generated elements and target all the charts
document.querySelector('.legend').innerHTML = myChartA.generateLegend();
var legendItems = document.querySelector('.legend').getElementsByTagName('li');
for (var i = 0; i < legendItems.length; i++) {
legendItems[i].addEventListener("click", legendClickCallback.bind(this,i), false);
}
function legendClickCallback(legendItemIndex){
document.querySelectorAll('.myChart').forEach((chartItem,index)=>{
var chart = Chart.instances[index];
var dataItem = chart.data.datasets[legendItemIndex]
if(dataItem.hidden == true || dataItem.hidden == null){
dataItem.hidden = false;
} else {
dataItem.hidden = true;
}
chart.update();
})
}
A sample pen is present here
https://codepen.io/srajagop/pen/yLBJOOo
Note I am using chartjs 2.8
If anyone using React version of Chartjs particularly react-chartjs-2, I have done it using React Hooks with react-chartjs-2, see the sandbox demo

Dynamicly update scatter/line chart in Chart.JS with multiple x/y grids

I would like to create a function that I can send data to push to my line chart. My function currently looks like this:
function addData(label, xp1, yp1, xp2, yp2) {
chart.data.labels.push(label);
chart.data.datasets.data.push({x: xp1, y: yp1}, {x: xp2, y: yp2});
chart.update();
}
label is a string
xp1, xp2, yp1, yp2 are doubles
I am running a loop that will execute this function. Nothing happens and my chart remains blank.
I have looked at the Chart.js docs and it doesn't seem to be helpful for my situation and it appears they have errors in their example code
This is my starting code:
var ctx = document.getElementById('chart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: [''],
datasets: [{}]
},
options: {}
});
This is what I expect it to look like once it's filled in:
var ctx = document.getElementById('chart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['a', 'b', 'c'],
datasets: [{
label: 'a',
fill: false,
data: [
{
x: 0,
y: 9
}, {
x: 3,
y: 9
}
]
},
{
label: 'a',
fill: false,
data: [
{
x: 3,
y: 7
}, {
x: 5,
y: 7
}
]
},
{
label: 'c',
fill: false,
data: [
{
x: 5,
y: 5
}, {
x: 10,
y: 5
}
]
}]
},
options: {}
});
You need to change your function this way:
function addData(label, xp1, yp1, xp2, yp2) {
chart.data.labels.push(label);
chart.data.datasets.push([{ label: label, fill: false, data: [ {x: xp1, y: yp1}, {x: xp2, y: yp2} ] }]);
chart.update();
};
You can directly access your data and update contents with:
chart.data.datasets[0].data.push( {x:5, y:2} ,{x:10, y:12},...,{x:50, y:25} );
which is easier if your want to maintain the series paint/color settings.

create a chart.js point dataset from json

I am trying to create a line plot from the json response from a webApi. I would like to create a time point dataset which looks like below:
var adddata = {
datasets: [{
label: "a",
backgroundColor: "rgba(255,0,0,0.5)",
fill: false,
data: [{
x: newDateString(0),
y: 22
}, {
x: newDateString(2),
y: 25
}, {
x: newDateString(4),
y: 12
}, {
x: newDateString(5),
y: 22
}],
}, {
label: "b",
backgroundColor: "rgba(0,255,0,0.5)",
fill: false,
data: [{
x: newDate(0),
y: 34
}, {
x: newDate(1),
y: 22
}, {
x: newDate(4),
y: 2
}, {
x: newDate(5),
y: 13
}]
}]
};
Now if I have a json which looks like:
{"Values":{"2018-01-17 09:24:34":"0","2018-01-17 09:24:31":"0","2018-01-17 09:24:33":"0","2018-01-17 09:24:35":"0"}}
Would it be possible to create a data set defining individual points?
You can parse your JSON string and transform resulting json object to dataset like below:
var json_str = '{"Values":{"2018-01-16 09:24:34":"10","2018-01-16 19:24:31":"5","2018-01-17 09:24:33":"8","2018-01-18 09:24:35":"9"}}'
var json = JSON.parse(json_str);
var data = [];
for (var d in json.Values) {
console.log(d, json.Values[d]);
data.push({
x : new Date(d),
y : json.Values[d]
})
}
var dataset = {
label : "c",
backgroundColor : "rgba(0,0,255,0.5)",
borderColor : 'green',
fill : false,
data : data
};
// add to existing datasets
adddata.push(dataset);
So this is the result: https://jsfiddle.net/beaver71/mfvc9p9x/

Adding data to empty rickshaw chart

I am charting different data with RickshawJS. But I need a way to update the chart when a user clicks the #search button. Right now it just creates a new chart below the old one, and that is pretty messy.
The user enters the page and enters some details and clicks the button to chart it. So ideally I'd like to start with an empty chart that isn't shown, but I can't really figure out how to remove the data from the chart and axes and then update it.
I could call $('#chart svg').remove(); on the chart and axes but it seems messy.
$('#search').click(function(event){
event.preventDefault();
var data = utils.malletData();
var graph = new Rickshaw.Graph( {
element: document.querySelector("#chart"),
width: 800,
height: 250,
series: [ {
name: data['name'],
color: 'steelblue',
data: data['series']
} ]
} );
graph.render();
var hoverDetail = new Rickshaw.Graph.HoverDetail( {
graph: graph,
xFormatter: function(x) {
var date = new Date(x).getTime();
return moment(x).format('MMMM Do YYYY, h:mm:ss a');
},
yFormatter: function(y) { return Math.floor(y) + " users" }
} );
var xAxis = new Rickshaw.Graph.Axis.X( {
graph: graph,
orientation: 'bottom',
element: document.getElementById('x_axis'),
tickFormat: function(x) { return moment(x).fromNow(); },
ticks: 7,
tickSize: 1,
} );
xAxis.render();
var ticksTreatment = 'glow';
var yAxis = new Rickshaw.Graph.Axis.Y( {
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
ticksTreatment: ticksTreatment,
element: document.getElementById('y_axis'),
} );
yAxis.render();
});
There's no official way to do so. However, you could leverage the fact that arrays in javascript are passed by reference and then update the graph.
Have a look at this demo on fiddle
var data = [
{
data: [ { x: 0, y: 120 }, { x: 1, y: 890 }, { x: 2, y: 38 }, { x: 3, y: 70 }, { x: 4, y: 32 } ],
color: "#c05020"
}, {
data: [ { x: 0, y: 80 }, { x: 1, y: 200 }, { x: 2, y: 100 }, { x: 3, y: 520 }, { x: 4, y: 133 } ],
color: "#30c020"
}
];
var graph = new Rickshaw.Graph( {
element: document.getElementById("chart"),
renderer: 'line',
height: 300,
width: 800,
series: data
} );
var y_ticks = new Rickshaw.Graph.Axis.Y( {
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis'),
} );
graph.render();
$('button#add').click(function() {
data.push({
data: [ { x: 0, y: 200 }, { x: 1, y: 390 }, { x: 2, y: 1000 }, { x: 3, y: 200 }, { x: 4, y: 230 } ],
color: "#6060c0"
});
graph.update();
});

Categories