On a Highcharts chart with datetime axis, I am trying to highlight weeks. First, I had the idea to use the grid and to set tickInterval to 7*24*60*60*1000 and minorTickInterval to 24*60*60*1000. With the option gridLineWidth set to 2, the result is almost perfect.
The problem is when zooming: minor ticks appears but without label. I can not find how to add it. And the labels are not dynamic.
You can try this demo: https://jsfiddle.net/gdebrion/19x4nmp5/19/
First chart is the basic one. When you zoom you can see the changes in x-axis.
Second chart is mine. The weeks are visible but when zooming in until having a day display on the full width, and the only ticks visible are the minor one, without label…
Please tell me if you have an idea. Thanks!
The API does not provide a way to display labels on minor ticks.
http://www.highcharts.com/docs/chart-concepts/axes
MINOR TICKS
If the minorTickInterval option is set, minor ticks are laid out between the major ones. This includes minor tick marks, and minor grid lines, which have their own options for look and feel, but excludes labels.
Having a peek at the source code for Highcharts, I also do not see any label representation for minor ticks as there are for the major ticks (axis.labelEdge = [];) .
https://github.com/highcharts/highcharts/blob/b6bc666da00d37c5c4e3c0d7fe238b8526e583ea/js/parts/Axis.js
...
// Major ticks
axis.ticks = {};
axis.labelEdge = [];
// Minor ticks
axis.minorTicks = {};
// List of plotLines/Bands
...
UPDATE:
Here is a slightly rough solution to enable minor tick labels for highcharts:
http://jsfiddle.net/strince/deuez7gk/
The code doesn't handle overlapping labels when the zoom is far out so you'll need to zoom in a bit to see it work.
The chart code was updated with:
// Keep track of elements created.
var minorTickLabels = new Array();
...
events: {
load: function() { addMinorTickLabels(this); },
redraw: function() { addMinorTickLabels(this); }
}
...
function addMinorTickLabels(chart) {
// The elements need to be destroyed, otherwise a dictionary
// internal to highcharts will accumulate and pollute the chart.
for (var i = 0; i < minorTickLabels.length; i++) {
var textItem = minorTickLabels[i];
textItem.destroy();
}
minorTickLabels = new Array();
var axis0 = chart.xAxis[0];
var lastIndexFound = 0;
for (var tick in axis0.minorTicks) {
var el = axis0.minorTicks[tick];
// Skip double labels on major ticks.
var index = axis0.tickPositions.indexOf(el.pos, lastIndexFound);
if (index >= 0) {
listIndexFound = index;
continue;
}
var xPos = el.mark.getBBox().x;
var yPos = el.mark.getBBox().y;
var labelText = 0;
// The formatting parameters below should be passed in.
var textItem = chart.renderer.text(Highcharts.dateFormat("%d. %b", el.pos), xPos, yPos)
.css({
color: '#101010',
fontSize: '8px'
})
.attr({
rotation: -25,
zIndex: 6
});
// Add the tick label to the chart.
textItem.add();
minorTickLabels.push(textItem);
}
};
Related
I am trying to create a bubble chart using the JS HighChart in Angular2+. Whenever there are more than 50 data points (bubbles), the graph breaks. There are the correct number of bubbles in the correct positions (x,y plots) with all different colors but the sizes are all the same even though the z-values are all different. (I am outputing the z-values in a tooltip and the z-values are accurate)
This function is how I am passing in data to the high-chart configuration.
setSeries() {
this.objData = []
this.Data.forEach(element => {
var x= element['xVal'];
var y = element['yVal'];
var z = element['zVal'].toFixed(0);
var name = element['seriesName'].trim();
var newData =[{
x:x,
y:y,
z:+z,
}]
// SetSeriesData is how i am creating the obj to pass into series=[] in highchart configuration
if(i<50) //If I comment this condition, the graph breaks. Right now, the graph is working properly
this.setSeriesData(sumData, name, this.objData)
i++
})
this.options.series = this.objData;
this.generateChart();
}
This is my setSeriesData function.
setSeriesData(graphData: any, dataName: any, objData: any){
var obj = {};
obj['name'] = dataName;
obj['data'] = graphData;
obj['events'] = {click: function(e) {
//takes me to another link
}};
objData.push(obj)
}
In the above function, I configured the chart so that when you click the bubble, it takes you to another page. When the data points >50, this click functionality is not working either. In addition, the fillOpacity is not correct.
Just a few things to point out
1. I am using Angular 2+
2. The discovered issues are, fillOpacity, click, and size based on z-value.
3. It works perfectly when the data points are less than 50
How can I fix this?
The data series in my HighCharts chart only includes dates from the past few days, but the chart's x-axis and zoom bar show a date range all the way back to 1970.
How can I limit the presented date range so it only goes back as far as the first date present in the series data?
Example
HTML
<div id="chart_container" style="height: 500px></div>
JavaScript
$(function () {
var timestamps = [1481000484000,1481108510000,1481215541000,1481316568000,1481417583000];
var series_raw_data = [100,300,750,400,200];
// prepare data
var points = [[],[]];
for (var i = 0; i < timestamps.length; i++) {
points.push([timestamps[i], series_raw_data[i]]);
}
// create chart
$('#chart_container').highcharts('StockChart', {
series: [{
data: points
}]
});
});
Here's Fiddle1 which shows the behavior.
I also tried setting the xAxis 'min' option to the first timestamp, and setting the axis type to 'datetime', but those didn't help - Fiddle2.
The reason why it happens is your points array.
If fact, after filling, it looks like this:
points = [ [], [], [x, y], [x, y]]
Those two empty arrays create unwanted behaviour.
Fix the initial array and it works
var points = [];
example: https://jsfiddle.net/hbwosk3o/3/
I have 2 Series on one graph. Only one series can show at a time but the hidden graph affects the range on the x-axis.
The data is dynamically generated via PHP but here is 2 fiddles to show what I mean:
Fiddle With Changed Scale and Hidden Data
Fiddle With removed Hidden Data and correct scale
This code snippet is to ensure that only one series can be shown at any given time.
events: {
show: function () {
var chart = this.chart,
series = chart.series,
i = series.length,
otherSeries;
var seriesName = this['options']['name'];
chart.yAxis[0].axisTitle.attr({
text: seriesName
});
while (i--) {
otherSeries = series[i];
if (otherSeries != this && otherSeries.visible) {
otherSeries.hide();
}
}
}
I am not sure why the graph with the hidden data shows until 16:00 but the graph without any additional data shows until the last data point at 15:38
It appears that Highcharts is taking into account the pointRange of the series with the largest pointRange (although it is hidden) and displaying the x-axis based on that. The range of your "Calls/Hour" series is 1 hour, so it makes sure that if that series had a point at the very end, it would still have room to show.
I'm not sure if there's any elegant way of solving this, but a bit of a "hack" in your case is to change the pointRange of all series to that of the currently showing one.
My crude implementation of this has three changes to your code:
Your series that are visible: false by default also get pointRange: 1 so they don't disrupt the x-axis range for the only visible series.
When the chart has been created we store the correct point range of each series for future reference, for example with the callback function:
$('#callFrequencyGraph').highcharts({
// Options...
}, function(event) {
var series = this.series;
// Store the correct point ranges
for(var i = 0; i < series.length; i++) {
series[i].update({
historicalPointRange: (series[i].closestPointRange ? series[i].closestPointRange : 3600000)
}, false);
this.redraw();
}
}
Extend your events.legendItemClick function to update all series pointRange to that of the series which will be showing after the click is completed:
legendItemClick: function() {
if(this.visible){
return false;
}
else {
var series = this.chart.series;
for(var i = 0; i < series.length; i++) {
series[i].update({
pointRange: this.options.historicalPointRange
}, false);
}
}
}
See this updated JSFiddle for the result of all these changes.
Edit: jsFiddle Update for bug
I have a spiderweb graph with just the one data series. In the interests of printing I'd like to incorporate the value plotted in the label after the actual label name but I can't seem to work out how to do so.
This example to help explain what I mean is a bar-graph that I found in my search. The code layout is similar and a lot less cluttered than mine and I'm fairly sure a solution on this one would be easily transferable.
labels: {
formatter: function() {
return this.value + ' XX.X';
}
}
JSFiddle Here
So for the X axis I'm trying to replace the "XX.X" with the relevant Y value to get the labels: "Foo 29.9 | Bar 71.5 | Foobar 106.4"
I dug through "this" in the xAxis labels formatter and got as far as finding the Y figures at "this.chart.series[0].yData", but couldn't work out a way to associate these back to each relevant X label, and I thought it seemed the wrong way of going about things anyway.
You can do this after rendering of the chart in the chart.events.load method using setCategories. This code below assumes that each index element on the xAxis has a corresponding data element. If it doesn't then you would need to handle that case.
chart: {
events: {
load: function (event) {
var cats = this.xAxis[0].categories;
var theData = this.series[0].data;
var newCats = [];
for (var i = 0; i < cats.length; i++) {
newCats.push(cats[i] + ' ' + theData[i].y)
}
this.xAxis[0].setCategories(newCats);
}
}
}
Live demo.
I would like to set different properties for my labels on the xAxis (Here is my problem).
I know how to do this for dataLabels : API.
It is similar to this.
But I don't find anything to do the same thing for xAxis.labels.
Does it exist a way to do this ?
Solution :
It changes only y property of xAxis labels.
Here is a jsFiddle.
chart: {
renderTo: 'container',
type: 'column',
events: {
load: function () {
var xAxis = this.xAxis[0];
var serie = this.series[0];
for (var current_tick in xAxis.ticks) {
var tick = xAxis.ticks[current_tick];
if(serie.data[current_tick]){
if (serie.data[current_tick].y > 0) {
tick.label.attr({
y: tick.label.y + 18
});
}
}
}
}
}
}
I am not aware of a way to do that.
What I would probably do in this situation is create to x axes, one for the positive values, and one for the negative.
{{edit - although, it seems the axis offset plugin only works (at least from what I am seeing) if you have opposite: true set for the axis.
SO, you have to offset the labels on one of them. example:
http://jsfiddle.net/jlbriggs/S48eX/