My custom X-axis values are not displayed in flot js.
Code for drawing the line chart as below :
var length = 0;
var length1 = 0;
var dataXY = [];
var data = [];
var dataX = [];
length = allVenues.length;
for (var i = 0; i < length; i++) {
length1 = allVenues[i].length;
for (var j = 0; j < length1; j++) {
dataX.push([j, returnDate(allVenues[i][j].date)]);
dataXY.push([returnTimestamp(allVenues[i][j].date), allVenues[i][j].price, "<b>X</b> : " + returnDate(allVenues[i][j].date) + " | " + " <b>Y</b>: " + allVenues[i][j].price]);
}
}
var result = {'label': 'Demo Graph', 'data': dataXY};
data = [result];
var options = {
lines: {
show: true
},
points: {
show: true
},
xaxis: {
ticks: dataX
},
grid: {
hoverable: true,
clickable: true
},
tooltip: {
show: true,
content: "%s | X: %x | Y: %y"
}
};
function returnTimestamp(val) {
var dateTime = new Date(val);
return moment(dateTime).unix();
}
function returnDate(val) {
var dateTime = new Date(val);
return moment(dateTime).format("YYYY-MM-DD hh:mm:ss A");
}
$.plot("#placeholder", data, options);
dataXY array values are:
{"label":"Demo Graph","data":[[1455776629,12],[1455801889,30],[1455962948,45]]}
dataX array values are:
[[0, "2016-02-18 11:53:49 AM"], [1, "2016-02-18 06:54:49 PM"], [2, "2016-02-20 03:39:08 PM"]]
Now i want to set this "dataX" array as X axis values (ticks) on the chart.
This values display below in each point of line graph with X-Axis.
Here dataX and dataXY from allVenues Json Array.
My graph is woking fine except the X-Axis data. You can see in the image below.
Your dataX array for the ticks must have the same x values (timestamps) as your real data array:
[[1455776629, "2016-02-18 11:53:49 AM"], [1455801889, "2016-02-18 06:54:49 PM"], [1455962948, "2016-02-20 03:39:08 PM"]]
PS: I would also suggest to put a linebreak (<br>) between date and time in the labels.
Related
I have the following data returned from php:
# Mes, Total, Categoria
2022-05, 1, Bullying (Mobbing, Bossing, Pessoal, Gossip)
2022-05, 1, Preocupação relativas à saúde e segurança
2022-05, 1, Suspeita de Roubo, Corrupção ou Desfalque
2022-04, 1, Suspeita de Roubo, Corrupção ou Desfalque
2022-05, 1, Feedback positivo ou elogio
Then with this data I want to create a graph that at this moment is already returning most of the data correctly:
To return the series I'm using the following loop:
var series = [];
for (var i = 0; i < data.length; i++) {
Mes = data[i][0];
Total = data[i][1];
Categoria = data[i][2];
series.push({
name: Categoria,
data: [Total],
stack: Mes,
dataLabels: {
enabled: true,
}
});
}
And this way it returns correctly as shown above in the image. The problem is the xAxis categories, which I am not able to return the two dates that exist in the month column.
I'm trying this way, but it's not working:
var xAxis = [];
for (var i = 0; i < data.length; i++) {
Mes = data[i][0];
Total = data[i][1];
Categoria = data[i][2];
xAxis.push({
categories: [Mes],
labels: {
skew3d: true,
style: {
fontSize: '16px'
}
}
});
}
Can you help?
The stack option doesn't refer to the category index as you expect in your example.
You use stack: 'A' and stack: B' and have one y value for each series. It means that two stacked columns are grouped for one category.
Take a look at the API Reference and its demo: https://api.highcharts.com/highcharts/series.column.stack
To achieve a stacked column for each category you need to parse Mes to the number (timestamp) and pass it as an x value.
var series = [];
for (var i = 0; i < data.length; i++) {
Mes = new Date(data[i][0]).getTime() + 60 * 60 * 1000,
Total = data[i][1];
Categoria = data[i][2];
series.push({
name: Categoria,
data: [{x: Mes, y: Total}],
dataLabels: {
enabled: true,
}
});
}
Then set your xAxis.type to datetime and change label format.
xAxis: {
type: 'datetime',
labels: {
format: '{value:%Y-%m}'
},
},
Example demo:
https://jsfiddle.net/BlackLabel/vuLdezxw/
I inherited a codebase that has this style of code and no tests:
var series1 = [];
var series2 = [];
var series3 = [];
var series4 = [];
var series5 = [];
var series6 = [];
var series7 = [];
var series8 = [];
for (var y = 1; y <= seriesData.length; y++) {
// columns are series
eval("series" + y).push({
label: "series" + y,
lineColor: colorArr[seriesData[y - 1].colorIndex],
x: sampleTime,
y: rows[x][seriesData[y - 1].index]
});
}
The main problem is that we're going to start accommodating more than 8 sets of data. Personally, I don't really appreciate this style of code, and I've read the eval function can be harmful in JS. Is there a better way to refactor this?
What I've tried:
let multiarr = []
for (var y = 1; y <= seriesData.length; y++) {
// columns are series
let arr = [];
arr.push({
label: "series" + y,
lineColor: colorArr[seriesData[y - 1].colorIndex],
x: sampleTime,
y: rows[x][seriesData[y - 1].index]
});
}
multiarr.push(arr);
The initial code seems a bit strange. You have a block of series arrays, but each one only gets pushed with a single item. Couldn't it simply be reduced to:
const result = seriesData.map((item, i) => ({
label: `series${i + i}`,
lineColor: colorArr[item.colorIndex],
x: sampleTime,
y: rows[x][item.index]
}))
If for some reason, you do actually need each of the items to themselves be an array, just do:
const multiarr = seriesData.map((item, i) => [{
label: `series${i + i}`,
lineColor: colorArr[item.colorIndex],
x: sampleTime,
y: rows[x][item.index]
}])
You could collect all arrays in a single array and push by taking an index.
var series1 = [],
series2 = [],
series3 = [],
series4 = [],
series5 = [],
series6 = [],
series7 = [],
series8 = [],
data = [series1, series2, series3, series4, series5, series6, series7, series8];
for (var y = 0; y < seriesData.length; y++) {
data[y].push({
label: "series" + (y + 1),
lineColor: colorArr[seriesData[y].colorIndex],
x: sampleTime,
y: rows[x][seriesData[y].index]
});
}
Seen below is a time series bar graph with a range selector in plotly.js.
In it, I am trying to figure out how to group the values by week, but cannot seem to accomplish this. Is there a setting in plotly.js to group these by week when changing the time range selection? I cannot seem to figure out if it is possible.
Here are the main documentation pages they offer, of which I tried as many settings as I thought pertained to accomplishing this, but could not figure it out.
https://plot.ly/javascript/time-series/
https://plot.ly/javascript/bar-charts/
var days = (function(start,count){
var days = [];
var MSday = 1000 * 60 * 60 * 24;
for(var i = 0; i < count; i++){
days.push(new Date(+start + i*MSday));
}
return days;
})(new Date(2018,0,1),100);
function vals(){
var vals = [];
for(var i = 0; i < 100; i++){
vals.push((Math.random() * 2 * i) | 0);
}
return vals;
}
var selectorOptions = {
buttons: [{
step: 'month',
stepmode: 'backward',
count: 1,
label: '1m'
}, {
step: 'month',
stepmode: 'backward',
count: 6,
label: '6m'
}, {
step: 'year',
stepmode: 'todate',
count: 1,
label: 'YTD'
}, {
step: 'year',
stepmode: 'backward',
count: 1,
label: '1y'
}, {
step: 'all',
}],
};
var trace1 = {
x: days,
y: vals(),
type: 'bar',
name: 'Trace 1'
};
var trace2 = {
x: days,
y: vals(),
type: 'bar',
name: 'Trace 2'
};
var data = [trace1, trace2];
var layout = {
title: 'Bar Demo',
barmode: 'group',
xaxis: {
rangeselector: selectorOptions
}
};
Plotly.newPlot('myDiv', data, layout);
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"><!-- Plotly chart will be drawn inside this DIV --></div>
How can I make the 6 month selection group by week instead of by day on the graph?
Apparently this isn't built in. If it is, or becomes built in at some point, please indicate that here in a comment or another answer.
The only option I was able to determine as viable was to hook into the relayout event using .on('plotly_relayout', function () {, taking the arguments from the range selector buttons (which seem limited, only a from and to date, if there is a better way to determine the origination please also let me know and I will update here), and then roughly based on that to bin the dates by week and adjust the x and y values in the plot.
This is just a basic implementation as proof of concept. Using it in production would require refactoring this code to work with the existing data structures with regards to design and page implementation.
There is a lot going on here. Basically, it will iterate through the set of dates to create sunday bins which will hold the weekly data (note that it still lacks a display update to show it is a week from the start date). Once it has the bins it sums the dates in each bin range. Then it replaces the data set using restyle. If the range selected is not 6m then it will use the a slice of the backup data because plotly modifies arrays in place, and as a result it will overwrite the data if there is no backup copy in addition with a single copy every time the backup is used.
See below for a working demo.
function sum(array){
return array.reduce(function(sum,curr){
return sum + curr;
},0);
};
Date.MSday = 1000 * 60 * 60 * 24;
Date.prototype.floor = function(){
return new Date(this.getFullYear(),this.getMonth(),this.getDate());
}
Date.prototype.addDays = function(days){
var time = +this - +this.floor();
var addedDays = new Date(+this.floor() + Date.MSday*days);
return new Date(+addedDays + time);
}
function weeksFromDates(datesArray, valsArray){
var lastDay = datesArray[datesArray.length -1];
var firstDay = datesArray[0];
var dayOfWeek = firstDay.getDay();
var firstSunday = firstDay.addDays(-dayOfWeek);
var sundays = [];
var currentSunday = firstSunday;
while(currentSunday < lastDay){
sundays.push(currentSunday);
currentSunday = currentSunday.addDays(7);
}
currentSunday = currentSunday.addDays(7);
sundays.push(currentSunday);
var valSets = [];
var n = 0;
for(var i = 1; i < sundays.length; i++){
var last = sundays[i-1];
var next = sundays[i];
var theseVals = [];
for(; n < datesArray.length && last <= datesArray[n] && next > datesArray[n]; n++){
theseVals.push(valsArray[n]);
}
valSets.push(sum(theseVals));
}
sundays.pop();
return {x: sundays, y: valSets};
}
var MSday = 1000 * 60 * 60 * 24;
var days = (function(start,count){
var days = [];
for(var i = 0; i < count; i++){
days.push(new Date(+start + i*MSday));
}
return days;
})(new Date(2018,0,1),100);
function vals(){
var vals = [];
for(var i = 0; i < 100; i++){
vals.push((Math.random() * 2 * i) | 0);
}
return vals;
}
var selectorOptions = {
buttons: [{
step: 'month',
stepmode: 'backward',
count: 1,
label: '1m'
}, {
step: 'month',
stepmode: 'backward',
count: 6,
label: '6m'
}, {
step: 'year',
stepmode: 'todate',
count: 1,
label: 'YTD'
}, {
step: 'year',
stepmode: 'backward',
count: 1,
label: '1y'
}, {
step: 'all',
}],
};
var trace1 = {
x: days,
y: vals(),
type: 'bar',
name: 'Trace 1',
orientation: 'v'
};
var trace2 = {
x: days,
y: vals(),
type: 'bar',
name: 'Trace 2',
orientation: 'v'
};
var data = [trace1, trace2];
var dataBackup = $.extend(true,{},data);
var layout = {
title: 'Bar Demo',
barmode: 'group',
xaxis: {
rangeselector: selectorOptions
}
};
Plotly.newPlot('myDiv', data, layout);
$('#myDiv').on('plotly_relayout', function () {
var lower = new Date(arguments[1]['xaxis.range[0]']);
var upper = new Date(arguments[1]['xaxis.range[1]']);
var dayRange = (+upper - +lower) / MSday;
if( dayRange < 190 && dayRange > 170 ){
//6m
for(var n = 0; n < data.length; n++){
var weekly = weeksFromDates(dataBackup[n].x,dataBackup[n].y);
Plotly.restyle('myDiv',{x:[weekly.x],y: [weekly.y]},n);
}
}else{
for(var n = 0; n < data.length; n++){
Plotly.restyle('myDiv',{x:[dataBackup[n].x.slice()],y: [dataBackup[n].y.slice()]},n);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"><!-- Plotly chart will be drawn inside this DIV --></div>
Blimey! There is a much simpler option...
use 7 days:
step: 'day',
stepmode: 'backward',
count: 7,
label: '1w'
I am working on a project and want to dynamically create highchart by assigning series arrays to the highchart. I use some dummy data to generate the array, however, in the example I provided below, the two columns are excatly the same which is not expected.
examples
$(function () {
var field_result = new Object();
var series = [];
var result_array = [];
var fields = [32, 22]
for (var i=0; i<fields.length; i++)
{
field_result.name = fields[i];
for (var m=0; m<4; m ++) {
result_array[m] = Math.random()*10;
}
field_result.data = result_array;
series.push(field_result);
}
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Column chart with negative values'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
credits: {
enabled: false
},
series: series
});
});
Thank you very much.
You intent to create two distinct series-objects with separate data-arrays and put these in the series-array. But you are initializing these objects outside the loop for each individual series, so you end up overwriting the first data object with the second data.
You just have to move the initialization inside the loop:
$(function () {
var series = [];
var fields = [32, 22];
for (var i=0; i<fields.length; i++)
{
var field_result = new Object(); // <---- moved here
var result_array = []; // <---- moved here
field_result.name = fields[i];
for (var m=0; m<4; m ++){
result_array[m] = Math.random()*10;
}
field_result.data = result_array;
series.push(field_result);
}
[...]
Then in each loop iteration a new object and array will be created and filled with random data.
http://jsfiddle.net/doc_snyder/jgoyynzd/2/
I am working in representing data in Highcharts. I have got a task like representing sales of every company for every year, where x axis has categories from jan to dec and y axis has data in which each year's data should be shown in different series, for example, if year is 2010, then jan to dec of 2010's data should be displayed as one series and remaining years.
For that I have googled all over the StackOverflow but I have not succeeded yet.
Here is my code:
$.post('./reportdata/salesbyyear.php', { reportid: value }, function(data) {
//incoming data from php echo statement
var year_data = data;
//replacing all special characters with space, except :
year_data = year_data.replace(/[()""/>{}<]/g, '');
//replacing : with ,
year_data = year_data.replace(/:/g, ',');
//splitting the input data into array
var total_data = new Array();
total_data = year_data.split(',');
//creted two new arrays and stroing alternate elements of previous array into two different arrays
var month_data = new Array();
var year_name = new Array();
var y = 0;
for (i = 0; i < total_data.length; i++) {
month_data[y] = total_data[i];
year_name[y] = total_data[i + 1];
i++;
y++;
}
series = [];
series = generatedata(month_data);
function generatedata(data_array) {
// finding total number of arrays by divding the elements by 12
//so that if I get 44 elements, the total arrays will be 4 , i.e each array
// has sequential 12 elements that represents 1 year (12 months)data
var total = Math.ceil(data_array.length / 12);
var values = [];
var l = 0;
for (i = 0; i < total; i++) {
values[i] = [];
for (j = 0; j < 12; j++) {
values[i][j] = parseFloat(data_array[l]);
l++;
//adding data to series and using this series in highcharts code
series.push({
data: values[i]
});
}
}
}
$('#container').highcharts({
chart: {
type: 'line',
backgroundColor: 'rgba(255, 255, 255, 0.1)',
lineColor: 'orange'
},
title: {
text: 'Customer Details',
style: {
fontFamily: 'monospace',
color: 'orange'
}
},
xAxis: {
categories:['January','February','March','April','May','June','July','August','September','October','November','December'],
lineColor: 'orange',
labels: {
style: {
fontFamily: 'monospace',
color: 'orange'
},
},
},
series: [{
data: series
}]
});
});