Charts.js Formatting Y Axis with both Currency and Thousands Separator
Asked Answered
S

10

83

I'm using Charts.js to show a graph on my site. Currently, the label shows as a long string of numbers (i.e 123456). I want it to show as currency with thousands separator: (i.e $123,456)

I'm using the scaleLabel option to put a $ USD symbol before the value:

scaleLabel: "<%= ' $' + Number(value)%>"

and a function to insert the comma separator:

function(label){return label.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");}

I just do not know how to use these together to get what I want.

Here is the fiddle: http://jsfiddle.net/vy0yhd6m/79/

(please keep in mind that currently the graph will only work if you remove one of those two pieces of JavaScript cited above)

Thank you for any and all help.

Schoening answered 15/2, 2015 at 5:46 Comment(1)
Answer - https://mcmap.net/q/167949/-chart-js-formatting-y-axisCy
G
43

You should be able to include currency prefix in composition of label inside function...

var options = {
    animation: false,
    scaleLabel:
    function(label){return  '$' + label.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");}
};

http://jsfiddle.net/vy0yhd6m/80/

Googol answered 15/2, 2015 at 5:53 Comment(3)
Thank you it worked! I will accept your answer in 7 minutes when the websites allows me to :-)Schoening
This is only for 1.x of Chart.js, scroll down if you need an answer for 2.x or greater.Overshoot
this does not work for a "complex" scaleLabel containing multiple values, you need { something1: something1, something2: something2, callback: function(label) etc. etc.}Barocchio
M
119

I'm new to chart.js, but here's what I had to do to make Billy Moon's answer work with the latest version 2.1.6.

  var data = {
    labels: ["12 AM", "1 AM", "2 AM", "3 AM", "4 AM", "5 AM", "6 AM", "7 AM", "8 AM", "9 AM", "10 AM", "11 AM", "12 PM", "1 PM", "2 PM", "3 PM", "4 PM", "5 PM", "6 PM", "7 PM", "8 PM", "9 PM", "10 PM", "11 PM"],
    datasets: [
      {
        label: "Sales $",
        lineTension: 0,
        backgroundColor: "rgba(143,199,232,0.2)",
        borderColor: "rgba(108,108,108,1)",
        borderWidth: 1,
        pointBackgroundColor: "#535353",
        data: [65, 59, 80, 81, 56, 55, 59, 80, 81, 56, 55, 40, 59, 80, 81, 56, 55, 40, 59, 80, 81, 56, 55, 40]
      }
    ]
  };

  //var myChart =
  new Chart(document.getElementById('sales-summary-today'), {
    type: 'line',
    data: data,
    options: {
      animation: false,
      legend: {display: false},
      maintainAspectRatio: false,
      responsive: true,
      responsiveAnimationDuration: 0,
      scales: {
        yAxes: [{
          ticks: {
            beginAtZero: true,
            callback: function(value, index, values) {
              if(parseInt(value) >= 1000){
                return '$' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
              } else {
                return '$' + value;
              }
            }
          }
        }]
      }
    }
  });

Again, credit goes to Billy Moon's Answer for the label formatting function.

Mealy answered 24/6, 2016 at 5:8 Comment(2)
This is the solution for charts v2. The other solutions listed at https://mcmap.net/q/167949/-chart-js-formatting-y-axis/… don't seem to work on the latest releaseMylan
thanks! We can also use toLocaleString instead of all the regex and conditionals, just simply: return "$" + parseInt(value).toLocaleString();Channel
N
51

I'm mostly summarizing what others have mentioned, but I think the cleanest solution to this exact (and frequently encountered) question is to utilize the toLocaleString method with USD currency formatting:

return value.toLocaleString("en-US",{style:"currency", currency:"USD"});

This works in all modern browsers. The Mozilla documentation for toLocaleString lists specific browser compatibility and options for other locales, currencies, and formatting types (e.g. percentages).

Note Chart.js Version 2+ (released in April 2016) requires using the callback method for advanced tick formatting:

var chartInstance = new Chart(ctx, {
  type: 'line',
  data: data,
  options: {
     scales: {
       yAxes: [{
         ticks: {
           callback: function(value, index, values) {
             return value.toLocaleString("en-US",{style:"currency", currency:"USD"});
           }
         }
       }]
     }
   }
 });

The syntax if you are using Chart.js Version 1.X would be:

var myLineChart = new Chart(ctx).Line(data, options);
var data = {
  ...
}
var options = {
  scaleLabel: function(label) {
    return value.toLocaleString("en-US",{style:"currency", currency:"USD"});
}

Credit to Perry Tew for referencing the syntax change, and to mfink for the idea to use toLocaleString.

Neoma answered 11/11, 2016 at 21:43 Comment(3)
why would you think this wouldnt work for tooltips ? tried putting this in my tooltip callback, nothingLacerated
For those who want to remove the decimal points from the currency: {style:"currency", currency:"USD",minimumFractionDigits:0,maximumFractionDigits:0}Overshoot
What if the symbol can change? How can you pass it, and the placement (before/after) the number?Fraught
G
43

You should be able to include currency prefix in composition of label inside function...

var options = {
    animation: false,
    scaleLabel:
    function(label){return  '$' + label.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");}
};

http://jsfiddle.net/vy0yhd6m/80/

Googol answered 15/2, 2015 at 5:53 Comment(3)
Thank you it worked! I will accept your answer in 7 minutes when the websites allows me to :-)Schoening
This is only for 1.x of Chart.js, scroll down if you need an answer for 2.x or greater.Overshoot
this does not work for a "complex" scaleLabel containing multiple values, you need { something1: something1, something2: something2, callback: function(label) etc. etc.}Barocchio
H
10

Adding to Perry Tew's answer, if you have negative dollar amounts on your axes (e.g. when displaying a profit/loss chart), you can use this:

ticks: {
    callback: function(value, index, values) {
        if(parseInt(value) > 999){
            return '$' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        } else if (parseInt(value) < -999) {
            return '-$' + Math.abs(value).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        } else {
            return '$' + value;
        }
    }
}

The correct format for displaying negative currencies is -$XXX, so we prepend -$ to the value, and then run it through Math.abs(), which converts it to positive.

Hyps answered 6/8, 2016 at 2:2 Comment(0)
S
8

In chartjs v2.0, you can set a global options like this:

Chart.defaults.global.tooltips.callbacks.label = function(tooltipItem, data) {
    return tooltipItem.yLabel.toLocaleString("en-US");
};

Chart.scaleService.updateScaleDefaults('linear', {
    ticks: {
        callback: function (value, index, values) {
            return value.toLocaleString();
        }
    }
});
Scanty answered 23/11, 2017 at 8:43 Comment(0)
S
6

If you are using Charts.js for Angular 2+ (ng2-charts) you can use CurrencyPipe. Here is how I formatted the label:

Inject the dependency within your page.ts file:

import { CurrencyPipe } from '@angular/common';

Here is how I call it within my chart options:

public chartOptions: any = {
        responsive: true,
        legend: {
            display: false,
            labels: {
                display: false
            }
        },
        tooltips: {
          enabled: true,
          mode: 'single',
          callbacks: {
            label: function(tooltipItem, data) {
              let label = data.labels[tooltipItem.index];
              let datasetLabel = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
              let currencyPipe = new CurrencyPipe('en');
              let formattedNumber = currencyPipe.transform(datasetLabel, 'USD', 'symbol');
              return label + ': ' + formattedNumber;
            }
          }
        }
    };

UPDATE 2022-04-07: The syntax has changed for Chart.js version 3. Here is what the options object looks like if you are using v3:

import { ChartConfiguration, ChartData, ChartType } from 'chart.js';
import { CurrencyPipe } from '@angular/common';

public chart_options: ChartConfiguration['options'] = {
   layout: {
      padding: 25,
   },
   responsive: true,
   plugins: {
      legend: {
         display: false,
      },
      tooltip: {
         enabled: true,
         callbacks: {
            label: function(context) {
               let currency_pipe = new CurrencyPipe('en');
               return ' ' + context.label + ': ' + currency_pipe.transform(context.parsed, 'USD', 'symbol');
            }
         }
      }
   }
};

public chart_type: ChartType = 'doughnut';
public chart_labels: string[] = [];
public chart_data: ChartData<'doughnut'> = {
   labels: this.chart_labels,
   datasets: [{
      data: [],
      backgroundColor: [],
   }]
};

<div style="display: block;">
   <canvas baseChart [data]="chart_data" [options]="chart_options" [type]="chart_type"></canvas>
</div>

Check out the Chart.js v3 Migration Guide for more info

Schoening answered 9/11, 2018 at 18:27 Comment(0)
B
5

Using chartjs v2.8.0, after looking around the docs, I found it here.

Instead of making my own formatter, I'm using numeraljs to format the number. So this is what I do:

import numeral from 'numeral'

options: {
  scales: {
    yAxes: [{
      ticks: {
        callback: function (value, index, values) {
          // add comma as thousand separator
          return numeral(value).format('0,0')
        },
      }
    }]
  },
  tooltips: {
    callbacks: {
      label: function (tooltipItem, data) {
        var label = data.datasets[tooltipItem.datasetIndex].label || ''

        if (label) {
          label += ': '
        }
        label += numeral(tooltipItem.yLabel).format('0,0')
        return label
      },
    },
  },
}

You can use format('$ 0,0') to add currency symbol along with comma thousand separator.

Bailment answered 14/6, 2019 at 6:41 Comment(0)
C
4

I know my answer is too late but due to op are getting more attention this may relevant now.

Here is the more simple and decent approach.

const formatter = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD"
}); // Change locale according to your currency and country

var options = {
    scales: {
        yAxes: [
            {
                ticks: {
                    callback: (label, index, labels) => {
                        return formatter.format(label);
                    }
                }
            }
        ]
    }
}
Cy answered 27/8, 2020 at 14:54 Comment(0)
Y
0

The answers here by Perry Tew, AJ A. et al yield a

Invalid scale configuration for scale: yAxes

error for me. I'm guessing that's because of a change in version 3.

Per the current docs this slight change seems to work:

options: {
    scales: {
        y: {
            ticks: {
                callback: function (value, index, values) {
                    return value.toLocaleString("en-CA", {
                        style: "currency", 
                        currency: "CAD", 
                        minimumFractionDigits:0, 
                        maximumFractionDigits:0});
                }
            }
        }
    }
}
You answered 8/10, 2023 at 18:45 Comment(0)
B
-1

There is a specific javascript function to convert a long number into a number formatted according to system settings: toLocaleString().

You can specify that the label of each tick (or of a specific tick identified by its number index) must be built by your own function, by adding "callback:" keyword inside tick options:

Before:

        ticks: {
                  max: maxAltitude,
                  min: 0
                }

After:

        ticks: {
                  max: maxAltitude,
                  min: 0, // <--- dont' foget to add this comma if you already have specified ticks options
                    callback:  
                      function(value, index, valuesArray) {
                          // value: currently processed tick label
                          // index of currently processed tick label
                          // valuesArray: array containing all predefined labels
                          return  value.toLocaleString(); 
                      } // Function end
                } // Ticks options end

Without the comments and without unused variables:

        ticks: {
                  max: maxAltitude,
                  min: 0, 
                  callback:  
                      function(value) {
                        return  value.toLocaleString(); 
                      }
                }
Barocchio answered 12/7, 2019 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.