0
votes

I'm trying to plot some sparse values over a few hundred x-axis category labels. The labels represent points along a geographical entity, so it is necessary to space them according to the actual distance between each point.

I can easily make x-axis categories and plot the values against them, but each category is evenly spaced. If I change to using a complex marker with {x, y, name} properties, the categories are only displayed if they match the tick interval. If a category doesn't match the tick interval, then a number is displayed.

I can produce the following:

highcharts screenshot showing x-axis category labels

with this small fake sample of data, JSFiddle:


    ...
    xAxis: {
        type: 'category'
    },
    series: [{
        name: 'Series 1',
        data: [
          {x:1, y:null, name: 'AB1.1'},
          {x:4, y:1, name: 'AB1.2'},
          {x:5, y:null, name: 'AB1.3'},
          {x:11, y:1, name: 'AB1.4'},
          {x:14, y:null, name: 'AB1.5'},
          {x:14, y:null, name: 'AB1.6'},
          {x:19, y:1, name: 'AB1.7'},
          {x:27, y:1, name: 'AB1.8'},
          {x:28, y:null, name: 'AB1.9'},
          {x:30, y:1, name: 'AB2'},
          {x:37, y:1, name: 'AB2.1'},
          {x:37, y:1, name: 'AB2.2'},
          {x:38, y:1, name: 'AB2.3'},
        ]
    }]
    ...

As you can see, the x-axis at this zoom level shows: 0, 3, 6, 9, 12, 15, 18, 21, 24, AB1.8, AB2, 33, 36, 39

What I want is for the x-axis to show any of the actual labels (so long as the markers are placed relative to their distance, just like the x-values of the plot); but no generated numbers.

In reality, I have multiple series with around 1,000 points each, but they will all be on the same geographical entity so they all share the same categories. (JSFiddle with much more fake data). I can also guarantee that x-values are whole numbers.

I have already tried specifying various x-axis options around ticks, minimum ticks etc. but highcharts still wants to extrapolate evenly spaced labels.

Thanks!

2

2 Answers

1
votes

I have got the results I want (JSFiddle) by setting xAxis.tickPositions dynamically on zoom. To begin with, I pick about 35 x-Axis positions to display my markers (an arbitrary number but I picked something that worked for my fixed-width chart size).

Then, on zoom, I update the chart to display about 30 markers that are within the new zoom level.

This way I always have a good number of markers displayed, and they are unevenly spaced because that's what my actual data is like.

Zoomed out (L) and zoomed in (R):

Zoomed out Zoomed in

this is an array of all x-axis points that have a marker-a few thousand

allTicks = [1, 6, 9, 9, ...]

a function to select 30 points from the given array

function selectTickPositions(tickPositions) {
    const maxTicks = 30;
    if (tickPositions.length <= maxTicks) return tickPositions; // return all
    let mod = Math.round(tickPositions.length / maxTicks);
    // always select the first and the last, and then up to 30 more
    return tickPositions.filter((val, idx) => idx == 0 || idx == tickPositions.length - 1 || idx % mod == 0);
}

setup the chart options:

let theChart = Highcharts.chart('container', {
    chart: {
        ...
        events: {
          // the selection event is fired when a zoom selection is made
            selection: (event) => {
                let ticks;
                if (event.xAxis) {
                    let min = event.xAxis[0].min;
                    let max = event.xAxis[0].max;
                    ticks = selectTickPositions(allTicks.filter(t => t >= min && t <= max));
                } else {
                    ticks = selectTickPositions(allTicks);
                }
                theChart.update({
                    xAxis: {
                        tickPositions: ticks
                    }
                });
                return true;
            }
        }
    },
    ...
    xAxis: {
        type: 'category',
        tickPositions: selectTickPositions(allTicks)
    },
});
0
votes

I am not sure if I understand your requirement very well, but here is my attempt of showing just a xAxis.labels if the label is a category string.

Demo: https://jsfiddle.net/BlackLabel/4xdjw5L7/

xAxis: {
  type: 'category',
  endOnTick: true,
  startOnTick: true,
        labels: {
            formatter() {
                if (typeof this.value !== 'number') {
                    return this.value
                }
            }
        }
},

API: https://api.highcharts.com/highcharts/xAxis.labels.formatter

Let me know if this is an expected output.