Highcharts use series labels as x-axis categories - javascript

I have a simple 1-series highchart bar chart where I load the data using json. In my fiddle I just defined the json data as a static variable for simplicity but the premise is the same.
The json data forms the basis for all the series properties, including the name and is formatted like so, which is consistent to many examples I have seen:
var json = [{
"name": "Currency Allocation",
"data": [
["gbp", 0.7053985],
["usd", 0.17856322],
["eur", 0.06901525],
["chf", 0.00135777],
["jpy", 0.00815169],
["em_asia", 0.02821377],
["other", 0.00982446]
]
}];
I would like the label, which is the first element in each data sub-array to be the x-axis category for the chart. However, I seem to have to define the x-axis categories separately under cht.xAxis.categories. Is there a way to avoid doing this and just use the categories in my data?
If I exclude the xAxis.categories property the chart is plotted with just numbers on the x-axis

You can do this on a chart.events.load call and looping through the series[0].data values. Since you say you only have one series per chart I am also assuming you only have one xAxis as well. You would loop through your data like so:
var seriesData = this.series[0].data;
var tCategories = [];
for (i = 0; i < seriesData.length; i++) {
tCategories.push(seriesData[i].name);
}
this.xAxis[0].setCategories(tCategories);
Live demo.
Less complex method is to define your xAxis.type as 'category':
"xAxis": {
"type": "category"
},
Live demo.

Related

How to display Dynamic Object Arrays into chart using Anychart.js

What i am trying to do is i want to display a chart based on my dynamic data i used Angular ForEach to loop through all my objects array see my code below:
var parse = JSON.parse(jsondata);
angular.forEach(parse, function (value, key) {
var dataSet = anychart.data.set(value);
var chart = anychart.column();
var series = chart.column(value);
chart.title("Data Sets: Array of Objects");
chart.container("container");
chart.draw();
});
it correctly display the count of my chart but the data of each object array is not showing up see picture below
but if put a static data like this :
var data = [
{x:"January", value: 12000},
{x:"February", value: 15000},
{x:"March", value: 16000},
{x:"April", value: 14000},
{x:"May", value: 10000}
];
the chart displays correctly.
can anyone help me with this ? any help will greatly appreciated.
Everything depends on the value content inside the loop. You are applying the value to the series and dataSet as well.
If you are using dataSet, you should apply the value to the dataSet, map the data, then apply the mapping to the series. Like this:
var dataSet = anychart.data.set(value);
var mapping = dataSet.mapAs({'x': 0, 'value': 1}); // for example
var chart = anychart.column();
var series = chart.column(dataSet);
The mapping depends on your data. If the value includes ready-to-use data that matches the default mapping you can apply it directly to the series.
Can you share the value content?
The chart can work with dynamic data. All you need is to apply new data to the existing dataSet, like this:
dataSet.data(newData);
And that's it! There's no need to recreate chart/series/dataSet.

Highcharts - gap between series in stacked area chart

I've created a stacked area chart in Highcharts, which you can see in the image below and in the following jsfiddle: http://jsfiddle.net/m3dLtmoz/
I have a workaround for the gaps you see, which is to group the data for each series by month so that each series looks something like this instead:
series: [{
data: [
[1464739200000,2471],
[1467331200000,6275],
[1470009600000,2574],
[1472688000000,7221],
[1475280000000,3228]
]}
]
While the above isn't exactly what I'm going for, the way the series above is structured does give me what I ultimately want, which is this:
I'm really dying to know why the original setup isn't working appropriately, however. I've tested other instances where datetimes group and aggregate properly based on a single datetime x axis value. I'm stumped as to why this particular data set isn't working. I've tried using the dataGrouping option in the Highstock library, but wasn't able to integrate that effectively. I've messed with options as far as tickInterval goes to no avail. I tried setting the "stacking: 'normal' option in each series instead of in the plotOptions, but that made no difference. I've seen issues on github dealing with the stacked area charts, but nothing seems to exactly match up with what I'm seeing. Any help is appreciated - thank you much!
You receive the error in the console. Most of the series require data to be sorted in ascending order. Stacking has nothing do to it, see example.
Series which do not require data to be sorted are scatter or polygon. No error in scatter
You should sort and group the points on your own. If you want to group them by months you have to prepare the data before you put them in a chart. The example below takes averages from the same datetime.
function groupData(unsortedData) {
var data = unsortedData.slice();
data.sort(function (a, b) {
return a[0] - b[0]
});
var i = 1,
len = data.length,
den = 1,
sum = data[0][1],
groupedData = [[data[0][0], sum]],
groupedData = [];
for (; i < len; i++) {
if (data[i - 1][0] === data[i][0]) {
sum += data[i][1];
den++;
} else {
groupedData.push([data[i - 1][0], sum / den]);
den = 1;
sum = data[i][1];
}
}
groupedData.push([data[i-1][0], sum / den]);
return groupedData;
}
example: http://jsfiddle.net/e4enhw9a/1/

D3 sorting with an ordinal scale and selecting top 5

I am trying to sort then select the top 5 in a D3 chart.
I have two series: "OL" and "NOL". The first thing I want to be able to do is to sort and have the labels match on the y axis. The second thing I want to do is to only show the top 5 with the two series still together udner one name in the y axis.
jsfiddle
Data is like so:
var values = feature.properties;
var data = [
{key: "N11", name:"N11OL",value:values["N11OL"]},
{key: "N11", name:"N11NOL",value:values["N11NOL"]},
{key: "N21", name:"N21OL",value:values["N21OL"]},
{key: "N21", name:"N21NOL",value:values["N21NOL"]},
{key: "N22", name:"N22OL",value:values["N22OL"]},
{key: "N22", name:"N22NOL",value:values["N22NOL"]},
{key: "N23", name:"N23OL",value:values["N23OL"]},
{key: "N23", name:"N23NOL",value:values["N23NOL"]},
{key: "N31-33", name:"N31_33OL",value:values["N31_33OL"]},
{key: "N31-33", name:"N31_33NOL",value:values["N31_33NOL"]},
{key: "N41", name:"N41OL",value:values["N41OL"]},
{key: "N41", name:"N41NOL",value:values["N41NOL"]}
];
Right now, the chart works before I sort the bars. When I sort the data with the code below, the ordinal domain doesn't match the bars anymore.
data.sort(function (a, b) {
return d3.ascending(a.value, b.value);
});
I could use
domain(data.map(function(d) { return d.name; }))`
});
to get the names from the data to show on the axis but I want "OL" and "NOL" series to be under one name: N11, etc. not show with all bars. That is why I have set a domain with :
.domain(["NAICS11", "NAICS21", "NAICS22", "NAICS23", "NAICS31-33", "NAICS41"])
That is half of the problem. Once I have sorted and the names are matching with the axis, I would like to have only the top 5 for both series.
I would be very grateful for any suggestions on how to do this.
EDIT I added a key to the data for the pairs and modified the D3 code. I feel this will make it easier going forward to get this chart where I want it.
How about:
// create temporary array with data grouped by
// the first part of our name (cut off the OL/NOL)
var tmp = d3.nest().key(function(d){
return d.name.substring(0, 3);
}).entries(data);
// sort this array descending with the max of our
// now "paired" entries
tmp.sort(function(a,b){
return (d3.max([a.values[0].value,
a.values[1].value]) >
d3.max([b.values[0].value,
b.values[1].value])) ? -1 : 1;
});
// loop our tmp array and
// flatten the data back out
// also use our substring names to for the domain
data = [];
domain = [];
tmp.forEach(function(d){
domain.push(d.key);
data.push(d.values[0]);
data.push(d.values[1]);
});
Updated fiddle.

Highcharts label grouping

I am making a diagram that should show states in a timeline like diagram. I figured that the best fit for it would be horizontal bar diagram, I added data like this:
series: [{
data: [?],
name: 'state1'
}, {
data: [?],
name: 'state2'
}, {
data: [?],
name: 'state3'
}, {
data: [?],
name: 'state1'
}, {
....
}, {
data: [?],
name: 'state1'
}]
Here's what I'v got:
The chart looks like what I need, but I need to somehow group legends, for example this case there should be only 3 legends: state1, state2, state3.
How can I achieve something like this?
I would suggest a different approach, using the column range series type.
This way you can do this with only three series, with a data point for each time slot, rather than a series for each time slot. This saves from having to manipulate the legend or fake other series level actions.
This is an example I did for an earlier question that demonstrates the method (with only two states):
http://jsfiddle.net/jlbriggs/o9ck2zLn/0/
can easily be adapted to use a datetime axis as well, which it seems you might be going for.
Basing on the answer of #StAlex, I would recommend a similar solution, but without the ECMAScript 5 specific forEach:
var legend = {};
for (var i = 0; i < series.length; i++) {
var bar = series[i];
if (!legend[bar.name]) {
legend[bar.name] = 0;
}
legend[bar.name] += bar.data;
}
I assumed that data is a number. If this is not so, add a comment.
var legends = {};
series.forEach(function(bar){
legends[bar.name] = bar.data;
});

Creating a bar chart in D3 from subset of json data. Xaxis is ordinal

[
...
{
"RowID":85,
"Name":"Billy",
"B":2,
"S":2,
"S2":1,
"M":0,
"T":"0",
"H":1,
"S":0,
"W":1,
"N":2,
"Malty":1,
"Fruity":0,
"Floral":0
}
...
]
I need to create a bar chart. Just a regular bar chart.
There are a total of 86 JSON pieces of data (that is, you'll find 86 RowIDs). I only need to pick 5-10 that I want to work with. The x-axis are the "B", "S" ... "Floral" from the JSON. It does NOT include RowID or Name. So there should be "clumps" of 5 bars (colored corresponding to "Name") for each "B", ... "Floral" piece of data. The end goal is to make it easy for the user to visually compare 5 objects (distinguished by Name attribute) according to their attributes.
I've been working at least 24 hours on this problem. And I'm not making any progress. I've looked at tutorials and other posts on StackOverflow. I can't get any of them to work.
Anyone?
And no, this question does not have an answer somewhere else.
A fiddle: http://jsfiddle.net/zdy6d/3/
What you want to do is a grouped bar chart. The main thing you need to do is create 2 x-scales: one that gives the position of each group, or clump as you call it, in the screen and the other one that gives the position of each series (name in this case) inside the group.
// Where to position each clump inside svg chart
var x0 = d3.scale.ordinal();
x0.domain(d3.keys(data[0]).filter(function(key) { return key !== 'RowID' && key !== 'Name'; }));
x0.rangeRoundBands([0, width], 0.1);
// Where to position each name bar inside the clump
var x1 = d3.scale.ordinal();
x1.domain(data.map(function(d) { return d.Name; } ));
x1.rangeRoundBands([0, x0.rangeBand()]);
You then have to filter the data and maybe change its structure to a more convenient format (e.g. [{groupname: 'B', data: [{name: 'Bobby', value: 3}, {name: 'Tom', value: 5}, ... ]}, ...] should be similar to the one the example I linked uses)
Minimal working JSFiddle with example of data manipulation and rect creation: http://jsfiddle.net/LeartS/23huy/2/

Categories