javascriptasp.netasp.net-corechartsgoogle-visualization

How do I format my secondary axis line values as percent using Google Chart API JavaScript in ASP.NET project


My chart consists of 2 stacked bars on the primary vertical axis and a line on the secondary axis. My secondary vAxis is formatted as % and displays as I want, however, the individual datapoints display as decimal values, i.e., -0.446, and what I would like is -44.6%.

Chart sample showing format to fix

JavaScript code

 <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
 <script type="text/javascript">

     google.charts.load('current', { packages: ['corechart'] });
     google.charts.setOnLoadCallback(drawChart);

     function drawChart() {
         var data = new google.visualization.DataTable();

         var jsonList = @(Json.Serialize(Model.listAllAircraftChart))

         var title = 'Monthly Aircraft Transaction Trend';

         data.addColumn('string', 'Month');
         data.addColumn('number', '2024');
         data.addColumn('number', '2023');
         data.addColumn('number', '% Change');
         data.addRows(jsonList.map((p) => {
             return [p.yearMonth, p.year1top, p.year2bottom, p.year1percent];
         }));

         var view = new google.visualization.DataView(data);
         view.setColumns([0, 1,
             {
                 calc: "stringify",
                 sourceColumn: 1,
                 type: "string",
                 role: "annotation"
             },
             2,
             {
                 calc: "stringify",
                 sourceColumn: 2,
                 type: "string",
                 role: "annotation"
             },
             3,
             {
                 calc: "stringify",
                 sourceColumn: 3,
                 type: "string",
                 role: "annotation"
             }

         ]);
         var options = {
             title: title,
             titlePosition: 'out',
             isStacked: true,

             seriesType: "bars",
             vAxes: {
                 0: {
                     textPosition: 'out',
                     viewWindowMode: 'pretty',
                     viewWindow: { min: -750, max: 750 },
                     gridlines: { color: 'light-gray' },
                 },
                 1: {
                     textPosition: 'out',
                     viewWindow: { min: -1, max: 1 },
                     format: 'percent',
                     gridlines: { color: 'transparent' }
                 },
             },
             series: {
                 0: { targetAxisIndex: 0, color: 'blue'},
                 1: { targetAxisIndex: 0, color: 'gray' },
                 2: { targetAxisIndex: 1, color: 'red', type: 'line', lineWidth: 1, lineDashStyle: [4, 4], pointSize: 5 },
             },
             width: '100%',
             height: '300',

             legend: { position: 'top' },
             chartArea: {
                 height: '100%',
                 width: '100%',
                 top: 48,
                 left: 60,
                 right: 60,
                 bottom: 75
             },
             annotations: {
                 textStyle: {
                     color: 'black',
                     fontSize: 11,
                 },
                 alwaysOutside: true
             },
         }

         var chart = new google.visualization.ComboChart(document.getElementById('primaryCurrentYear'));
         chart.draw(view, options);

         document.getElementById('downloadimg').innerHTML = '<a download="google-chart-image" href="' + chart.getImageURI() +
             '"><button type="button" class="btn btn-outline-dark btn-sm opacity-25 ms-4 mb-3">Download Chart Image</button></a>';

         window.addEventListener('resize', drawChart, false);
     }
 </script>

I have tried researching similar charts and reviewed Google Charts API documentation, but I haven't been able to figure it out.


Solution

  • you can use Google Charts' NumberFormat class...

    here, we provide a number pattern to the formatter: #,##0.0%

    var formatter = new google.visualization.NumberFormat({
      pattern: '#,##0.0%'
    });
    

    after creating the number formatter, you can use the format method to format an entire data table column.

    formatter.format(data, 3);  // <-- format % Change column
    

    see following working snippet...

    google.charts.load('current', {
      packages: ['corechart']
    }).then(drawChart);
    
    function drawChart() {
      var data = new google.visualization.DataTable();
    
      //var jsonList = @(Json.Serialize(Model.listAllAircraftChart))
      var jsonList = [
        {yearMonth: 'January', year1top: 141, year2bottom: -158, year1percent: -0.108},
        {yearMonth: 'February', year1top: 98, year2bottom: -77, year1percent: -0.446},
        {yearMonth: 'March', year1top: 0, year2bottom: -299, year1percent: -1},
        {yearMonth: 'April', year1top: 0, year2bottom: -219, year1percent: -1},
        {yearMonth: 'May', year1top: 0, year2bottom: -272, year1percent: -1}
      ];
    
      var title = 'Monthly Aircraft Transaction Trend';
    
      data.addColumn('string', 'Month');
      data.addColumn('number', '2024');
      data.addColumn('number', '2023');
      data.addColumn('number', '% Change');
      data.addRows(jsonList.map((p) => {
         return [p.yearMonth, p.year1top, p.year2bottom, p.year1percent];
      }));
    
      // format % Change column
      var formatter = new google.visualization.NumberFormat({
        pattern: '#,##0.0%'
      });
      formatter.format(data, 3);
    
      var view = new google.visualization.DataView(data);
      view.setColumns([0, 1,
         {
             calc: "stringify",
             sourceColumn: 1,
             type: "string",
             role: "annotation"
         },
         2,
         {
             calc: "stringify",
             sourceColumn: 2,
             type: "string",
             role: "annotation"
         },
         3,
         {
             calc: "stringify",
             sourceColumn: 3,
             type: "string",
             role: "annotation"
         }
    
      ]);
      var options = {
         title: title,
         titlePosition: 'out',
         isStacked: true,
    
         seriesType: "bars",
         vAxes: {
             0: {
                 textPosition: 'out',
                 viewWindowMode: 'pretty',
                 viewWindow: { min: -750, max: 750 },
                 gridlines: { color: 'light-gray' },
             },
             1: {
                 textPosition: 'out',
                 viewWindow: { min: -1, max: 1 },
                 format: 'percent',
                 gridlines: { color: 'transparent' }
             },
         },
         series: {
             0: { targetAxisIndex: 0, color: 'blue'},
             1: { targetAxisIndex: 0, color: 'gray' },
             2: { targetAxisIndex: 1, color: 'red', type: 'line', lineWidth: 1, lineDashStyle: [4, 4], pointSize: 5 },
         },
         width: '100%',
         height: '300',
    
         legend: { position: 'top' },
         chartArea: {
             height: '100%',
             width: '100%',
             top: 48,
             left: 60,
             right: 60,
             bottom: 75
         },
         annotations: {
             textStyle: {
                 color: 'black',
                 fontSize: 11,
             },
             alwaysOutside: true
         },
      }
    
      var chart = new google.visualization.ComboChart(document.getElementById('primaryCurrentYear'));
    
      google.visualization.events.addListener(chart, 'ready', function () {
        document.getElementById('downloading').innerHTML = '<a download="google-chart-image" href="' + chart.getImageURI() +
           '"><button type="button" class="btn btn-outline-dark btn-sm opacity-25 ms-4 mb-3">Download Chart Image</button></a>';
      });
    
      chart.draw(view, options);
    
      window.addEventListener('resize', drawChart, false);
    }
    <script src="https://www.gstatic.com/charts/loader.js"></script>
    <div id="primaryCurrentYear"></div>
    <div id="downloading"></div>

    note: getImageURI is only available after the chart's 'ready' event has fired...