Chart.js: Line Chart - Data series without label for each point

Created on 18 Mar 2013  Â·  96Comments  Â·  Source: chartjs/Chart.js

From the Line Chart documentation,

"The line chart requires an array of labels for each of the data points. This is show on the X axis."

I would like to be able to add a large set of data points to a line chart, but not have a label for each data point. For instance, showing the months of the year on the x axis but having several data points between January and February. I know the project is young, but would you agree this is a good direction to go? I feel the x axis labels and data set should be decoupled.

Most helpful comment

The use case I'm having (and I don't really see solved with any of the mentioned changes), is the following:

I have a dataset of 255 data samples. On my X axis though I only want to show 0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90%, 100% as the labels. And, obviously, these labels don't really match an exact sample in my data array. They're somewhere in between. E.g. 0% = 0, 10% = 25.5, etc.

The simplest solution would be if chart.js would not match the labels with the samples in case of a line chart, but simply would draw the lines and then draw the labels independently below the chart.

E.g. it would help if I could simply specify:
labels = ['0%', '50%', '100%'];
datasets = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]];

and chart.js would automatically divide the labels linearly through the data instead of matching them to the first three samples in my data.

All 96 comments

Yes, or chart.js should have a way to hide data points based on width, kind of what like google charts does. For instance, displaying data for Jan 1-30, but the graph is only x pixels wide, it shows Jan 1-30, but skips every other date.

@humdedum That is a pretty stupid comment. There is nothing wrong with feature enhancements, they should not be taken negatively, but positively by people being interested in @nnnick's projects. It gives him a good idea of what to improve for his users.

I plan on trying to contribute to this project, and reading some of these issues/feature enhancements gives me a good idea of what other people are thinking as well.

As for using "" as a label, that might work right now, but I am sure user interaction/tooltips will come soon, and that will not work when displaying default tooltip information.

@humdedum I was suggesting decoupling x axis labels from data points because for a line chart, I imagine a greater percentage of use cases not requiring labels for each point than those that do. It seems inefficient from that regard. Since the project is young, I am trying to raise thought rather than rush to find a workaround.

@humdedum but this suggestion will definitely improve this project. People pull data from databases all the time to draw these charts and the last thing they want to do is have to determine which labels stay and which labels go.

For example, if I pull an integer column for my data points and a date column for my labels in the database, I'm not going to want to have to filter out those date columns based on the width of the canvas and the number of points on my chart.

Not everyone creates static HTML pages. " :-)".

@r043v Looks good. Did you ever form a PR for that?

@r043v This is definitely a welcome improvement, but how is skipLabels used? Adding "skipLabels : [int]" as an option does not make any change to the line chart or it's labels. Maybe I misunderstood your idea, documentation about it would be helpful.

Line charts are simply indexed across the x axis, so they need a label for each point.

A potentially better solution would be to create a .Series chart (maybe extending from Chart.types.Line) as an extension to the core library.

Is there an open issue for creating such "Series" chart?

Not as of yet, it is something I made a very brief start on in the past though.

I think it should probably live in it's own repo rather than this repo, so perhaps creating an issue here isn't the best idea. That way there could be alternate community run variants etc.

I added showXLabels option for .Line and .Bar. A pull request has been raised at: https://github.com/nnnick/Chart.js/pull/521 [ @nnnick ]

With it, you can set the number of labels to display on the X-Axis by passing the option {showXLabels: 10} where 10 is roughly the number of labels to be displayed.

Original Graph:
err-graph

Modified Graph with {showXLabels: 10} option:
great-graph

@humdedum I feel like you're missing the entire point of open source software. If contributors were silenced and "good enough" was accepted as the norm, we'd still be using Linus Torvald's (wonderful at the time) Linux 1.0. Hell, Github wouldn't even have a reason for existing.

As I'm dealing with very large numbers of data points (500+), a graphing library that requires labels is unusable as shown by @hay-wire's first graph above. I love the look of this library, and may try my hand at a PR as well.

@loganfuller you can use skip-xlabels branch from my fork of Chart.js with showXLabels option:
https://github.com/hay-wire/Chart.js/tree/skip-xlabels
Hope it solves your problem.
However, I am thinking of fixing the label rotation as well when showXLabels is passed. I shall post an update here if I do it anytime around!

I think this isn't the right solution to this problem. The line charts in Chart.js are designed to handle index data, so just skipping the render of certain labels feels like a hacky solution.

What I propose as a better solution would be to define an x/y value for a point, then have Chart.js dynamically generate the x scale, similar to how the y scale is generated dynamically currently.

It'd require data in slightly different format, so that's why I propose another chart type for this. I think a lot of the base classes for points/bars/whatever could be reused, with an extension to/a new scale class providing this dynamic x/y functionality.

What do you guys think?

If you want to hide the labels when there are too many, you can use the following extension. It just pushes the x-labels off the canvas so they are painted but not visible.

  Chart.types.Line.extend({
     name : "AltLine",

     initialize : function(data) {
        Chart.types.Line.prototype.initialize.apply(this, arguments);
        this.scale.draw = function() {
           if (this.display && (this.xLabelRotation > 90)) {
              this.endPoint = this.height - 5;
           }
           Chart.Scale.prototype.draw.apply(this, arguments);
        };
     }
  });

  // then
  new Chart(ctx).AltLine(data, options);

Love this chart.js. How can I configure it so the label is alway on by default without hovering it?

There is a great hack here.

I quote:

For concreteness, let's say your original list of labels looks like:

["0", "1", "2", "3", "4", "5", "6", "7", "8"]

If you only want to display every 4th label, filter your list of labels so that every 4th label is filled in, and all others are the empty string (e.g. ["0", "", "", "", "4", "", "", "", "8"]).

@nnnick, any news on this feature? I think a lot of people need it as it's pretty common to have a lot of data on your x-axis.

:+1: i need this too

Very interested in this feature. I have a a graph I need to create with 1,000+ points across X. Do I use one of the hacked modules or is this coming into the main branch? Thanks for great software!

I'm using '' as labels

The problem with using '' as labels is, that Graph.js still 'renders' them (although invisible). This means that the other, visible, labels are still angled against the axis, even though there is now enough room to render them horizontally (see @hay-wire comment and graphs above).
I would much rather prefer to define skipped labels as false and have the remaining labels render normally?

screen shot 2014-11-26 at 3 55 14 pm

This is google analytics line chart. as you can see all the days are not labeled in the x axis but the data of each day is in the line chart, and if you hover on each Dot a tooltip will show the date & the Y value.
I think this is the best solution, if anyone can implement it. Other solutions like using '' as labels or skip labels are kinda hacky solutions.
@nnnick I think it's exactly what you were saying about this feature request.

Thanks again for your great project.

@sepehr-y this is exactly what my skipLabels option do
skip labels

And can you skip labels altogether?

On Thursday, November 27, 2014, Sören Schwert [email protected]
wrote:

But can you still see the correct labels when you hover over a data point
whose label is skipped?
Sent using CloudMagic
On Thu, Nov 27, 2014 at 2:25 pm, noferi mickaĂ«l <[email protected]
wrote:@sepehr-y this is exactly what my skipLabels option do

—Reply to this email directly or view it on GitHub.

—
Reply to this email directly or view it on GitHub
https://github.com/nnnick/Chart.js/issues/12#issuecomment-64796440.

King Harrison IV

Executive Vice President
[email protected]
Linkedin Profile https://www.linkedin.com/in/kingharrison/
877.725.1305 ext: 504
www.k3s.com

@r043v how do you use your skipLabels option? I'm also interested in this!

Fully agree with @nnnick that a Scale is the right solution and not a skip labels option to avoid chart.js growing to complex.

I created a gist that shows how to implement a series chart. The implementation is not perfect but working!

https://gist.github.com/saintedlama/05cc1663f3e38e06e2d7

Hey guys. Loving chart.js but this is a bit of a downside, any news on whether there's gonna be anything incorporated into the master branch any time soon?

+1 for this feature request

+1 this is a must be feature

+1

+1

perhaps we should open a new issue as this one is closed

+1

I'll reopen

The pull request #521 sorts this issue out, can any of the collaborators take a look at it?

@Ehesp I'm going to merge once it can be automatically merged. Looks Great!

I'v updated showXLabels with latest pull from Chart.js' latest master branch. Its in a separate branch "showXLabels" in my fork at: https://github.com/hay-wire/Chart.js/tree/showXLabels

A corresponding pull request has been raise at https://github.com/nnnick/Chart.js/pull/897.

Any progress on any of these PRs being merged into chart.js?

Almost 2 years since this issue was opened, and the showXLabels hack is still the best option we have? This avoids professional usage of this library, which is a pitty, since it looks pretty nice

:+1: to @trufa, thanks for the tip and it made my charts look less messy when doing large sets.

:8ball: any update on when will this be merged or available for use?

Looking for this solution as well. Thanks

My hack was similar to what mentioned by @trufa , which is replace label with "". But when dealing with large dataset , the label text will rotate even when we use "" to skip most of the labels.

To fix that, I checked the source code and found, we just need to slightly modify code in Chart.js

First locate to: function "calculateXLabelRotation"
and then replace

//Allow 3 pixels x2 padding either side for label readability
var xGridWidth = Math.floor(this.calculateX(1) - this.calculateX(0)) - 6;

with

//Allow 3 pixels x2 padding either side for label readability
var _leftIndex = -1;
var _rightIndex = -1;
for (var i = 0; i < this.xLabels.length; i++) {
    if (_leftIndex < 0 && this.xLabels[i]) {
        _leftIndex = i;
        continue;
    }
    if (_leftIndex >= 0 && this.xLabels[i]) {
        _rightIndex = i;
        break;
    }
}
var xGridWidth = Math.floor(this.calculateX(_rightIndex) - this.calculateX(_leftIndex)) - 6;

Note: this hack only works when you show at least 2 labels and show labels periodically,
for example: ["0", "", "", "","", "5", "", "", "", "","10"], you show every 5th label.

Hope this can help someone who has the same issue.

:+1: For this request

:+1:

:+1:

+1

+1 strongly needed

++1

+1

+1

+1

+1

+1

+1

+1

:+1:

:shipit:

+1

Is there a plan or at least agreed-upon idea for how this should be implemented? Chart.js is great but this is a huge limitation for displaying time series type data. Either another chart type or more dynamic scaling on the x-axis would work I'd think.

It seems like the best solution would be to dynamically scale things on the x-axis if there are more 'data' elements than labels?

@qiaorancho comment is working for me, though unprofessional

+1

+1

I would love to see this merged...

+1

To provide an update on this, we are working towards solving this issue in the v2.0-dev branch. So far in that branch we've worked on tooltips, but our next big focus is to split the internal representation of x & y axes. Ultimately, we're planning to add support for an arbitrary linear x axis. We also plan to make it easier to support axis extensions so that adding something like a logarithmic axis does not require a new chart type.

At the moment there is no timeline for when v2.0 may be released and the code is not currently stable, but you can follow the progress in https://github.com/nnnick/Chart.js/tree/v2.0-dev

it's really helpful option :+1:

Huzzah! The first alpha of Chart.js 2.0 has landed and should fix this issue. Check out the release and try it out! We've got a lot of momentum right now, so please help us test so we can launch 2.0 Gold by the end of the month.
https://github.com/nnnick/Chart.js/releases/tag/v2.0-alpha

I'm closing this issue for now, but if you have implementation questions or find bugs, please create a jsfiddle and post the link here and we'll reopen this issue and get it fixed.

Could someone show a snippet of how to utilize the fix? I've tried to use hay-wire's pull and v2.0-alpha.
But I cannot seem to find how to activate it.

Regards,

@ehajri sync down the v2.0-dev branch and build it. You need to use the scatter chart type rather than the line type.

@etimberg, how do I specify the number of displayed X labels?

@ehajri We don't have a hard count on the number of labels. If you use a line chart in v2.0 it should behave exactly as a line chart in v1.0. We created the scatter chart that has a different x axis which dynamically adjusts the number of labels (not user settable at the moment). At the moment the x axis of the scatter chart only supports numerical data. We're going to write a date/time scale before 2.0 releases but it has not been done yet,

What kind of labels do you have? In the v2.0 config you can specify a user callback for each axis as

config: {
    scales: {
        xAxes: [{
            labels: {
                userCallback: function(tickValue, index, tickArray) { return "label string"},
           }
        }],
    }
}

You could return an empty string for no label. Does this help? Can you create a jsfiddle of your use case and I can try and give some better advice.

Guys It was sa irritating I did it using two solutions and adding my hack ;)

  1. get @hay-wire solution Chart.js
  2. modify @qiaorancho solution like this:

Replace
//Allow 3 pixels x2 padding either side for label readability
var xGridWidth = Math.floor(this.calculateX(1) - this.calculateX(0)) - 6;

With:

if(this.showXLabels === true || this.showXLabels === false)
var xGridWidth = Math.floor(this.calculateX(1) - this.calculateX(0)) - 6;
else{
var gap = Math.floor(this.xLabels.length/this.showXLabels);
var _leftIndex = -1;
var _rightIndex = -1;
for (var i = 0; i < this.xLabels.length; i=i+gap) {//dynamic gap between labels based on labels/showxlabels
if (_leftIndex < 0 && this.xLabels[i]) {
_leftIndex = i;
continue;
}
if (_leftIndex >= 0 && this.xLabels[i]) {
_rightIndex = i;
break;
}
}
var xGridWidth = Math.floor(this.calculateX(_rightIndex) - this.calculateX(_leftIndex)) - 6;
}

Now pass the option:

showXLabels,

to get requested nr of labels! Or you can leave it false and it works original way

The following snippet will hide labels automatically. By modify xLabels with empty string before invoke draw() and restore them after then. Even more, re-rotating x labels can be applied as there's more space after hiding.

var axisFixedDrawFn = function() {
    var self = this
    var widthPerXLabel = (self.width - self.xScalePaddingLeft - self.xScalePaddingRight) / self.xLabels.length
    var xLabelPerFontSize = self.fontSize / widthPerXLabel
    var xLabelStep = Math.ceil(xLabelPerFontSize)
    var xLabelRotationOld = null
    var xLabelsOld = null
    if (xLabelStep > 1) {
        var widthPerSkipedXLabel = (self.width - self.xScalePaddingLeft - self.xScalePaddingRight) / (self.xLabels.length / xLabelStep)
        xLabelRotationOld = self.xLabelRotation
        xLabelsOld = clone(self.xLabels)
        self.xLabelRotation = Math.asin(self.fontSize / widthPerSkipedXLabel) / Math.PI * 180
        for (var i = 0; i < self.xLabels.length; ++i) {
            if (i % xLabelStep != 0) {
                self.xLabels[i] = ''
            }
        }
    }
    Chart.Scale.prototype.draw.apply(self, arguments);
    if (xLabelRotationOld != null) {
        self.xLabelRotation = xLabelRotationOld
    }
    if (xLabelsOld != null) {
        self.xLabels = xLabelsOld
    }
};

Chart.types.Bar.extend({
    name : "AxisFixedBar",
    initialize : function(data) {
        Chart.types.Bar.prototype.initialize.apply(this, arguments);
        this.scale.draw = axisFixedDrawFn;
    }
});

Chart.types.Line.extend({
    name : "AxisFixedLine",
    initialize : function(data) {
        Chart.types.Line.prototype.initialize.apply(this, arguments);
        this.scale.draw = axisFixedDrawFn;
    }
});

Please notice that clone is an external dependency.

http://stackoverflow.com/a/32569127/837697

Any ideas when v2 will be out with this feature?

v2.0-dev already has multiple ways of achieving this. Primarily, there is a built in auto-skip feature that will reduce labels as they overlap in most circumstances. You can also override the labels via a userCallback function that is used in the core scale class, or even override the entire scale.ticks array with whatever you want in a hook function. We're working on documentation for these new features right now.

how??

For those who are trying to get rid of the x-axis labels altogether, while retaining y-axis labels, I was able to achieve this with the following:

  • In chart data: labels: [""]
  • In chart options, add object.label = "ToolTipTitle"; before the line specifying the values that should be returned

Any word on where the documentation for this can be found?

Can you make the x axis time / date data with a scatter chart? I don't see anything in the docs about it.

+1, docs pls

If it's of any help, I get the desired effect of reducing the numbers of objects in the X label by adding the following line:

Chart.defaults.scale.ticks.autoSkipPadding = X;

Where X is the padding you want between the values (and it will create an empty space accordingly), try adjusting the X value so it suits your needs.

+1 It's a shame this feature request has been around for so long and nothing has been done.

@gentisaliu this is supported in v2 out of the box. See https://github.com/chartjs/Chart.js/blob/master/samples/scatter.html

Thanks, I missed that. I tested it and it works, however is there a way to control the number of displayed labels/ticks in the X axis?

I want to display for instance at most 4 labels in the X axis, since any more than that they overlap and they get difficult to read.

Awesome job and thank you all. Is this also supported on bar charts for a series of dates? I can't seem to make this work.

This question is now a couple of years old. Is there in the current version a better solution to achieve this? I can not seem to make this work. Or is there some documentation where I can find this?

What is the exact question? This is quite a thread with many questions/answers. As for the original question, you have a lot of control over labels in v2.x.x. Check out the callbacks in the scales documentation, afterTickToLabelConversion would probably best work or add a callback directly into the ticks configuration.

Use highcharts. i ended up doing the same.

I have the same problem. I am creating a chart by dynamically assigning value to both labels and dataset. But at certain point, label are not showing. label data is generating but not showing.

The use case I'm having (and I don't really see solved with any of the mentioned changes), is the following:

I have a dataset of 255 data samples. On my X axis though I only want to show 0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90%, 100% as the labels. And, obviously, these labels don't really match an exact sample in my data array. They're somewhere in between. E.g. 0% = 0, 10% = 25.5, etc.

The simplest solution would be if chart.js would not match the labels with the samples in case of a line chart, but simply would draw the lines and then draw the labels independently below the chart.

E.g. it would help if I could simply specify:
labels = ['0%', '50%', '100%'];
datasets = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]];

and chart.js would automatically divide the labels linearly through the data instead of matching them to the first three samples in my data.

+1
An suggestion can be that you place each unequal label a bit lower?

Like so:
L | L | L | L
L L L

A good solution would be if each data-point could be an object or array and contain an optional label

Example:

datasets: [{
    data: [1,2,3,4,5,[6,'Special Label'],7,8,9,10,[11,'Yet another labeled point']
}]

Or somesuch.

@george-viaud you need close expression with ]

Was this page helpful?
0 / 5 - 0 ratings