Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repeating same tick values #4748

Closed
ostrolucky opened this issue Sep 12, 2017 · 19 comments
Closed

Repeating same tick values #4748

ostrolucky opened this issue Sep 12, 2017 · 19 comments

Comments

@ostrolucky
Copy link

screenshot from 2017-09-12 14 39 08

See Y axis? This is caused because we are returning rounded value in options.yAxes.ticks.callback. So chart.js calls callback with 0, 0.1 ... 0.9, 1.0, 1.1 values, but callback returns 0, 1 only. Repeating same values in a chart is undesirable for end user.

In userspace, I've applied following fix to solve this issue:

// this is to prevent repeating tick values
var middlewareToMakeTicksUnique = function(next) {
    return function(value, index, values) {
        var nextValue = next(value);

        if (index && values.length > index+1 && // always show first and last tick
            // don't show if next or previous tick is same
            (next(values[index + 1]) === nextValue || next(values[index - 1]) === nextValue)
        ) {
            return null;
        }

        return nextValue;
    }
};

...

yAxes: [{
    ticks: {
        callback: middlewareToMakeTicksUnique(function (value) {
            return value.format();
        })
    }
}]
@etimberg
Copy link
Member

@ostrolucky do you have a fiddle that reproduces this?

@ostrolucky
Copy link
Author

@etimberg
Copy link
Member

I'm not entirely convinced this is a bug. The callback is explicitly formatting the string values for ticks like 0.8 to be 1 and so 1 is displayed. The conversion to strings happens after all the ticks have been calculated.

Using a callback to only display certain ticks is recommended. Here I've written a simple one that only returns ticks that are integers and removes the others. If you want grid lines to show up for the hidden ticks, return '' instead of null.

@ostrolucky
Copy link
Author

I don't care about classification of this, I never mentioned it's a bug. I don't see current behaviour as sensible though. I don't see any use case where it's useful when values shown there are duplicated, do you? I also don't see why is developer forced to work around this. Developer never provided non-integer value, but Chart.js tries to display them. I've never see this in other charting solutions.

@ostrolucky
Copy link
Author

Closing as this is unlikely to be fixed.

@sstruct
Copy link

sstruct commented Nov 8, 2017

@etimberg same here. I need to format ticks' value with different units, this solution couldn't help.

Can this issue be reopened please?

@sstruct
Copy link

sstruct commented Nov 8, 2017

Worked out a temporary solution:

ticks: {
  beginAtZero: true,
  // formatValue convert value to be suffixed, eg: 0.2 -> 20%
  callback: value => formatValue(value),
  /**
   * userCallback
   * @param label
   * @param index
   * @param labels
   * @return {*}
   */
  userCallback: (label, index, labels) => {
    // _ refers to [lodash](https://lodash.com/)
    if ((_.every(labels, lb => Math.abs(lb) < 1) && Math.floor(label * 100) === label.toFixed(4) * 100)
          || Math.floor(label) === label
          || index === 0) {
      return formatValue(label);
    }
  },
},

ref: https://stackoverflow.com/questions/37699485/skip-decimal-points-on-y-axis-in-chartjs


Another Solution Now:

/**
 * fix issue: https://trello.com/c/7MeGZsmu
 * @param label
 * @param index
 * @param labels
 * @return {*}
 */
userCallback: function(label, index, labels) {
  const formatedLabel = formatValue(label, unitDesc);
  const formatedLabels = _.map(labels, lb => formatValue(lb, unitDesc));
  const counts = _.countBy(formatedLabels);
  if (counts[formatedLabel] === 1
    || index === labels.length - 1
    || index === 0) {
    return formatedLabel;
  }
},

@ostrolucky
Copy link
Author

Since I see other people have same problem, reopening

@ostrolucky ostrolucky reopened this Nov 16, 2017
@sabelofficial
Copy link

It'd be great if this would be fixed soon

@etimberg
Copy link
Member

There is a proposal to add a way of forcing integer steps in #4841

@nagix
Copy link
Contributor

nagix commented Dec 24, 2018

Closing as this was solved in #4841 and is already available in version 2.7.3 (setting ticks.precision to 0, no need for callback).

@nagix nagix closed this as completed Dec 24, 2018
@nagix nagix modified the milestones: Version 2.8, Version 2.7.3 Dec 24, 2018
@pimvanderheijden
Copy link

pimvanderheijden commented Jan 31, 2019

Using precision: 0 (or even { precision: 0, integerSteps: true }) and still have repeating tick values, as described above

version 2.7.3

@pimvanderheijden
Copy link

I got it working now. What helped was converting the (y) values first, before constructing a label in ticks.callback . Appears to me that Chart.js does filter identical values only before the callback and not after.

@eakkew
Copy link

eakkew commented Feb 8, 2019

I got the solution by using suggestedMin, suggestedMax, and stepSize

https://www.chartjs.org/docs/latest/axes/cartesian/linear.html#axis-range-settings

@JIGARKAPADIYA
Copy link

Repeating values are not seen in graph any one who has resolved it please send the 'options' of chart

@tapistefan
Copy link

tapistefan commented Dec 17, 2020

I was struggling with this problem for hours at last "precision: 0" solved this for me.
options: { scales: { yAxes: [{ ticks: { beginAtZero: false, fontSize: 20, precision:0 } }] } }

@tansinjahan
Copy link

I got it working now. What helped was converting the (y) values first, before constructing a label in ticks.callback . Appears to me that Chart.js does filter identical values only before the callback and not after.

@pimvanderheijden I am facing the same problem and my current code converts the y-value inside callback function and then constructs the label inside. Could you please give more context about how did you manage to filter the identical values before the callback??

@pimvanderheijden
Copy link

pimvanderheijden commented Jun 9, 2021

I think I meant I mapped the set of x and y values [{ t, y }, ... ] first so that the x has the right format before going into Chart.js.

const original = [{ t1, y2 }, { t2, y2 } ]
const chartJsReady = original.map(({ t, y }) => { return { t: new Date(t).toISOString(), y })

Not really sure if this answer the question honestly

@tansinjahan
Copy link

I think I meant I mapped the set of x and y values [{ t, y }, ... ] first so that the x has the right format before going into Chart.js.

const original = [{ t1, y2 }, { t2, y2 } ]
const chartJsReady = original.map(({ t, y }) => { return { t: new Date(t).toISOString(), y })

Not really sure if this answer the question honestly
Doesn't solve my problem 100% so had to do some workaround but yeah thanks for replying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests