Parsing CSV and then Using the Data to Build Highcharts Bar Chart - javascript

I want to create a bar chart visualization IN JS FIDDLE that will visualize 'Q1 / 18 (TTM) Annual Guest Value' and 'Days Between 1st and 2nd Visits' for each category of Consumer which is: ['1', '2', .....'29+']. The bar chart should look like this (the legend is covering the 1st category but I'll fix this):
I assume that the data is present already in a CSV that looks like:
I have an interface that will allow the user to import a CSV file. It is here:
// The event listener for the file upload
document.getElementById('txtFileUpload').addEventListener('change', upload, false);
// Method that checks that the browser supports the HTML5 File API
function browserSupportFileUpload() {
var isCompatible = false;
if (window.File && window.FileReader && window.FileList && window.Blob) {
isCompatible = true;
}
return isCompatible;
}
function upload(evt) {
if (!browserSupportFileUpload()) {
alert('The File APIs are not fully supported in this browser!');
} else {
var data = null;
var file = evt.target.files[0];
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function(event) {
var csvData = event.target.result; //alert(csvData);
var data2 = csvData.split("\n"); //alert(data2);
var i;
for (i = 0; i < data2.length; ++i) {
// here's the data row separated by commas
alert(i+': '+data2[i]);
// call your ajax and submit this one row
// now wait for response
// if not error:
// advance progress bar, and number converted, etc in modal
// else:
// show error message
}
if (data2 && data2.length > 0) {
alert('Imported -' + data2.length + '- rows successfully!');
} else {
alert('No data to import!');
}
};
reader.onerror = function() {
alert('Unable to read ' + file.fileName);
};
}
}
<h1>File Upload Test</h1>
<p>
<div id="dvImportSegments" class="fileupload ">
<fieldset>
<legend>Select the CSV file to upload</legend>
<input type="file" name="File Upload" id="txtFileUpload" accept=".csv" />
</fieldset>
</div>
</p>
Then, I am using .get() to bring in the variable csvData (from a function in the above code) and then I will parse it using the function parseCSVData (the function is written below). Then, I will make the bar chart of the data. Here is my code for this part:
$.get(csvData, function (csvFile) { //retrieve csvData from other function above
var data = parseCSVData(csvFile);
//create the chart
Highcharts.chart('container', {
chart: {
type: 'bar'
},
title: {
text: null,
align: 'center',
verticalAlign: 'bottom',
},
xAxis: {
categories: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11-17', '18-28', '29+'],
title: {
text: 'Visits Per Customer (TTM)'
},
},
yAxis: {
min: 0,
gridLineWidth: 0,
minorGridLineWidth: 0,
title: {
text: 'Average Return Rate Overall: 64 Days',
y: 10
},
labels: {
overflow: 'justify'
}
},
tooltip: {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.0f} </b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
bar: {
dataLabels: {
enabled: true,
}
}
},
legend: {
layout: 'horizontal',
align: 'right',
verticalAlign: 'top',
x: -25,
y: 5,
floating: true,
borderWidth: 1,
backgroundColor: ((Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'),
shadow: true
},
credits: {
enabled: false
},
series: [{
name: 'Q1 / 18 (TTM) Annual Guest Value',
//data: 2nd column of CSV file
color: 'grey',
// label color
dataLabels: {
style: {
color: 'grey'
}
}
}, {
name: 'Days Between 1st and 2nd Visits',
//data: 3rd Column of CSV file
color: 'green',
// label color
dataLabels: {
style: {
color: 'green'
}
}
}]
})
})
function parseCSVData (csvFile){
//empty array for storing the chart data
var guestvalue_and_visits = []; //2nd and 3rd column extraction
var lines = csvFile.split("\n");
$.each(lines, function (lineNumber, line){
if(lineNumber != 0) { //skipping header lines
var fields = line.split(",");
var a = parseFloat(fields[1]); // this is guest value
var b = parseFloat(fields[2]); //this is days between visit
guestvalue_and_visits.push([a , b]);
}
})
return guestvalue_and_visits.reverse();
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<div id="container" style="min-width: 310px; max-width: 800px; height: 400px; margin: 0 auto"></div>
My questions are:
What is the right form of the data that I need to parse? Is it var data2 = csvData.split("\n") OR is it var csvData = event.target.result?
Did I bring in the variable csvData (or data2 if this is the right one) in correctly in .get()? I am not an expert in Javascript but I am pretty sure that for instance the variable csvData is local to reader.onload = function(event){} so I would somehow need to access this local variable. How would I bring this correctly into .get()? Would simply writing .get(csvData, function (csvFile){ be okay?
Also, if you look at the 'data' property under 'series', I have left it blank because I do not know how to bring the data from the guestvalue_and_visits variable into the Highcharts code. (I did guestvalue_and_visits.push([a , b] because this is the form Highcharts accepts). I want to extract the 'a' and 'b' part from the data structure and put them in their corresponding 'data' property under 'series'. How would I do this?
Last but not least, bringing everything together how would I allow the interface to FIRST allow the user to upload a CSV file and THEN when it is uploaded, the interface will change to the Highcharts bar chart? Is there some sort of code I need to write to do this?

What is the right form of the data that I need to parse? Is it var
data2 = csvData.split("\n") OR is it var csvData =
event.target.result?
In your case I recommend you to separate the categories and series data in your CSV string parser, and return two different series with data included, just like that:
var parseCSV = function(csv) {
var lines = csv.split("\n").map(line => line.split(",")) // split string to lines
var categories = []
var series = [{
name: 'Q1 / 18 (TTM) Annual Guest Value',
color: 'grey',
data: [],
dataLabels: {
style: {
color: 'grey'
}
}
}, {
name: 'Days Between 1st and 2nd Visits',
color: 'green',
data: [],
dataLabels: {
style: {
color: 'green'
}
}
}]
// Parse every line of csv file.
lines.forEach((line, i) => {
if (i !== 0) {
var cat = line[0].slice(1, -1)
var p1 = parseFloat(line[1])
var p2 = parseFloat(line[2])
categories.push(cat)
series[0].data.push(p1)
series[1].data.push(p2)
}
})
// return the object with categories and series
return {
categories: categories,
series: series
}
}
Then just assign the categories, and series:
var parsedCSV = parseCSV(csv)
Highcharts.chart('container', {
xAxis: {
categories: parsedCSV.categories
},
series: parsedCSV.series
})
Did I bring in the variable csvData (or data2 if this is the right one) in correctly in .get()? I am not an expert in Javascript but I am pretty sure that for instance the variable csvData is local to reader.onload = function(event){} so I would somehow need to access this local variable. How would I bring this correctly into .get()? Would simply writing .get(csvData, function (csvFile){ be okay?
I don't see your whole project structure, but yes, the csvData and data2 variables scope is limited only to reader.onload function so, you can't call get() anywhere except this event function.
Last but not least, bringing everything together how would I allow the
interface to FIRST allow the user to upload a CSV file and THEN when
it is uploaded, the interface will change to the Highcharts bar chart?
Is there some sort of code I need to write to do this?
Actually, I think the process of generating the chart should look like that:
Generate an empty chart (or with some initial data)
Get CSV from file
Parse CSV you've got
When parsed just update the chart with new categories and whole series object using Chart.update() method.
API Reference: https://api.highcharts.com/class-reference/Highcharts.Chart#update
Live example with parsing data in correct way: http://jsfiddle.net/db0vsgmh/

Related

highcharts (using csv data) not loading until refreshing the page, sometimes i even have to refresh several times

I'm using html, css and javascript for the project. The server is set up locally including node, express and highcharts.
In my html i have a div container, that i'm referencing in my highcharts function. The data i'm using in the highchart come from a csv file. I wrote a simple getData function, that parses the data into an array. And at the top of the highchartsfunction, i'm using await getData, so the chart can only be rendered after getting the data for it. All functions are async. On that one page i'm having seven charts, all constructed using the syntax following below, each with its own getData function and div container.
Two problems:
Problem No.1:
The charts are not getting displayed until i refresh the page and often times i even have to refresh it several times, till every chart is getting shown at a time (Like 20 times). The functions are all executed, i checked that in the console.
Problem No.2:
I would like to write this dynamically, as i want to have multiple pages on my website, each using its own csv file, but basically the same code.
*Edit:
From time to time i receive: "Error: Highcharts error #13: www.highcharts.com/errors/13/" in the console, but as i keep refreshing it changes the line/js it is referencing to. It always is the part of the highcharts function, in which i give it its container Highcharts.chart('hammerchart', {. I checked this error and what it sais is basically, that the script can't find a container with the #id. Which i don't understand as im using "DOMContentLoaded". I tried the "load" event instead, which solved the error #13, but ended up in no chart getting displayed at all without any error message.
*Edit2:
Until now i only used firefox to view my website. I checked Chrome aswell and here i don't have any error message, but it also never shows any of the charts aswell at all.
If someone could help me out here, i would be really happy, as i tried to fix this for days now with no success. I'm also open for suggestions, regarding the handling of my data. Thank you veeeery much in advance!!
Code:
CSV Data sample
2015,2.5,7.2,1.6,6.5,2.2
2016,3.5,7.6,2.6,9.3,1.2
2017,2.5,7.2,1.6,6.5,2.2
2018,3.5,7.6,2.6,9.3,1.2
2019,2.5,7.2,1.6,6.5,2.2
HTML
<div id="hammerchart">
</div>
CSS
#hammerchart{
width:49%;
height: 500px;
margin:0.5%;
margin-top:50px;
flex: 1 1 600px;
}
Javascript - first declaration of the arrays, then my parsing function, splitting the csv by linebreaks and commas. Then i'm using parseFloat(), so that i don't have strings in it. In the highcharts function i'm using await getData and DOMContentloaded, to make sure both html and my data are ready.
const years = [];
const columntwos = [];
const columnthrees = [];
const columnfours = [];
const columnfives = [];
const columnsixs = [];
async function getDataone() {
const response = await fetch('/javascripts/hammerchart.CSV');
const data = await response.text();
const table = data.split('\n');
table.forEach(row => {
const columns = row.split(',');
const year = columns[0];
years.push(year);
const columntwo = columns[1];
columntwos.push(parseFloat(columntwo));
const columnthree = columns[2];
columnthrees.push(parseFloat(columnthree));
const columnfour = columns[3];
columnfours.push(parseFloat(columnfour));
const columnfive = columns[4];
columnfives.push(parseFloat(columnfive));
const columnsix = columns[5];
columnsixs.push(parseFloat(columnsix));
});
};
async function hammerchart() {
await getDataone();
document.addEventListener('DOMContentLoaded', () => {
Highcharts.chart('hammerchart', {
chart: {
zoomType: 'xy'
},
title: {
text: 'Data'
},
subtitle: {
text: ''
},
credits: {
text: 'highcharts',
},
xAxis: [{
categories: years,
plotBands: [{ // visualize
from: 4.5,
to: 6,
color: 'rgba(68, 170, 213, .2)'
}],
crosshair: true
}],
yAxis: [{ // Primary yAxis
labels: {
format: '{value}$',
style: {
color: Highcharts.getOptions().colors[1]
}
},
title: {
text: 'Amount in $',
style: {
color: Highcharts.getOptions().colors[1]
}
}
}, { // Secondary yAxis
title: {
text: 'Ratio in %',
style: {
color: Highcharts.getOptions().colors[0]
}
},
labels: {
format: '{value} %',
style: {
color: Highcharts.getOptions().colors[0]
}
},
opposite: true
}],
tooltip: {
shared: true
},
legend: {
layout: 'vertical',
align: 'left',
x: 120,
verticalAlign: 'top',
y: 100,
floating: true,
backgroundColor:
Highcharts.defaultOptions.legend.backgroundColor || // theme
'rgba(255,255,255,0.25)'
},
series: [{
name: 'columntwo',
type: 'areaspline',
data: columntwos,
tooltip: {
valueSuffix: '$'
}
}, {
name: 'columnthree',
type: 'areaspline',
data: columnthrees,
tooltip: {
valueSuffix: '$'
}
}, {
name: 'columnfour',
type: 'areaspline',
data: columnfours,
tooltip: {
valueSuffix: '$'
}
}, {
name: 'columnfive',
type: 'column',
data: columnfives,
tooltip: {
valueSuffix: '$'
}
}, {
name: 'columnsix',
type: 'spline',
yAxis: 1,
data: columnsixs,
tooltip: {
valueSuffix: '%'
}
}]
});
});
};
hammerchart();

How to show the transition in highchart series graph without refreshing the html webpage?

I am getting JSON data using an api which is being stored in an data.json file.
Later a javascript is using that data.json file and using it to draw highcharts. The JSON File is changing every instant and the data.json file is getting update with the data.I am linking this javascript file to an html file and later running it on chrome browser. As data.json file is changing every instant then the graph corresponding to it is also changing every instant. In order to see the graphs I have to manually refresh to see that graph . How do I show the transitions in the data in the graphs without refreshing the browser.
I DONOT WANT TO REFRESH THE DIV OR EITHER THE ENTIRE HTML PAGE something dynamically.
Reference: https://onedesigncompany.com/
Similar to the transitions in this website.
This is how my graph looks like
This is my html + javascript code
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
enter code here<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore.js" type="text/javascript"></script>
<div id="container" style="min-width: 310px; height: 400px; max-width: 800px; margin: 0 auto"></div>
<script type="text/javascript">
$(document).ready(function() {
$("#container").load("index.html");
var options = {
chart: {
renderTo: 'container',
type: 'scatter',
zoomType: 'xy'
},
title: {
text: 'Number of people Versus floor'
},
xAxis: {
title: {
enabled: true,
text: 'Uids'
},
startOnTick: true,
endOnTick: true,
showLastLabel: true
},
yAxis: {
title: {
text: 'Floor'
}
},
legend: {
layout: 'vertical',
align: 'left',
verticalAlign: 'top',
x: 100,
y: 70,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF',
borderWidth: 1
},
plotOptions: {
scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: 'uid: {point.x} , floor: {point.y} '
}
}
},
// series: [{}]
};
$.getJSON('/static/data/data.json', function(data) {
//floor0 data
var floor0=[];
var i,j;
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="0")
floor0.push(data.occupancy_information[i].uids);
}
var merged0 = [].concat.apply([], floor0);
var result0=[];
result0=merged0.map(Number);
var len0=result0.length;
var iMax0 = len0;
var jMax0 = 2;
var f0 = new Array();
for (i=0;i<iMax0;i++) {
f0[i]=new Array();
for (j=0;j<jMax0;j++) {
f0[i][0]=parseInt(merged0[i]);
f0[i][1]=0;
}
}
//floor1 data
var floor1=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="1")
floor1.push(data.occupancy_information[i].uids);
}
var merged1 = [].concat.apply([], floor1);
var result1=[];
result1=merged1.map(Number);
var len1=result1.length;
var iMax1 = len1;
var jMax1 = 2;
var f1 = new Array();
for (i=0;i<iMax1;i++) {
f1[i]=new Array();
for (j=0;j<jMax1;j++) {
f1[i][0]=parseInt(merged1[i]);
f1[i][1]=1;
}
}
//floor2 data
var floor2=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="2")
floor2.push(data.occupancy_information[i].uids);
}
var merged2 = [].concat.apply([], floor2);
var result2=[];
result2=merged2.map(Number);
var len2=result2.length;
var iMax2 = len2;
var jMax2 = 2;
var f2 = new Array();
for (i=0;i<iMax2;i++) {
f2[i]=new Array();
for (j=0;j<jMax2;j++) {
f2[i][0]=parseInt(merged2[i]);
f2[i][1]=2;
}
}
//floor3 data
var floor3=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="3")
floor3.push(data.occupancy_information[i].uids);
}
var merged3 = [].concat.apply([], floor3);
var result3=[];
result3=merged3.map(Number);
var len3=result3.length;
var iMax3 = len3;
var jMax3 = 2;
var f3 = new Array();
for (i=0;i<iMax3;i++) {
f3[i]=new Array();
for (j=0;j<jMax3;j++) {
f3[i][0]=parseInt(merged3[i]);
f3[i][1]=3;
}
}
//floor4 data
var floor4=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="4")
floor4.push(data.occupancy_information[i].uids);
}
var merged4 = [].concat.apply([], floor4);
var result4=[];
result4=merged4.map(Number);
var len4=result4.length;
var iMax4 = len4;
var jMax4 = 2;
var f4 = new Array();
for (i=0;i<iMax4;i++) {
f4[i]=new Array();
for (j=0;j<jMax4;j++) {
f4[i][0]=parseInt(merged4[i]);
f4[i][1]=4;
}
}
//floor5 data
var floor5=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="5")
floor5.push(data.occupancy_information[i].uids);
}
var merged5 = [].concat.apply([], floor5);
var result5=[];
result5=merged5.map(Number);
var len5=result5.length;
var iMax5 = len5;
var jMax5 = 2;
var f5 = new Array();
for (i=0;i<iMax5;i++) {
f5[i]=new Array();
for (j=0;j<jMax5;j++) {
f5[i][0]=parseInt(merged5[i]);
f5[i][1]=5;
}
}
var chart = new Highcharts.Chart(options);
chart.addSeries({
name: 'Ground floor',
data: f0
}, false);
chart.addSeries({
name: 'First Floor',
data: f1
}, false);
chart.addSeries({
name: 'Second Floor',
data: f2
}, false);
chart.addSeries({
name: 'Third Floor',
data: f3
}, false);
chart.addSeries({
name: 'Fourth Floor',
data: f4
}, false);
chart.addSeries({
name: 'Fifth Floor',
data: f5
}, false);
chart.redraw();
});
});
</script>
Keep your ajax /getJson in the set interval and pass the data to your massager function when it returns data every five seconds, this way the page doesn't get refreshed.
Look at this example
var time_interval = 5000;
setInterval(function () {
$.ajax({
url: 'your_path_to_the_api',
data: '',
cache: false,
type: 'POST',
success: function (data) {
$('#container').text(data);
}
});
}, time_interval);
You want to update chart, when your data in the backend is updated. To achieve that you have two ways:
as the other answer states, use AJAX with setInterval, where you will request new data from the backend. The problem is that, your data may be not updated yet, or updated before, so you may miss/late with the graph update.
use websockets (or long polling) with database which will have publish possibility (like Redis). Then create websocket connection between backend and frontend. When connection is set, your database should emit signal that "new data is available" and in the backend gather all new data and send via websocket to the front end, and in front end update data using chart.series[index].setData(new_data).
The second solution of course requires backend: database and server. If this is too much, then you need to use the first one.
You can also consider using some platform which implements natively second solution. For example Meteor.
Why not set a time interval so that it refreshes every 5 seconds?
http://devzone.co.in/automatically-refresh-html-page-div-specific-time-interval/

Data Not Showing in Highcharts

I'm attempting to combine a couple of different chart demos from Highcharts.
My examples are: Data classes and popup and Small US with data labels
I want the map from the first with the popup feature of the second. I need to connect the map to my own google spreadsheet but for now I'm just trying to get the data from the first example to work.
This is what I have so far but can't seem to get any data in the map. I thought I had a joinBy problem, and I may still, but when I set joinBy to null I thought "the map items are joined by their position in the array", yet nothing happened.
https://jsfiddle.net/9eq6mydv/
$(function () {
// Load the data from a Google Spreadsheet
// https://docs.google.com/a/highsoft.com/spreadsheet/pub?hl=en_GB&hl=en_GB&key=0AoIaUO7wH1HwdFJHaFI4eUJDYlVna3k5TlpuXzZubHc&output=html
Highcharts.data({
googleSpreadsheetKey: '0AoIaUO7wH1HwdDFXSlpjN2J4aGg5MkVHWVhsYmtyVWc',
googleSpreadsheetWorksheet: 1,
// custom handler for columns
parsed: function (columns) {
// Make the columns easier to read
var keys = columns[0],
names = columns[1],
percent = columns[10],
// Initiate the chart
options = {
chart : {
renderTo: 'container',
type: 'map',
borderWidth : 1
},
title : {
text : 'US presidential election 2008 result'
},
subtitle: {
text: 'Source: <a href="http://en.wikipedia.org/wiki/United_States_presidential_election,' +
'_2008#Election_results">Wikipedia</a>'
},
mapNavigation: {
enabled: true,
enableButtons: false
},
legend: {
align: 'right',
verticalAlign: 'top',
x: -100,
y: 70,
floating: true,
layout: 'vertical',
valueDecimals: 0,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || 'rgba(255, 255, 255, 0.85)'
},
colorAxis: {
dataClasses: [{
from: -100,
to: 0,
color: '#C40401',
name: 'McCain'
}, {
from: 0,
to: 100,
color: '#0200D0',
name: 'Obama'
}]
},
series : [{
data : data,
dataLabels: {
enabled: true,
color: '#FFFFFF',
format: '{point.code}',
style: {
textTransform: 'uppercase'
}
},
mapData: Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small']),
joinBy: keys,
name: 'Democrats margin',
point: {
events: {
click: pointClick
}
},
tooltip: {
ySuffix: ' %'
},
cursor: 'pointer'
}, {
type: 'mapline',
data: Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small'], 'mapline'),
color: 'silver'
}]
};
/**
* Event handler for clicking points. Use jQuery UI to pop up
* a pie chart showing the details for each state.
*/
function pointClick() {
var row = this.options.row,
$div = $('<div></div>')
.dialog({
title: this.name,
width: 400,
height: 300
});
window.chart = new Highcharts.Chart({
chart: {
renderTo: $div[0],
type: 'pie',
width: 370,
height: 240
},
title: {
text: null
},
series: [{
name: 'Votes',
data: [{
name: 'Obama',
color: '#0200D0',
y: parseInt(columns[3][row], 10)
}, {
name: 'McCain',
color: '#C40401',
y: parseInt(columns[4][row], 10)
}],
dataLabels: {
format: '<b>{point.name}</b> {point.percentage:.1f}%'
}
}]
});
}
// Read the columns into the data array
var data = [];
$.each(keys, function (i, key) {
data.push({
key: key,//.toUpperCase(),
value: parseFloat(percent[i]),
name: names,
row: i
});
});
// Initiate the chart
window.chart = new Highcharts.Map(options);
},
error: function () {
$('#container').html('<div class="loading">' +
'<i class="icon-frown icon-large"></i> ' +
'Error loading data from Google Spreadsheets' +
'</div>');
}
});
});
UPDATE:
I wanted to share with everyone my final solution. Although Ondkloss did a magnificent job answering my question the popup feature still didn't work and this is because I forgot to include the jQuery for the .dialog call. Once I included that I had an empty popup with a highchart error 17, this is because the highmaps.js code doesn't include the pie chart class. So I had to add the highcharts.js code and include map.js module afterward. You can see my final jsfiddle here.
Thanks again to Ondkloss for the excellent answer!
The problem here mostly comes down to the use of joinBy. Also to correct it there are some required changes to your data and mapData.
Currently your joinBy is an array of strings, like ["al", "ak", ...]. This is quite simply not an accepted format of the joinBy option. You can read up on the details in the API documentation, but the simplest approach is to have a attribute in common in data and mapData and then supply a string in joinBy which then joins those two arrays by that attribute. For example:
series : [{
data : data,
mapData: mapData,
joinBy: "hc-key",
]
Here the "hc-key" attribute must exist in both data and mapData.
Here's how I'd create the data variable in your code:
var data = [];
$.each(keys, function (i, key) {
if(i != 0)
data.push({
"hc-key": "us-"+key,
code: key.toUpperCase(),
value: parseFloat(percent[i]),
name: names[i],
row: i
});
});
This skips the first key, which is just "Key" (the title of the column). Here we make the "hc-key" fit the format of the "hc-key" in our map data. An example would be "us-al". The rest is just metadata that will be joined in. Note that you were referencing your data in the options prior to filling it with data, so this has to be moved prior to this.
This is how I'd create the mapData variable in your code:
var mapData = Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small']);
// Process mapdata
$.each(mapData, function () {
var path = this.path,
copy = { path: path };
// This point has a square legend to the right
if (path[1] === 9727) {
// Identify the box
Highcharts.seriesTypes.map.prototype.getBox.call(0, [copy]);
// Place the center of the data label in the center of the point legend box
this.middleX = ((path[1] + path[4]) / 2 - copy._minX) / (copy._maxX - copy._minX);
this.middleY = ((path[2] + path[7]) / 2 - copy._minY) / (copy._maxY - copy._minY);
}
// Tag it for joining
this.ucName = this.name.toUpperCase();
});
The first part is your "standard map data". The rest is to correctly center the labels for the popout states, and gotten directly from the example.
And voila, see this JSFiddle demonstration to witness your map in action.
I suggest doing some console.log-ing to see how data and mapData have the hc-key in common and that leads to the joining of the data in the series.

Date not displaying correctly on x-axis in High Stock Charts

I am working on stock charts where i have to show the stock data of three currencies. I am able to see the chart and rates corresponding to it but dates on x axis are not coming properly. my json response is like this .
[{"rate":1.3349,"month":"1422403200000"},{"rate":1.3415,"month":"1422316800000"},{"rate":1.3394,"month":"1422230400000"},{"rate":1.3202,"month":"1421971200000"},{"rate":1.304,"month":"1421884800000"},{"rate":1.3109,"month":"1421798400000"},{"rate":1.3017,"month":"1421712000000"},{"rate":1.3114,"month":"1421625600000"},{"rate":1.305,"month":"1421366400000"},{"rate":1.292,"month":"1421280000000"},{"rate":1.2876,"month":"1421193600000"},{"rate":1.2819,"month":"1421107200000"},{"rate":1.2801,"month":"1421020800000"}]
its just an example of json response. in my java vo rate is of double type and month is of String type.
my js code is here
function drawChart(){
var seriesOptions = [],
seriesCounter = 0,
names = ['EURGBP', 'EURJPY', 'EURCHF'],
// create the chart when all data is loaded
createChart = function () {
$('#drawchart').highcharts('StockChart', {
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent'
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2
},
series: seriesOptions
});
};
$.each(names, function (i, name) {
$.getJSON('/bin/drawChart, function (data) {
var dataArray = new Array;
$.each(data, function (i, obj) {
dataArray.push([obj.month,obj.rate]);
});
alert(dataArray);
seriesOptions[i] = {
name: name,
data: dataArray,
tooltip: {
valueDecimals: 2
}
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter += 1;
if (seriesCounter === names.length) {
createChart();
}
});
});
}
Why date is not appearing correctly on x-axis
The problem is that in your JSON should be fields x and y. Morever values should be number not string as you have. So you should prepare correct JSON structure in your backend or parse it after loading.
your X-axis information is missing in draw chart method

Adding Dynamic Data Series to High charts

×212414
×123754
I am calling a PageMethod in codebehind.aspx.cs file which returns me a string array[] in the javascript code in the aspx page the problem at hand is that string array returns Time(X axis-Value),Data/Name(Y axis Value),Type(Defines the type of chart (Spline or Column)) from a WEB SERVICE. I am using that data to add series dynamically to the chart. Using the function chart.AddSeries() but I am unable to do so.
Can anyone please guide me how to do that and upon doing that I want to add points to the particular Series.
Please Note that I would be displaying to types{Spline and Column} on the same chart.
<script type="text/javascript">
alert("Bingo");
$(function () {
$(document).ready(function () {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart;
chart = new Highcharts.Chart({
chart: {
renderTo: 'ltrChart',
type: 'spline',
marginRight: 10,
events: {
load: function () {
PageMethods.GetSingleValue(function (result) {
var Name = new Array();
var Type = new Array();
var Data = new Array();
var Time = new Array();
var Ser = chart.series;
for (var i = 0; i < 6; i++) {
Type[i] = result[i].split('-')[0];
Name[i] = result[i].split('-')[1];
Data[i] = result[i].split('-')[2];
Time[i] = result[i].split('-')[3];
chart.addSeries({ name :Name[i], data : [ [Time[i], Data[i]] ] }, true, true);
/* Test Method To ensure data Fetching */
// alert(Type[i] + Name[i] + Data[i] + Time[i]);
// alert(result[i]);
}
})
//console.log(typeof PageMethods.GetSingleValue);
// PageMethods.GetSingleValue();
setInterval("PageMethods.GetSingleValue()", 5000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
//type: 'datetime',
//tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Test Data',
data: [[10, 50], [15, 55]]
}]
});
});
});
</script>
This is what I've done and works like a charm. On a side-note, since you mentioned aspx page, why don't you just buy the dot net highcharts library? It makes life a lot easier if you're a dot net fan!
I am initially creating a chart with 5 elements, and then using the "iterated" JSON serialized string to pass data to client-side. Traversing the elements gives me a dynamic live chart!
Highcharts chart = new Highcharts("livechart")
.InitChart(new Chart
{
Events = new ChartEvents { Load = "ChartEventsLoad" }
})
.SetSeries(initialSeries)
.SetXAxis(new XAxis { Categories = lsst.ToArray() })
.AddJavascripVariable("iterated", iterateData.ToString())
.AddJavascripVariable("index", "5")
.AddJavascripFunction("ChartEventsLoad",
#"// set up the updating of the chart each 5 seconds
var result = iterated;
var theseries = eval(result); // De-serializing the JSON object
var loopseries = function() {
var sseries = livechart.series[0]
,shift = sseries.data.length > 5; // shift if the series is longer than 5;
sseries.addPoint(theseries[0].data[index], true, shift);
var sseries1 = livechart.series[1]
sseries1.addPoint(theseries[1].data[index], true, shift);
index++; };
setInterval(loopseries, 5000);")
You can add as many series as you like; you can use a loop if needed and the same code I've added as a function can be used to create the chart completely in Javascript.

Categories