Using ECharts visualMap with time axis - javascript

I am using Echarts, and I want to color my series (the trends, not the background) with different ranges. The following example is almost what I need:
But with two modifications:
I have a "time" axis instead of a "category" axis.
For the ranges of the series that are not specified in the visualMap, I want them to keep their original, random-generated color.
I just modified the code in the previous example to try to do it, with no luck:
var values = [];
for(var i = 0; i < 15; i++) {
var date = new Date();
date.setDate(date.getDate() + i);
values.push([date, i])
}
const firstDate = values[1][0];
const lastDate = values[5][0];
option = {
xAxis: {
type: 'time',
boundaryGap: false,
},
yAxis: {
type: 'value',
},
visualMap: {
pieces: [{
gt: firstDate,
lte: lastDate,
color: 'green'
}]
},
series: [
{
type: 'line',
data: values,
}
]
};
I just get errors like:
Uncaught DOMException: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('undefined') could not be parsed as a color.
t.indexOf is not a function at py (echarts.min.js:formatted:15975)
I do not see any information related with time axes in the visualMap documentation.... any ideas?

Related

Getting values instead of percentages of dataZoom in Apache Echarts

I am using Apache Echarts, and I have a chart with an X axis of type time, with a dataZoom of type slider. This serves as an example:
var values = [];
for(var i = 0; i < 15; i++) {
var date = new Date();
date.setDate(date.getDate() + i);
values.push([date, i])
}
const firstDate = values[1][0];
const lastDate = values[5][0];
option = {
xAxis: {
type: 'time',
boundaryGap: false,
},
yAxis: {
type: 'value',
},
dataZoom: [{
type: 'slider',
}],
series: [
{
type: 'line',
data: values,
}
]
};
myChart.on('datazoom', (event) => {
console.log(event)
})
In the event I receive 'start' and 'end' as percentages, but what I would like to receive are the actual start and end date. This means, the values of the axis itself.
I checked the docs, and they say that I can actually get the values when "zoom event of triggered by toolbar". I am not sure whether this refers to the toolbox datazoom (which does not fulfill my needs) or any other thing.
Any help would be appreciated.
As F.Marks answered here, you should get the values in dataZoom echart`s option property object like the code below:
myChart.on('dataZoom', function() {
var option = myChart.getOption();
console.log(option.dataZoom[0].startValue, option.dataZoom[0].endValue);
});

How do I add time sourced from an external source as an X axis to a ChartJS graph?

https://plnkr.co/edit/O4BxVsdOZBc4R68p
fetch(target)
.then(response => response.json())
.then(data => {
var prices = data['Time Series (5min)'];
for (prop in prices) {
var stockPrices = prices[prop]['1. open'];
//change to 2. high, etc
console.log(`${prop} : ${stockPrices}`);
stocksData.datasets[0].data.push({x: prop, y: +stockPrices})
//time x axes are preventing render
window.lineChart.update();
}
})
I am getting information from the AlphaVantage API and am trying to graph the time as the X axis and the open price as the Y axis. However, the time from the API is in an odd format and doesn't appear to graph. I have looked into Moment.js but that appears to be making times, not formatting them. Can anyone give me any pointers on graphing the time correct?
Your problem comes from 2 things:
Your Chart config in options with xAxes that should be xAxis instead
Missing Labels and correct data in Chart data
Here is the codes that works:
var stocksData = {
datasets: [
{
label: 'open',
backgroundColor: 'rgba(104,0,255,0.1)',
data: [
],
},
],
};
window.onload = function() {
var ctx = document.getElementById('myChart').getContext('2d');
var lineChart = new Chart(ctx, {
type: 'line',
data: stocksData,
options: {
scales: {
xAxis: [
{
type: 'linear',
position: 'bottom',
},
],
},
},
});
window.lineChart = lineChart;
};
var sym = 'AAPL'; //get from form
var tseries = 'TIME_SERIES_INTRADAY'; //get from form
var target = `https://www.alphavantage.co/query?function=${tseries}&symbol=${sym}&interval=5min&apikey=VA3RZ8B9PPYWKQKN`;
function update () {
fetch(target)
.then(response => response.json())
.then(data => {
var prices = data['Time Series (5min)'];
for (prop in prices) {
var stockPrices = prices[prop]['1. open'];
//change to 2. high, etc
console.log(`${prop} : ${stockPrices}`);
//stocksData.datasets[0].data.push({x: prop, y: +stockPrices})
stocksData.datasets[0].data.push(stockPrices);
// Format date here. For example with Moment:
// var date = moment(prop).format('YYYY-MM-DD')
stocksData.labels.push(prop);
//time x axes are preventing render
window.lineChart.update();
}
})
.catch(error => console.error(error));
}
A complete format for Chart data would be like:
var stocksData = {
labels: ['date1', 'date2', 'date3', 'date4'],
datasets: [
{
label: 'open',
backgroundColor: 'rgba(104,0,255,0.1)',
data: [
'data1', 'data2', 'data3', 'data4'
],
},
],
};
Then each data and date label should be push separately:
stocksData.datasets[0].data.push(stockPrices);
stocksData.labels.push(prop);
To format with Moment you can use:
var dateStr = moment(prop).format('YYYY-MM-DD');
The "odd" time format is (almost) the standard international datetime format. In this case YYYY-MM-DD HH:MM:SS. I strongly suggest you familiarise yourself with it and use it in preference to DD/MM/YYYY or MM/DD/YYYY.
You can fix your code by changing the x-axis type to time and adding the appropriate configuration options:
options: {
scales: {
xAxes: [
{
type: 'time',
...
Note that you'll also need to change your call to Chart.js to the version with moment.js bundled (or include moment separately):
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>

HighCharts Playing with YAxis & TimeStamps

I will need to display objects (a doublebar chart for each object). The structure of the object is:
{
dates: (5) ["2018-12-26", "2018-12-27", "2018-12-28", "2018-12-31", "2019-01-02"]
formattedDates: (5) ["2018/12/26", "2018/12/27", "2018/12/28", "2018/12/31", "2019/01/02"]
formatPoints2: (5) [1545945000000, 1546026562061, 1546284847056, 1546465543023, 1546545993086]
points: (5) ["2018-12-27T10:36:24.893", "2018-12-28T17:29:56.517", "2018-12-31T05:48:41.587", "2019-01-01T10:10:09.683", "2019-01-03T10:36:42.002"]
points2: (5) ["2018-12-27T16:10", "2018-12-28T14:49:22.061", "2018-12-31T14:34:07.056", "2019-01-02T16:45:43.023", "2019-01-03T15:06:33.086"]
formatPoints: (5) [1545924984893, 1546036196517, 1546253321587, 1546355409683, 1546529802002]
}
I took the liberty of converting the points and points 2 array using date.getTime() to get the formatPoints and formatPoints2
what I need to do is plot the time of the timestamps vs the dates.
e.g. points[0] = 2018-12-27T10:36:24.893, dates[0] = 2018-12-26
plot 10:36:24 vs 2018-12-26 and so on for each time in the array
an extra catch I need to display the FULL timestamp in the tool-tip (2018-12-27T10:36:24.893) on the chart when you hover over the bar for that point
the chart is a double bar chart where points&points2 is plotted against dates.
In your case the key is to set the right axis types. For timestamp values on yAxis the best type will be datetime and for dates on xAxis - category. Please check the example below and let me know if everything is fine.
var series = [{data: []}, {data: []}];
data.points.forEach(function(point, i){
series[0].data.push({
name: data.formattedDates[i],
tooltipText: data.points[i],
y: data.formatPoints[i]
});
series[1].data.push({
name: data.formattedDates[i],
tooltipText: data.points2[i],
y: data.formatPoints2[i]
});
});
Highcharts.chart('container', {
chart: {
type: 'bar'
},
xAxis: {
type: 'category'
},
tooltip: {
pointFormat: '{point.tooltipText}'
},
yAxis: {
min: 1545945000000,
max: 1546529802002,
type: 'datetime'
},
series: series
});
Live demo: http://jsfiddle.net/BlackLabel/asm64f5r/
API: https://api.highcharts.com/highcharts/xAxis.type

JS for Loop in Flot with JSON Data

I am attempting to create a dynamic flot graph dependant upon the data given to it, my flot graph is using JSON for its information and here is an example of the dataset:
{
"total":[[1377691200,115130],[1377694800,137759],[1377698400,137759],[1377702000,137759],[1377705600,137759],[1377709200,139604],[1377712800,137759],[1377716400,137759],[1377720000,137759],[1377723600,137759],[1377727200,137759],[1377730800,138156],[1377734400,137759],[1377738000,137759],[1377741600,137759],[1377745200,137759],[1377748800,138156],[1377752400,137759],[1377756000,137759],[1377759600,168831],[1377763200,137759],[1377766800,0],[1377770400,0]],
"dev0":[[1377691200,115130],[1377694800,137759],[1377698400,137759],[1377702000,137759],[1377705600,137759],[1377709200,139604],[1377712800,137759],[1377716400,137759],[1377720000,137759],[1377723600,137759],[1377727200,137759],[1377730800,138156],[1377734400,137759],[1377738000,137759],[1377741600,137759],[1377745200,137759],[1377748800,138156],[1377752400,137759],[1377756000,137759],[1377759600,168831],[1377763200,137759],[1377766800,0],[1377770400,0]],
"dev1":[[1377691200,0],[1377694800,0],[1377698400,0],[1377702000,0],[1377705600,0],[1377709200,0],[1377712800,0],[1377716400,0],[1377720000,0],[1377723600,0],[1377727200,0],[1377730800,0],[1377734400,0],[1377738000,0],[1377741600,0],[1377745200,0],[1377748800,0], [1377752400,0],[1377756000,0],[1377759600,0],[1377763200,0],[1377766800,0],[1377770400,0]]
}
The script i have created already:
$(".bytes_portal_pop").click(function(e) {
e.preventDefault();
var graph=$(this).data('graph');
var range=$(this).data('range');
var divid=$(this).data('divid');
var title=$(this).data('boxtitle');
$.getJSON("/action/sites/GetFlotStats/?graph=" + graph + "&range=" + range, function(json) {
//succes - data loaded, now use plot:
var plotarea = $("#" + divid);
var dev0=json.dev0;
var dev1=json.dev1;
$.plot(
$("#" + divid),
[
{
data: dev0,
lines:{show: true, fill: true},
label: "dev0",
},
{
data: dev1,
lines:{show: true, fill: true},
label: "dev1",
},
],
{
xaxis: {mode:"time"},
grid: {hoverable: true},
tooltip: true,
tooltipOpts: {
content: "Traffic: %y GB"
}
}
);
});
$("#boxtitleB_flot").html(title);
});
This way works fine and displays the two lines as i need however i would like it to be dynamic i.e. so i dont have to define each graph line i believe todo this i simply need a for or each() loop on the
var dev0=json.dev0;
and
{
data: dev0,
lines:{show: true, fill: true},
label: "dev0",
},
Any help achieving this would be much appreciated.
Correct, just loop it and generate your series objects dynamically.
Given a json return like:
jsonObj = {
"total":[[1377691200,115130],[1377694800,137759],[1377698400,137759],[1377702000,137759],[1377705600,137759],[1377709200,139604],[1377712800,137759],[1377716400,137759],[1377720000,137759],[1377723600,137759],[1377727200,137759],[1377730800,138156],[1377734400,137759],[1377738000,137759],[1377741600,137759],[1377745200,137759],[1377748800,138156],[1377752400,137759],[1377756000,137759],[1377759600,168831],[1377763200,137759],[1377766800,0],[1377770400,0]],
"dev0":[[1377691200,115130],[1377694800,137759],[1377698400,137759],[1377702000,137759],[1377705600,137759],[1377709200,139604],[1377712800,137759],[1377716400,137759],[1377720000,137759],[1377723600,137759],[1377727200,137759],[1377730800,138156],[1377734400,137759],[1377738000,137759],[1377741600,137759],[1377745200,137759],[1377748800,138156],[1377752400,137759],[1377756000,137759],[1377759600,168831],[1377763200,137759],[1377766800,0],[1377770400,0]],
"dev1":[[1377691200,0],[1377694800,0],[1377698400,0],[1377702000,0],[1377705600,0],[1377709200,0],[1377712800,0],[1377716400,0],[1377720000,0],[1377723600,0],[1377727200,0],[1377730800,0],[1377734400,0],[1377738000,0],[1377741600,0],[1377745200,0],[1377748800,0], [1377752400,0],[1377756000,0],[1377759600,0],[1377763200,0],[1377766800,0],[1377770400,0]]
};
Create an array of series like:
var series = [];
$.each(jsonObj, function (key, val) {
var serie = {};
serie.label = key;
serie.data = val;
series.push(serie);
});
And then create the plot:
$.plot(
$("#placeholder"),
series,
{}
);
Fiddle here.

Set Additional Data to highcharts series

is there any way to pass some additional data to the series object that will use to show in the chart 'tooltip'?
for example
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
Highcharts.dateFormat('%b %e', this.x) +': '+ this.y;
}
here we can only use series.name , this.x & this.y to the series. lets say i need to pass another dynamic value alone with the data set and can access via series object. is this possible?
Thank you all in advance.
Yes, if you set up the series object like the following, where each data point is a hash, then you can pass extra values:
new Highcharts.Chart( {
...,
series: [ {
name: 'Foo',
data: [
{
y : 3,
myData : 'firstPoint'
},
{
y : 7,
myData : 'secondPoint'
},
{
y : 1,
myData : 'thirdPoint'
}
]
} ]
} );
In your tooltip you can access it via the "point" attribute of the object passed in:
tooltip: {
formatter: function() {
return 'Extra data: <b>' + this.point.myData + '</b>';
}
}
Full example here: https://jsfiddle.net/burwelldesigns/jeoL5y7s/
Additionally, with this solution, you can even put multiple data as much as you want :
tooltip: {
formatter: function () {
return 'Extra data: <b>' + this.point.myData + '</b><br> Another Data: <b>' + this.point.myOtherData + '</b>';
}
},
series: [{
name: 'Foo',
data: [{
y: 3,
myData: 'firstPoint',
myOtherData: 'Other first data'
}, {
y: 7,
myData: 'secondPoint',
myOtherData: 'Other second data'
}, {
y: 1,
myData: 'thirdPoint',
myOtherData: 'Other third data'
}]
}]
Thank you Nick.
For time series data, especially with enough data points to activate the turbo threshold, the proposed solutions above will not work. In the case of the turbo threshold, this is because Highcarts expects the data points to be an array like:
series: [{
name: 'Numbers over the course of time',
data: [
[1515059819853, 1],
[1515059838069, 2],
[1515059838080, 3],
// you get the idea
]
}]
In order not to lose the benefits of the turbo threshold (which is important when dealing with lots of data points), I store the data outside of the chart and look up the data point in the tooltip formatter function. Here's an example:
const chartData = [
{ timestamp: 1515059819853, value: 1, somethingElse: 'foo'},
{ timestamp: 1515059838069, value: 2, somethingElse: 'bar'},
{ timestamp: 1515059838080, value: 3, somethingElse: 'baz'},
// you get the idea
]
const Chart = Highcharts.stockChart(myChart, {
// ...options
tooltip: {
formatter () {
// this.point.x is the timestamp in my original chartData array
const pointData = chartData.find(row => row.timestamp === this.point.x)
console.log(pointData.somethingElse)
}
},
series: [{
name: 'Numbers over the course of time',
// restructure the data as an array as Highcharts expects it
// array index 0 is the x value, index 1 is the y value in the chart
data: chartData.map(row => [row.timestamp, row.value])
}]
})
This approach will work for all chart types.
I am using AJAX to get my data from SQL Server, then I prepare a js array that is used as the data in my chart.
JavaScript code once the AJAX is successfull:
...,
success: function (data) {
var fseries = [];
var series = [];
for (var arr in data) {
for (var i in data[arr]['data'] ){
var d = data[arr]['data'][i];
//if (i < 5) alert("d.method = " + d.method);
var serie = {x:Date.parse(d.Value), y:d.Item, method:d.method };
series.push(serie);
}
fseries.push({name: data[arr]['name'], data: series, location: data[arr]['location']});
series = [];
};
DrawChart(fseries);
},
Now to show extra meta-data in the tooltip:
...
tooltip: {
xDateFormat: '%m/%d/%y',
headerFormat: '<b>{series.name}</b><br>',
pointFormat: 'Method: {point.method}<br>Date: {point.x:%m/%d/%y } <br>Reading: {point.y:,.2f}',
shared: false,
},
I use a DataRow to iterate through my result set, then I use a class to assign the values prior to passing back in Json format. Here is the C# code in the controller action called by Ajax.
public JsonResult ChartData(string dataSource, string locationType, string[] locations, string[] methods, string fromDate, string toDate, string[] lstParams)
{
List<Dictionary<string, object>> dataResult = new List<Dictionary<string, object>>();
Dictionary<string, object> aSeries = new Dictionary<string, object>();
string currParam = string.Empty;
lstParams = (lstParams == null) ? new string[1] : lstParams;
foreach (DataRow dr in GetChartData(dataSource, locationType, locations, methods, fromDate, toDate, lstParams).Rows)
{
if (currParam != dr[1].ToString())
{
if (!String.IsNullOrEmpty(currParam)) //A new Standard Parameter is read and add to dataResult. Skips first record.
{
Dictionary<string, object> bSeries = new Dictionary<string, object>(aSeries); //Required else when clearing out aSeries, dataResult values are also cleared
dataResult.Add(bSeries);
aSeries.Clear();
}
currParam = dr[1].ToString();
aSeries["name"] = cParam;
aSeries["data"] = new List<ChartDataModel>();
aSeries["location"] = dr[0].ToString();
}
ChartDataModel lst = new ChartDataModel();
lst.Value = Convert.ToDateTime(dr[3]).ToShortDateString();
lst.Item = Convert.ToDouble(dr[2]);
lst.method = dr[4].ToString();
((List<ChartDataModel>)aSeries["data"]).Add(lst);
}
dataResult.Add(aSeries);
var result = Json(dataResult.ToList(), JsonRequestBehavior.AllowGet); //used to debug final dataResult before returning to AJAX call.
return result;
}
I realize there is a more efficient and acceptable way to code in C# but I inherited the project.
Just to add some kind of dynamism :
Did this for generating data for a stacked column chart with 10 categories.
I wanted to have for each category 4 data series and wanted to display additional information (image, question, distractor and expected answer) for each of the data series :
<?php
while($n<=10)
{
$data1[]=array(
"y"=>$nber1,
"img"=>$image1,
"ques"=>$ques,
"distractor"=>$distractor1,
"answer"=>$ans
);
$data2[]=array(
"y"=>$nber2,
"img"=>$image2,
"ques"=>$ques,
"distractor"=>$distractor2,
"answer"=>$ans
);
$data3[]=array(
"y"=>$nber3,
"img"=>$image3,
"ques"=>$ques,
"distractor"=>$distractor3,
"answer"=>$ans
);
$data4[]=array(
"y"=>$nber4,
"img"=>$image4,
"ques"=>$ques,
"distractor"=>$distractor4,
"answer"=>$ans
);
}
// Then convert the data into data series:
$mydata[]=array(
"name"=>"Distractor #1",
"data"=>$data1,
"stack"=>"Distractor #1"
);
$mydata[]=array(
"name"=>"Distractor #2",
"data"=>$data2,
"stack"=>"Distractor #2"
);
$mydata[]=array(
"name"=>"Distractor #3",
"data"=>$data3,
"stack"=>"Distractor #3"
);
$mydata[]=array(
"name"=>"Distractor #4",
"data"=>$data4,
"stack"=>"Distractor #4"
);
?>
In the highcharts section:
var mydata=<? echo json_encode($mydata)?>;
// Tooltip section
tooltip: {
useHTML: true,
formatter: function() {
return 'Question ID: <b>'+ this.x +'</b><br/>'+
'Question: <b>'+ this.point.ques +'</b><br/>'+
this.series.name+'<br> Total attempts: '+ this.y +'<br/>'+
"<img src=\"images/"+ this.point.img +"\" width=\"100px\" height=\"50px\"/><br>"+
'Distractor: <b>'+ this.point.distractor +'</b><br/>'+
'Expected answer: <b>'+ this.point.answer +'</b><br/>';
}
},
// Series section of the highcharts
series: mydata
// For the category section, just prepare an array of elements and assign to the category variable as the way I did it on series.
Hope it helps someone.

Categories