首页 > 解决方案 > 如何使用 ChartJS 创建从新的 ajax 请求更新的条形图?

问题描述

我正在使用 Flask 和 MongoDB 构建我的应用程序。

现在我很难弄清楚如何让我的条形图根据我基于下拉菜单的不同 ajax 请求动态更改..

在弄清楚如何使图表响应我在下拉菜单中的选择之前,我决定致力于使图表能够对不同的 ajax 数据做出反应并相应地更新。

首先,我学习了如何创建一个基本的条形图,如下所示:

var getValues = $.get('/data/locations-vs-counts/');
getValues.done(function(bar_data){
    counts = bar_data.counts;
    label = bar_data.locations;
    maxValue = Math.max.apply(Math, counts);
    var barchart = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: label,
            datasets: [{
            label: '# of counts',
            backgroundColor: 'rgb(17, 146, 232)',
            borderColor: 'rgb(17, 146, 232)',
            data: counts
        }]
    },
    options: {
        responsive: false,
        scales: {
            yAxes: [{
         id: 'y-axis-1', type: 'linear', position: 'left', ticks:{beginAtZero:true,max:(maxValue+1)}
        }]
    }
    }
});
});

但为了实现我想要的,我想我需要为图表创建一个函数,以便能够接受一些输入(URL、chart_title、标签等)。我决定在第一次尝试时只尝试 URL 输入。
我已阅读以下帖子以供参考:
Refresh the Bar Char in ChartJS (v2.6.0) Using Ajax Correct Way
How to return multiple arrays from a function in Javascript?
https://github.com/chartjs/Chart.js/issues/6176
使用动态数据更新chartJS
如何从AJAX 帖子获取Flask 中的数据 (尚未使用,但我认为在需要使用下拉列表更新chartjs 时会很有用)

到目前为止,我最终得到了以下代码:

// Bar chart (# of Counts vs Locations)
var ctx = document.getElementById('barChart').getContext('2d');
var barChart = new Chart(ctx,{
    type: 'bar',
    data:[],
    option:{responsive: false}
});

function barData(url){
    let data_labels = [];
    let data_values = [];
    $.ajax({
        url: url,
        type: 'GET',
        async: false,
        success: function(bar_data){
            data_labels= bar_data.labels;
            data_values= bar_data.values;
        }
    })
    return {data_labels,data_values};
}

function updateBarChart(url_link){
    let results = barData(url_link);
    counts = results.data_values;
    xlabels = results.data_labels;
    maxValue = Math.max.apply(Math, counts);
    console.log("counts:",counts);
    console.log("xlabels:", xlabels);
    barChart.data.labels = xlabels;
    barChart.data.datasets.data = counts;
    barChart.data.datasets.label = "# of counts";
    barChart.data.datasets.backgroundColor = 'rgb(17, 146, 232)';
    barChart.options.scales.yAxes[0].ticks.beginAtZero= true;
    barChart.options.scales.yAxes[0].ticks.max = (maxValue+1);
    barChart.update();
}
updateBarChart('/data/locations-vs-counts/')

但是..以上没有按预期工作。
画布以正确的 xlabels 和 y 比例显示,但未绘制条形。但我可以看到 counts 变量在控制台中具有正确值的数组。
我也尝试过barChart.data.datasets[0].data = counts;一些建议的帖子,但显示错误:

未捕获的类型错误:无法在 updateBarChart 处设置未定义的属性“数据”

作为参考,我从 URL 获得的数据是我从 pandas 数据框生成的两个列表,如下所示:data_parse.py:

@data_parser.route('/locations-vs-counts/', methods=['GET'])
def locations_vs_counts():
    locations = location_list()   #from another function
    df = all_counts()
    df = df['location'].value_counts()
    for location in locations:
        if(location not in df.index):
            df.loc[location] = 0
    labels = df.index.tolist()
    counts = df.tolist()
    return jsonify({'labels':labels, 'values': counts})

有人可以告诉我我在updateBarChart()功能上做错了什么吗?
如果这种方法是可行的,我想最终实现:将所有位置与计数作为默认图表的条形图,然后用户可以从位置下拉列表中选择以查看该位置的详细信息(来自另一条路线的 2 个新数组)
任何帮助表示赞赏!先感谢您!

对adelriosantiago建议的回应:
我可以看到我的条形图用以下内容正确绘制

var results = barData('/data/locations-vs-counts/');  //same barData() function from above
var myValues = results.data_values;
var myLabels = results.data_labels;

var myChart = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: myLabels,
            datasets: [{
                label: '# of counts',
                data: myValues
            }]
        },
        options:{
            responsive: false
        }
});

所以我认为这证明 barData() 正在按预期获取值myLabelsmyValues正确存储,尽管这async:false似乎并不理想。我不猜测这与我如何更新内部的图形数据有关updateBarChart()

标签: javascriptjqueryajaxchart.js

解决方案


这是一个异步与同步错误。本教程可能会有所帮助。

看一下这部分代码:

function barData(url){
    let data_labels = [];
    let data_values = [];
    $.ajax({
        url: url,
        type: 'GET',
        async: false,
        success: function(bar_data){
            data_labels= bar_data.labels;
            data_values= bar_data.values;
        }
    })
    return {data_labels,data_values};
}

return {data_labels,data_values};实际上是在$.ajax通话之前发生的。如果你想从服务器返回结果,这一行应该在successajax 调用的函数内。看看这个问题,其中 OP 有同样的问题。

关于更新图表,这里有一个模拟服务器响应的演示,每秒更新其值:https ://codepen.io/adelriosantiago/pen/YzpNLbd


推荐阅读