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
}]
});
});
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 already know how to draw a vertical line in the chart but it's a static value and I want to be dynamic. So what I want is to get the Index of the current month and year is there a function?.
Example:
Imagine that the current date is now = '27-03-2021'
I need a function that retrieves the current month and year
Note: this.value, this.category, this.point always show undefined why can't I use it in the potLines area?
xAxis: {
categories: ['01-08-2018', '01-10-2019', '31-02-2020', '27-03-2021', '01-01-1900'],
plotLines: [{
color: '#FF0000',
width: 1,
value: index = (function() {
var value;
if (this.category == '03-2021') { //Compare only the month and year
value = //I want the Index of this position date
} else {
value = //the length of the list
}
return value;
})()
}]
}
Here is a dynamic way to set the plotLine
let data = () => {
let data = []
let start = 1609455600000
for(let i = 0; i < 12; i++){
data.push([start + i * 2592000000, Math.floor(Math.random() * Math.floor(30))])
}
return data
}
Highcharts.chart('container', {
xAxis: {
type: 'datetime',
plotLines: [{
color: '#FF0000',
width: 2,
value: Date.now()
}]
},
series: [{
name: 'Installation',
data: data(),
}],
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container"></div>
I believe as per the API documentation that value only takes a value not a function. If you wish to use a function to you can do so in chart.events.load for example. Then you could try to get the value, category, point from the chart object using this keyword.
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/
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.