Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Format chart.js x labels

I use chart.js with React. My question is how to show the month label (MMM) only once per month?

The chart currently has labels: [May 15, May 18, May 21, May 24, ...]
As result I want to get: [May 15, 18, 21, 24, 27, 30, Jun 2, 5, ...]

CodeSandbox

enter image description here

Line Chart:

import React from 'react'
import { Line } from 'react-chartjs-2'
import date from 'date-and-time'

const startDate = new Date(2020, 4, 15)

//===fake data===
const json = '{"responses":[{"rows":[{"values":["1"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["1"]},{"values":["6"]},{"values":["7"]},{"values":["5"]},{"values":["8"]},{"values":["9"]},{"values":["2"]},{"values":["1"]},{"values":["1"]},{"values":["1"]},{"values":["6"]},{"values":["3"]},{"values":["0"]},{"values":["20"]},{"values":["9"]},{"values":["3"]},{"values":["2"]},{"values":["1"]},{"values":["13"]},{"values":["3"]},{"values":["13"]},{"values":["13"]},{"values":["7"]},{"values":["12"]},{"values":["0"]}]}]}'
const values = JSON.parse(json).responses[0].rows.map((row, index) => {
  let date = new Date(2020, 4, 20)
  date.setDate(startDate.getDate() + index)
  return {
    y: row.values[0],
    x: date,
  }
})
//===============

const options = {
  legend: {
    display: false,
  },
  hover: {
    mode: 'index',
    intersect: false,
    animationDuration: 0,
  },
  scales: {
    yAxes: [{ position: 'right' }],
    xAxes: [{
      gridLines: { display: false },
      distribution: 'linear',
      type: 'time',
      time: {
        parser: 'MMM D',
        tooltipFormat: 'MMM D',
        unit: 'day',
        unitStepSize: 3,
        displayFormats: {
          day: 'MMM D',
        },
      },
      ticks: {
        min: startDate,
        max: date.format(date.addDays(new Date(), 1), 'MMM D'),
        autoSkip: true
      },
    }],
  },
  tooltips: {
    mode: 'x-axis',
  },
}

const data = {
  datasets: [
    {
      label: 'test',
      fill: false,
      data: values,
      backgroundColor: '#fff',
      borderWidth: 2,
      lineTension: 0,
      borderColor: 'forestgreen',
      hoverBorderWidth: 2,
      pointBorderColor: 'rgba(0, 0, 0, 0)',
      pointBackgroundColor: 'rgba(0, 0, 0, 0)',
      pointHoverBackgroundColor: '#fff',
      pointHoverBorderColor: 'forestgreen',
      showLine: true,
    }
  ],
}

const LineChart = () => <Line data={data} options={options}/>

export default LineChart
like image 797
Arthur Avatar asked Jul 30 '20 08:07

Arthur


People also ask

How do I label the axis in a chart?

When creating a chart, you want to tell the viewer what data they are viewing. To do this, you need to label the axis. Namespace: options.scales [scaleId].title, it defines options for the scale title. Note that this only applies to cartesian axes. If true, display the axis title. Alignment of the axis title.

How do I format labels?

Formatting labels is very simple by using a culture name, and a format string. By default the culture name 'en-US' indicating US English language is used. However, all cultures are supported. Example: cultures Enum All possible culture names. A format string can be used with an axis to specify the type of values the axis represents.

How do I format a number or date without a chart?

Number or date values can be formatted without a chart as well by using the JSC.formatDate () and JSC.formatNumber () utility functions. This is useful when using a function with chart label text properties instead of strings. The following references list the supported format strings that can be used with formatString properties:

How to use labelformatter to display the value on axis?

By using labelFormatter, you can return any value to be displayed on axis. Note If you have to access any preset options of the chart, you can access them via e.chart.options. For example e.chart.options.title.text


Video Answer


2 Answers

Solution 1 label filter: According to the filtering labels sample you can set a function to define what should be displayed:

options: {
    scales: {
        x: {
            display: true,
            ticks: {
                callback: function(dataLabel, index) {
                    // Apply logic to remove name of the month
                    return dataLabel
                }
            }
        },
        y: {
            display: true,
            beginAtZero: false
        }
    }
}

Github source of the example

Solution 2: You could prepare your labels array beforehand. Filter the occurence of all the upcoming mentions and feed this array to chart.js.

like image 132
lotype Avatar answered Oct 19 '22 13:10

lotype


  1. Define different displayFormats for day and month.
  2. Enable ticks.major.
  3. Mark the desired ticks as major through the afterBuildTicks callback.
time: {
  ...
  displayFormats: {
    day: 'D',
    month: 'MMM D',
  },
},
ticks: {
  major: {
    enabled: true
  }
},
afterBuildTicks: (scale, ticks) => {
  ticks.forEach((t, i) => t.major = i == 0 || new Date(t.value).getMonth() != new Date(ticks[i - 1].value).getMonth());
  return ticks;
}

Please take a look at your amended code and see how it works.

const startDate = new Date(2020, 4, 15)

//===fake data===
const json = '{"responses":[{"rows":[{"values":["1"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["1"]},{"values":["6"]},{"values":["7"]},{"values":["5"]},{"values":["8"]},{"values":["9"]},{"values":["2"]},{"values":["1"]},{"values":["1"]},{"values":["1"]},{"values":["6"]},{"values":["3"]},{"values":["0"]},{"values":["20"]},{"values":["9"]},{"values":["3"]},{"values":["2"]},{"values":["1"]},{"values":["13"]},{"values":["3"]},{"values":["13"]},{"values":["13"]},{"values":["7"]},{"values":["12"]},{"values":["0"]}]}]}'
const values = JSON.parse(json).responses[0].rows.map((row, index) => {
  let date = new Date(2020, 4, 20);
  date.setDate(startDate.getDate() + index)
  return {
    y: row.values[0],
    x: date
  }
})

//===============

const options = {
  legend: {
    display: false
  },
  hover: {
    mode: 'index',
    intersect: false,
    animationDuration: 0
  },
  scales: {
    yAxes: [{
      position: 'right'
    }],
    xAxes: [{
      gridLines: {
        display: false
      },
      distribution: 'linear',
      type: 'time',
      time: {
        tooltipFormat: 'MMM D',
        unit: 'day',
        unitStepSize: 3,
        displayFormats: {
          day: 'D',
          month: 'MMM D',
        },
      },
      ticks: {
        major: {
          enabled: true
        }
      },
      afterBuildTicks: (scale, ticks) => {
        ticks.forEach((t, i) => t.major = i == 0 || new Date(t.value).getMonth() != new Date(ticks[i - 1].value).getMonth());
        return ticks;
      }
    }]
  },
  tooltips: {
    mode: 'x-axis',
  }
};

const data = {
  datasets: [{
    label: 'test',
    fill: false,
    data: values,
    backgroundColor: '#fff',
    borderWidth: 2,
    lineTension: 0,
    borderColor: 'forestgreen',
    hoverBorderWidth: 2,
    pointBorderColor: 'rgba(0, 0, 0, 0)',
    pointBackgroundColor: 'rgba(0, 0, 0, 0)',
    pointHoverBackgroundColor: '#fff',
    pointHoverBorderColor: 'forestgreen',
    showLine: true,
  }],
};

new Chart('myChart', {
  type: 'line',
  data: data,
  options: options
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="myChart" height="90"></canvas>
like image 1
uminder Avatar answered Oct 19 '22 11:10

uminder