load data in highcharts from 2 different csv files - highcharts

I am trying to find out if I can get a graph using 2 sources (one for the categories, another for the actual data plotted.
I find myself often in need to use the same category for different series; but I can't code in the chart itself, since they are not global. As example picture a temperature sensor data: it uses Celsius and my category fits in a specific user case; which apply to all my temperature sensors but if I need to use data coming from a pressure sensor, then I need to change unit of measure and other parameters in the category.
To alleviate; I can simply write functions on the fly, that generate directly from the server, a ton of specific csv files; but I thought that I can just grab bits and pieces instead from the files that the server already returns.
But I can't find an example about how would you set different files as source for the category and the series. Is this possible or should I just make a ton of ad hoc single csv files?
EDIT
I am using the standard example that is on the highcharts site, to load a csv file; it is not on JSFiddle so I can just paste the link to that web example: http://www.highcharts.com/studies/data-from-csv.htm
What I did was to duplicate the $.get function, using a different file name, but it won't work; so I tried to change also the data name, and that didn't work either:
$(document).ready(function() {
var options = {
chart: {
renderTo: 'container',
type: 'column'
},
title: {
text: 'Fruit Consumption'
},
xAxis: {
categories: []
},
yAxis: {
title: {
text: 'Units'
}
},
series: []
};
/*
Load the data from the CSV file. This is the contents of the file:
Apples,Pears,Oranges,Bananas,Plums
John,8,4,6,5
Jane,3,4,2,3
Joe,86,76,79,77
Janet,3,16,13,15
*/
$.get('data.csv', function(data) {
// Split the lines
var lines = data.split('\n');
$.each(lines, function(lineNo, line) {
var items = line.split(',');
// header line containes categories
if (lineNo == 0) {
$.each(items, function(itemNo, item) {
if (itemNo > 0) options.xAxis.categories.push(item);
});
}
// the rest of the lines contain data with their name in the first position
else {
var series = {
data: []
};
$.each(items, function(itemNo, item) {
if (itemNo == 0) {
series.name = item;
} else {
series.data.push(parseFloat(item));
}
});
options.series.push(series);
}
});
$.get('data2.csv', function(data) {
// Split the lines
var lines = data.split('\n');
$.each(lines, function(lineNo, line) {
var items = line.split(',');
// header line containes categories
if (lineNo == 0) {
$.each(items, function(itemNo, item) {
if (itemNo > 0) options.xAxis.categories.push(item);
});
}
// the rest of the lines contain data with their name in the first position
else {
var series = {
data: []
};
$.each(items, function(itemNo, item) {
if (itemNo == 0) {
series.name = item;
} else {
series.data.push(parseFloat(item));
}
});
options.series.push(series);
}
});
var chart = new Highcharts.Chart(options);
});
});

Here you can find example how to load three files as series: http://www.highcharts.com/stock/demo/compare
So the only difference would be that you are using just one series, and second file will be used for categories data.
In above solution added is some global counter, to render chart after all files are received.
Second solution will be to call second AJAX inside callback for a first one, snippet:
$.getJSON(url1, function(data) {
$.getJSON(url2, function(data2) {
// create chart here
});
});
Edit:
If you have two CSV files, this is what you need to change:
$.get(url1, function(data1) {
$.get(url2, function(data2) {
// parse data1
var parsedData1 = ...
// parse data2
var parsedData2 = ...
$("#container").highcharts({
series: [{
data: parsedData1
}, {
data: parsedData2
}]
});
});
});

Related

highcharts mapchart: no color shown after reload the graph

I am new to high charts.
Below is my partial code in a function when creating a mapChart, what it does is that it only show the matching region (with cur_state) as red and others as blue.
chart: {
backgroundColor: null,
map: 'countries/au/au-all',
events: {
load: function () {
// place1
this.series[0].data = this.series[0].data.map((el) => {
// place2
if (el['hc-key'] == region_dict[cur_state][1]) {
el.color = "#ff0000";
return el;
}
el.color = "blue"
return el
})
this.update({
series: [{
data: this.series[0].data
}]
})
}
}
},
When the value of cur_state is changed, I recall the function which contains the map graph, hoping that the corresponding region has color update.
This is the first time I call the function:
This is after second time I call the function, the coloring and hovering effect are gone:
After testing, I realised that both place1 and place2 are executed when the chart is firstly created, and only place1 is executed when the chart is re-created.
My other part of code has similar structure as this: https://jsfiddle.net/gh/get/library/pure/highslide-software/highcharts.com/tree/master/samples/mapdata/countries/au/au-all
How can I achieve the expected outcome?
Thanks for helping
The best solution in your case seems to be to use render event and change the color on the SVG level. Example:
chart: {
...,
events: {
render: function() {
this.series[0].points.forEach(function(point) {
if (point['hc-key'] == state) {
point.graphic.attr({
fill: 'red'
});
}
});
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/x69pLcyo/
API Reference:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr

How to get points information when hovering over axis labels in highcharts using custom-events library?

I have a bar chart with labels. Is it possible to get the "points" data by hovering over said labels using custom-events library?
By points data I mean the variable from here:
tooltip: {
useHTML: true,
formatter(this: { points: any[] }) {
}
}
You can loop through all series points and match a point with a label position. Example:
xAxis: {
...,
labels: {
events: {
mouseover: function() {
const points = [];
this.axis.series.forEach(s => {
s.points.forEach(point => {
if (point.x === this.pos) {
points.push(point);
}
})
});
console.log(points);
}
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/3xvgtw2c/

JqGrid searchoptions with select2 existing value

I'm trying to integrate select2 for JqGrid filter form. I'm using JqGrid min 4.6 & Select2 min 4.0.1. The filter works fine but I'm unable to retrieve the value that has been set through select2 once the filter form is closed and reopened. i.e. dataInit e1 does not return the existing value of the select input. I must be doing something wrong?
JqGrid Column Model:
{
name: 'CurrencyID', hidden: true, search: true, stype: 'select', searchtype: 'number', searchoptions: {
searchhidden: true,
sopt: ['eq', 'ne'],
dataInit: function (el) {
intiGridFilterSelecr2Field(el, paramFromView.CurrencyOptions);
}
},
searchrules: { required: true }
},
Parameters:
#section scripts{
<script>
var paramFromView = {
CurrencyOptions: {
searchURL: '#Url.Action("GetCurrency", "Controller")',
detailURL: '#Url.Action("CurrencyDetailsJson", "Controller")',
idField: 'CurrencyID',
txtField: 'Description'
}
};
</script>
}
Select2 Helper:
function intiGridFilterSelecr2Field(element, options) {
var comboPageSize = 15;
var quietMillis = 200;
var placeHolderText = 'Choose...'
var defaults = {
searchURL: '',
detailURL: '',
idField: '',
txtField: ''
};
var options = $.extend({}, defaults, options);
var select2Element = $(element);
select2Element.select2({
width: 'element',
minimumInputLength: 1,
placeholder: placeHolderText,
ajax: {
url: options.searchURL,
dataType: 'json',
quietMillis: quietMillis,
cache: false,
data: function (params) {
return {
name: params.term,
page: params.page,
pageSize: comboPageSize
};
},
processResults: function (data) {
var more = (data.page * comboPageSize) < data.total;
var resultsArr = [];
for (var i = 0; i < data.result.length; i++) {
resultsArr.push({ id: data.result[i][options.idField], text: data.result[i][options.txtField] });
}
return { results: resultsArr, more: more };
}
},
}).each(function (index, element) {
var idCombo = $(this);
// The problem is that idCombo.val() is always empty.
// element:select2-hidden-accessible
if (idCombo.val() != null && idCombo.val().length > 0) {
$.ajax(options.detailURL, {
data: {
id: idCombo.val()
},
dataType: 'json',
cache: false
}).done(function (data) {
var optselected = select2Element.find('option').filter(function () { return this.value == data[idField] && this.text == data[txtField] && this.selected })
if (optselected == undefined || optselected.length == 0) {
var $optionContact = $("<option selected></option>").val(data[idField].toString()).text(data[txtField]);
var toBeRemoved = select2Element.find('option').filter(function () { return this.value == data[idField] });
if (toBeRemoved != undefined) {
toBeRemoved.remove();
}
select2Element.append($optionContact).trigger('change.select2');
}
});
}
});
}
When the filter is being set...
When Loading the existing filter. How do I pass this CurrencyID = 1 to select2 helper?
Update:
With Oleg's answer, I updated my code as below.
{
name: 'CurrencyID', hidden: true, searchtype: 'number', search: true,
stype: "select", searchoptions: {
searchhidden: true,
sopt: ["eq", "ne"],
dataUrl: paramFromView.CurrencyOptions.searchURL,
buildSelect: function (data) {
var obj = jQuery.parseJSON(data);
var i, options = [];
for (i = 0; i < obj.result.length; i++) {
options.push("<option value='" + obj.result[i][paramFromView.CurrencyOptions.idField] + "'>" +
obj.result[i][paramFromView.CurrencyOptions.txtField] + "</option>");
}
return "<select>" + options.join("") + "</select>";
},
noFilterText: "Any",
selectFilled: function (options) {
setTimeout(function () {
$(options.elem).select2({
width: 'element',
});
}, 0);
}
},
searchrules: { required: true }
},
I'm almost there with what I wanted to achieve. However I'm still facing some difficulties.
When the filter is initially loaded, value is selected on the dropdown but query value is empty. i.e. if the user clicks on the find button soon after the filter form is loaded, no filter will be set.
I still cannot get select2 styles working.
I can demonstrate how to use select2 with free jqGrid fork of jqGrid, which I develop. I get the demo from the README of the old version 4.14.1 (the current released version is 4.15.3) and modified it to demonstrate the usage of select2.
The main part of the code could be
stype: "select",
searchoptions: {
sopt: ["eq", "ne"],
...
selectFilled: function (options) {
setTimeout(function () {
$(options.elem).select2({
width: "100%"
});
}, 0);
}
}
See https://jsfiddle.net/Lae6kee7/2/. You can try to choose an option in the filter toolbar in "Shipped via" column and the open the search dialog. You will see that the select2 will have the same option selected.
If you would load the data via Ajax request posted by select2 than your code will be much more complex as it could be. It's important to understand that such way is really required only for really large set of possible value. I means the number of items larger as 100000 items for example. On the other side, the most use cases required less as 1000 options. In the case it would be more effective to load all the data as options of select and then convert the select to select2. select2, which uses local select works much more quickly from the users point of view.
The code will be easier in my opinion if you will use dataUrl instead of ajax option of select2. You can use dataUrl to return from the server all different values, which can be used in select2 and to use buildSelect to build <select> from JSON data returned from the server. The demo https://jsfiddle.net/Lae6kee7/23/ demonstrates that. I made the demo for JSFiddle, which supports Echo service (see here), which allows to simulate server responses. Your real code should contains mostly only dataUrl, buildSelect and the code of selectFilled, which I included above.
Additionally, I'd recommend you to consider to use <datalist> (see here for example), which could be good alternative to select2. All modern web browsers contains native support of <datalist> and thus <datalist> works very quickly. Try to search in the first Client column of my demos. You will see control, which will be very close to select2. Additional advantage of <datalist>: one will be able not search for only exact predefined values like test10, test11 or test12, but for substrings like 1. Compare
with
or
with

Highchart duplicates data on chart instead of refreshing it

I am using the highcharts library to collect data from a csv file every 2 minutes and dispaly it in the graph.
Instead of refreshing the data, the function just duplicates the data and my browser ends up crashing. Can some one help ? i am running out of ideas. Below is my code. I have removed all the xAxis,Yaxis,legend from the code to make it shorter
<script type="text/javascript">
var chart;
var options = {
chart: {
renderTo: 'container',
defaultSeriesType: 'spline',
events: {
load: function() {
setInterval(function(){
refresh('file.csv');
}, 120000);
}
}
},
tooltip: {
valueSuffix: ' Views'
},
legend: {
layout: 'left'
},
series : []
};
function refresh(file) {
if(chart) chart.destroy();
$.get(file, function(data) {
var lines = data.split('\n');
$.each(lines, function(lineNo, line) {
var items = line.split(',');
var series = {
data: []
};
$.each(items, function(itemNo, item) {
if (itemNo == 0) {
series.name = item;
} else {
series.data.push(parseFloat(item));
}
});
options.series.push(series);
});
chart = new Highcharts.Chart(options);
});
}
$(document).ready(function() {
refresh('file.csv');
});
</script>
<div id="container"></div>
Instead of destroy chart, you can use setData / addSeries function which allows to manipulate data. http://api.highcharts.com/highcharts#Chart.addSeries
http://api.highcharts.com/highcharts#Series.setData

Highcharts.js - multiple themes on same page?

I have about 6 charts on one page, one of them needs to have a different theme from the other five. I have the themes working individually but the second one initialized is applied to all the charts.
Is there a way to specify which theme a chart uses?
After reading Ricardo's comment I realized I just had to move the setOptions() call inside the $(document).ready call.
A much simplified version of my code:
Highcharts.theme1 = {
chart: {
borderWidth: 0,
},
};
var chart;
$(document).ready(function() {
// Apply the theme
var highchartsOptions = Highcharts.setOptions(Highcharts.theme1);
// Build the chart
chart = new Highcharts.Chart({});
});
Highcharts.theme2 = {
chart: {
borderWidth: 5,
},
};
var chart2;
$(document).ready(function() {
// Apply the theme
var highchartsOptions = Highcharts.setOptions(Highcharts.theme2);
// Build the chart
chart = new Highcharts.Chart({});
});
Best practice currently would be to merge in the theme with your chart options:
chart1 = new Highcharts.Chart(Highcharts.merge(options1, theme1));
var options1 = {
// options goes here
chart: {
renderTo: 'chart1',
type: 'bar',
},
title: {
text: 'Conversions'
},
};
var theme1 = {
// themes goes here
};
var chart1 = new Highcharts.Chart(Highcharts.merge(options1, theme1));
this way you can set individual themes for each chart if you need too

Resources