Search code examples
reactjschart.jsreact-chartjsreact-chartjs-2

How to change the color of a specific y-axis in Chart.js?


I'm working with Chart.js to create a line chart that displays two datasets with different y-axes. I want to change the color of one of the y-axes, The x-axis contains the no of tests which starts from 1, so the first tick in the x-axis is 1 and the final tick varies as I am using autoSkip with maxTicksLimit so sometimes the final tick doesn't lie on the second y-axis

const rootStyles = getComputedStyle(document.documentElement);
    const mainColor = rootStyles.getPropertyValue('--main-color');
    const subColor = rootStyles.getPropertyValue('--sub-color');
    const data = {
        labels: [] as number[],
        datasets: [
            {
                label: 'WPM',
                data: [] as number[],
                fill: true,
                backgroundColor: mainColor,
                borderColor: mainColor,
                lineTension: 0.4,
                yAxisID: 'y',
            },
            {
                label: 'Accuracy',
                data: [] as number[],
                fill: true,
                backgroundColor: subColor,
                borderColor: subColor,
                lineTension: 0.4,
                yAxisID: 'y1',
            },
        ],
    };

    const options: any = {
        tooltips: {
            enabled: true,
            mode: 'label',
        },
        bezierCurve: true,
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
            legend: {
                position: 'top',
                display: false,
                labels: {
                    usePointStyle: true,
                    font: {
                        size: 14,
                        family: 'lexend, sans-serif',
                    },
                },
            },
            title: {
                display: false,
            },
        },
        interaction: {
            intersect: false,
        },
        scales: {
            x: {
                title: {
                    display: true,
                    text: 'Test',
                    color: subColor,
                    font: {
                        size: 16,
                        family: 'lexend, sans-serif',
                    },
                },
                ticks: {
                    autoSkip: true,
                    maxTicksLimit: 10,
                    font: {
                        family: 'lexend, sans-serif',
                    },
                    color: subColor
                },
                grid: {
                    color: (context: any) => {
                        if (context.tick.value === data.labels[data.labels.length - 2] // here is the problem
                           || context.tick.value === 0)
                        {
                            return subColor
                        }
                        else {
                            return subColor + "15"
                        }
                    },
                },
            },
            y: {
                min: 0,
                max: Math.max(...wpmData) > 150 ? 290 : 200,
                position: 'left',
                title: {
                    display: true,
                    text: 'Words per minute',
                    color: subColor,
                    font: {
                        size: 16,
                        family: 'lexend, sans-serif',
                    },
                },
                ticks: {
                    font: {
                        family: 'lexend, sans-serif',
                    },
                    color: subColor,

                },
                grid: {
                    color: (context: any) => {
                        if (context.tick.value === 0) {
                            return subColor
                        }
                        else {
                            return subColor + "15"
                        }
                    },
                },
            },
            y1: {
                position: 'right',
                max: 120,
                min: 0,
                title: {
                    display: true,
                    text: 'Accuracy',
                    color: subColor,
                    font: {
                        size: 16,
                        family: 'lexend, sans-serif',
                    },
                },
                ticks: {
                    font: {
                        family: 'lexend, sans-serif',
                    },
                    color: subColor,
                },
                grid: {
                    color: (context: any) => {
                        if (context.tick.value === 0) {
                            return subColor
                        }
                        else {
                            return "transparent"
                        }
                    },
                },
            },
        },
        elements: {
            point: {
                radius: 2,
            },
        },

Note that I don't want to color the gridLines

Current

enter image description here

Expected

enter image description here


Solution

  • Assuming you are using Chart.js 4, you could use the border node in scales configuration.

    const ctx = document.getElementById('myChart').getContext('2d');
    const myChart = new Chart(ctx, {
      type: 'line',
      data: {
        labels: ['1', '2', '3', '4', '5', '6', '7'],
        datasets: [{
          label: 'Sales',
          data: [12, 19, 3, 5, 2, 3, 14],
          borderWidth: 3,
          yAxisID: 'y'
        }, {
          label: 'Purchases',
          data: [10, 40, 30, 1, 1, 13, 8],
          borderWidth: 3,
          yAxisID: 'y1'
        }],
      },
      options: {
        scales: {
          x: {
            ticks: {
              color: 'red'
            },
            grid: {
              display: false
            },
            border: {
              color: 'red',
            }
          },
          y: {
            ticks: {
              color: 'red'
            },
            grid: {
              display: false
            },
            border: {
              color: 'red',
            }
          },
          y1: {
            position: 'right',
            ticks: {
              color: 'red'
            },
            grid: {
              display: false
            },
            border: {
              color: 'red',
            }
          }
        },
      },
    });
    .myChartDiv {
      max-width: 600px;
      max-height: 400px;
    }
    <script src="https://npmcdn.com/chart.js@latest/dist/chart.umd.js"></script>
    <div class="myChartDiv">
      <canvas id="myChart" width="600" height="400"></canvas>
    </div>

    EDIT: if you want the same color for all chart instances, you could also think to set borderColor in chart defaults:

    Chart.defaults.borderColor = 'red';