Colors doesn't change using Highcharts.setOptions - javascript

I have a page displaying multiple charts. I set the theme to be used for all charts according to the code below:
Highcharts.theme = {
colors: ["#E37B25", "F5BF36", "#7C1C1D", "#458744", "#3E7FA3", "#0C9BD7", "#265667"],
...
}
Highcharts.setOptions(Highcharts.theme);
I then have a bunch of specific options for each chart and create the charts in a set interval.
var chart;
chart = new Highcharts.Chart(chartOptions);
The problem is that every time a chart is created it has the first color in the array, instead of rotating through them. I thought setOptions() would manage this for each chart but apparently it doesn't. How can this be done so every time i create a new chart using new Highcharts.Chart(chartOptions) it selects the next color in the array?

As #wegeld commented, colors in the array are given as list option which are used by series elements of the chart rather than charts in successive manner.
But if that is the requirement, you can create a colorIterator and do following. I have create a codepen example for you here: https://codepen.io/mikhilraj/pen/KrjzxN/
var colorIterator = 0;
function getColor() {
var color = Highcharts.getOptions().colors[colorIterator%Highcharts.getOptions().colors.length];
colorIterator++;
return color;
};
And add following in as options while creating the chart.
series: [{
name: 'John',
data: [0, 1, 4, 4, 5, 2, 3, 7],
fillColor: getColor()
}]

Related

Set dynamic regions for each y axis group

I would like to implement an alternate region background to the chart, sort of like a striped table look.
Is there a way for me to dynamically set the regions for each y-axis block? Once I can do this, I can just basically use css to set alternating background colors.
The regions can be set statically like this:
http://c3js.org/samples/region.html
To do it dynamically, you'd just need to use the API:
http://c3js.org/reference.html#api-regions e.g.
chart.regions([
{axis: 'x', start: 5, class: 'regionX'},
{axis: 'y', end: 50, class: 'regionY'}
]);
So to get alternating stripes build up a regions array as so after generating your chart object:
// find range of all data
var allData = d3.merge (chart.data().map(function(d) {
return d.values.map (function(dd) { return dd.value; });
}));
var dataRange = d3.extent(allData);
dataRange.min = Math.min (dataRange[0], 0);
dataRange.extent = dataRange[1] - dataRange.min;
// set number of pairs of stripes
var stripeCount = 5;
var step = dataRange.extent / stripeCount;
var newRegions = [];
// then divide the data range neatly up into those pairs of stripes
d3.range(0,stripeCount).forEach (function(d) {
newRegions.push ({axis: 'y', start: dataRange.min+(step*d), end: dataRange.min+(step*(d+0.5)), class: 'stripe1'});
newRegions.push ({axis: 'y', start: dataRange.min+(step*(d+0.5)), end: dataRange.min+(step*(d+1)), class: 'stripe2'});
});
// set the new regions on the chart object
chart.regions(newRegions);
css:
.c3-region.stripe1 {
fill: #f00;
}
.c3-region.stripe2 {
fill: #0f0;
}
(If, alternatively, you wanted to make a new stripe pair every 10 units on the y scale you would just make step=10; and change the d3.range to d3.range(0,dataRange.extent/step))
I forked off someone's bar chart on jsfiddle and added the striping --> http://jsfiddle.net/k9c0peax/

Highcharts: How to exempt a series from redraw zoom calculations?

In this jsfiddle the chart has a nice zoom effect every time the visiblity of a series is toggled.
But when I add the UpperLimit series this effect is lost because that series has the lowest and highest x-values.
How can I make the chart zoom in on the series of my choice and keep other series from affecting zoom boundaries?
{
name: 'UpperLimit',
color: '#FF0000',
dashStyle: 'ShortDash',
showInLegend: false,
//affectsZoomBox: false, //No such thing :(
data: [
[1, 100],
[10, 100]
]
},
I don't think it is possible using configuration of the series. However, if you are willing to hack a bit it will be possible to exclude one or more series from the calculation of axis extremes:
chart.xAxis[0].oldGetSeriesExtremes = chart.xAxis[0].getSeriesExtremes;
chart.xAxis[0].getSeriesExtremes = function() {
var axis = this;
var originalSeries = axis.series;
var series = [];
for (var i = 0; i < originalSeries.length; i++) {
// Filter out the series you don't want to include in the calculation
if (originalSeries[i].name != 'UpperLimit') {
series.push(originalSeries[i]);
}
}
axis.series = series;
axis.oldGetSeriesExtremes();
axis.series = originalSeries;
}
The code shows how to overwrite the getSeriesExtremes function on the axis object. The method is replaced with a wrapper that removes the series that should be excluded, then calls the original function and then restores the original series to the axis.
This is clearly a hack. However, it works on my machine...

Grouped bar chart "in one line" with D3.js

I'm trying to make a particular bar chart with D3.js, and I don't find any example who could match. I would code a bar chart with two series (one negative, and one generally positive) disposed on the same line, but not stacked.
I guess that maybe it's not very clear, so I've made this on Highcharts. I want to use D3 to connect the chart with a map I did before.
So, does someone know any example that could help me? Can I sort directly the chart even if my series are unordered? And if the two series are punctually postive, does the little one appear in front of the largest?
The trick is to order your data, in order to do so, you can use the [d3.ascending()][1] functions:
with the following example data:
data = [{
name: "A",
valueRight: 1,
valueLeft: 2
}, {
name: "B",
valueRight: 4,
valueLeft: 5
}, ...]
We would have:
function leftBound(node) {
return d3.max([node.valueLeft,-node.valueRight])
}
function rightBound(node) {
return d3.max([node.valueRight,-node.valueLeft])
}
dataSort = function(a,b) {
res = d3.descending(leftBound(a),leftBound(b))
if(res==0) {
return d3.descending(rightBound(a),rightBound(b))
} else {
return res
}
}
For reusable charts, you can also use [selection.sort()][2] but you have to do this for the 2 bar categories.
JsFiddle: http://jsfiddle.net/vgZ6E/55/
ScreenShot:
The original code is from the following question: d3.js bar chart with pos & neg bars (win/loss) for each record

Kendo ui Bar Chart width/maxWidth of Bars

I got an Kendo ui Bar Chart which is filled with an dynamic array.
One time its filled with 12 items and one time its filled with only 1 item.
Now the Bars automatically resizes, when only one item is in the array, the Bar is super big. I know, that there is no "max-width" or "width" property in the configuration.
Is there a workaround for my problem? I.E. dynamic calculation of the gap/space or whatever property? Or even with css or so?
Here is an simple fiddle
var dataset = [1,2,3,3,5,6,8];
var dataOnlyOne = [10]
//gap:0.2
// gap: function(){
return width/12*... // works not
}
Its been a while, and you probably moved on, but I was searching for something similar...
Your problem could be resolved using the below code, where the gap is calculated from the number of items in the data array:
$(function() {
var data = [1,2,3,3,5,6,8,2,3,3,5,6,8];
// var data = [10];
var gap = 8/data.length
$('#chart').kendoChart({
seriesDefaults: {
type: 'column',
stack: true,
},
series: [
{
name: 'dataset',
data: data, // dataOnlyOne
color: 'blue',
gap:gap
}
]
})
});

Adding data to a highchart chart using an array with IDs

I want to add a series to a highchart scatterplot where I am naming each point in the series. I create a chart in the following way:
var chart; // globally available
makeCharts = function(){
chart = new Highcharts.Chart({
chart: {
renderTo: 'container1',
type: 'scatter'
},
series: [{
name: 'a',
data: [{
'id': 'point1',
'x': 1,
'y': 2
}, {
'id': 'point2',
'x': 2,
'y': 5
}]
}]
});
}
I would like to be able to update the points on the chart using something like:
chart.series[0].setData([{id:['point3', 'point4', 'point5'], y:[0,1,2], x:[1,2,3]}])
but this is not correct. Is it possible to update a chart using this approach where each point has an ID?
EDIT:
Just to clarify, I would like to be able to pass the arrays directly, rather than adding the data point by point using addPoint(). I could loop through an array and use addPoint() doing something like this:
id:['point3', 'point4', 'point5'];
y:[0,1,2];
x:[1,2,3];
for (i=0; i<x.length; i++)
{
chart.series[0].addPoint({
x: x[[i],
y: y[i],
id: id[i]
});
}
However, this is very slow. It's much quicker to add data using the following approach:
chart.series[0].setData([[1,0],[2,1],[3,2]]);
I have found that I can add data like this:
chart.series[0].setData([[1,0, 'point3'],[2,1, 'point4'],[3,2, 'point5']]);
but then the only way that I can access the id when the point is selected, is through this.point.config[2]. With the following approach I am unable to use chart.get('pointID') to identify a point as I did not set the ID. I want to be able to identify the point using just the ID.
Well broadly speaking there are two ways in which you can modify the chart data dynamically
Series.setData() Use this approach when you want to completely replace the existing data with some new data
Series.addPoint() Use this approach when you want to add a subset of the points dynamically. This method is not just for adding one point at a time, if you read the documentation carefully again you will find that this method takes a boolean redraw argument, and the argument detail is as following
redraw: Boolean
Defaults to true. Whether to redraw the chart after
the point is added. When adding more than one point, it is highly
recommended that the redraw option beset to false, and instead
chart.redraw() is explicitly called after the adding of points is
finished.
In your case, since you want to add a few points dynamically, but retaining the existing points, you should go with approach 2. But you need to use it inside a loop, with the redraw being set to false (hence solving the problem of being slow) and then after the loop, call the redraw method explicitly
Code
var id = ['point3', 'point4', 'point5'],
y = [0, 1, 2],
x = [1, 2, 3];
for (var i = 0; i < x.length; i++) {
chart.series[0].addPoint({
x: x[i],
y: y[i],
id: id[i]
},false);
}
chart.redraw();
Adding multiple points dynamically | Highcharts and Highstock # jsFiddle
Try using series.addPoint.
chart.series[0].addPoint({
x: 0,
y: 0,
id: 'anything'
});
But if you need to set data for series, use
chart.series[0].setData([{
x: 0,
y: 0,
id: 'anything'
},{
x: 2,
y: 2,
id: 'another'
}]);
As soon as you can pass your data like this:
chart.series[0].setData([[1,0, 'point3'],[2,1, 'point4'],[3,2, 'point5']]);
(as you stated in question), I can suggest you to use a little hack.
We'll need to add another statement to method applyOptions of Highcharts.Point prototype.
if (typeof options[0] === 'number' && options[2] && typeof options[2] === 'string') this.id = options[2];
Here you can see it in action.

Categories