【问题标题】:Using ChartJS to create a multiple grouped bar chart - see picture below使用 ChartJS 创建多组条形图 - 见下图
【发布时间】:2021-03-16 12:24:15
【问题描述】:

我正在测试 HighCharts 和 ChartJS 以查看使用哪个。对于 Highcharts,我能够找到一个技巧来创建在 x 轴上具有双重分组的条形图。

这就是我想要的样子:

我对图表 JS 选项都很陌生,想知道在 ChartJS 中是否有办法做到这一点。

我有这样的数据集:

    xAxis: {
        categories: [{
            name: "Total",
            categories: ["2004", "2008", "2012"]
        }, {
            name: "Lower than 2.50",
            categories: ["2004", "2008", "2012"]
        }]
    },
    yAxis: {
        min: 0,
        title: {
            text: 'Percent (%)'
        }
    },
    series: [{
        name: 'Male',
        data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4]

    }, {
        name: 'Female',
        data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6]

    }]

基本上我需要一个在 x 轴上的嵌套系列,我对来自 Github 的插件或代码持开放态度。

【问题讨论】:

    标签: charts chart.js data-visualization bar-chart visualization


    【解决方案1】:

    您可以使用Plugin Core API。它提供了不同的钩子,可用于执行自定义代码。在下面的代码中,我使用afterDraw 钩子来绘制类别标签和分隔线。

    new Chart('myChart', {
      type: 'bar',
      plugins: [{
        afterDraw: chart => {
          let ctx = chart.chart.ctx;
          ctx.save();    
          let xAxis = chart.scales['x-axis-0'];
          let xCenter = (xAxis.left + xAxis.right) / 2;
          let yBottom = chart.scales['y-axis-0'].bottom;
          ctx.textAlign = 'center';
          ctx.font = '12px Arial';
          ctx.fillText(chart.data.categories[0], (xAxis.left + xCenter) / 2, yBottom + 40);
          ctx.fillText(chart.data.categories[1], (xCenter + xAxis.right) / 2, yBottom + 40);
          ctx.strokeStyle  = 'lightgray';
          [xAxis.left, xCenter, xAxis.right].forEach(x => {
            ctx.beginPath();
            ctx.moveTo(x, yBottom);
            ctx.lineTo(x, yBottom + 40);
            ctx.stroke();
          });
          ctx.restore();
        }
      }],
      data: {
        labels: ['2004', '2008', '2012', '2016', '2004', '2008', '2012', '2016'],
        categories: ['Total', 'Lower than 2.50'],
        datasets: [{
            label: 'Male',
            data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4, 51.2, 51.8],
            backgroundColor: 'rgba(124, 181, 236, 0.9)',
            borderColor: 'rgb(124, 181, 236)',
            borderWidth: 1
          },
          {
            label: 'Female',
            data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6, 53.7, 54.6],
            backgroundColor: 'rgba(67, 67, 72, 0.9)',
            borderColor: 'rgb(67, 67, 72)',
            borderWidth: 1
          }
        ]
      },
      options: {
        legend: {
          position: 'bottom',
          labels: {
            padding: 30,
            usePointStyle: true
          }
        },
        scales: {
          yAxes: [{
            ticks: {
              min: 0,
              max: 80,
              stepSize: 20
            },
            scaleLabel: {
              display: true,
              labelString: 'Percent (%)'
            }
          }],
          xAxes: [{
            gridLines: {
              drawOnChartArea: false
            }
          }]
        }
      }
    });
    canvas {
      max-width: 400px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
    <canvas id="myChart" height="200"></canvas>

    【讨论】:

    • 谢谢。你知道你的东西。我将更多地玩这个,让它对我们充满活力。
    【解决方案2】:

    您必须定义第二个 x 轴并使用许多 ticksgridLines 选项。

    请看看下面的可运行代码,看看它是如何完成的。这显然只是一个草案,需要优化并使其更通用。

    new Chart(document.getElementById('myChart'), {
      type: 'bar',
      data: {
        labels: ['2004', '2008', '2012', '2004', '2008', '2012'],    
        datasets: [{
            label: 'Male',
            data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4],
            backgroundColor: 'rgba(124, 181, 236, 0.9)',
            borderColor: 'rgb(124, 181, 236)',
            borderWidth: 1
          },
          {
            label: 'Female',
            data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6],
            backgroundColor: 'rgba(67, 67, 72, 0.9)',
            borderColor: 'rgb(67, 67, 72)',
            borderWidth: 1
          }
        ]
      },
      options: {
        legend: {
          position: 'bottom',
          labels: {
            usePointStyle: true
          }
        },
        scales: {
          yAxes: [{
            ticks: {
              min: 0,
              max: 80,
              stepSize: 20
            },
            scaleLabel: {
              display: true,
              labelString: 'Percent (%)'
            }
          }],
          xAxes: [{
              gridLines: {
                drawOnChartArea: false
              }
            },
            {
              offset: true,
              ticks: {
                autoSkip: false,
                maxRotation: 0,
                padding: -15,
                callback: (v, i) => {
                  if (i == 1) {
                    return 'Total';
                  } else if (i == 4) {
                    return 'Lower than 2.50';
                  } else {
                    return '';
                  }
                }
              },
              gridLines: {
                drawOnChartArea: false,
                offsetGridLines: true,
                tickMarkLength: 20,
                color: ['white', 'white', 'white', 'lightgray', 'white', 'white', 'lightgray']
              }
            }
          ]
        }
      }
    });
    canvas {
      max-width: 400px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
    <canvas id="myChart" height="200"></canvas>

    【讨论】:

    • 我发现如果我的图表大小为 400 x 400,那么 Total 就会消失,这很奇怪,而且我可以看到有关刻度线的文档在线低于标准。
    • 您能解释一下第二个刻度线下缺少总数的问题吗?
    • 我使用max-width 缩小了图表,但无法重现第二个 x 轴上缺少“总计”的问题。您是否也在使用最新的稳定版 Chart.js(目前为 2.9.4)?
    • 这是 Firefox 与 chrome 的问题。在Firefox中运行时上面的sn-p没有总数。在 chrome 中运行上面相同的 sn-p 工作正常。我不知道为什么。
    • 我必须在第二个 x 轴上添加 autoSkip: false 才能使其在 Firefox 中也能正常工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-05
    • 1970-01-01
    相关资源
    最近更新 更多