【问题标题】:Line Chart Dashboard with Aggregated Data Points带有聚合数据点的折线图仪表板
【发布时间】:2018-11-14 21:16:00
【问题描述】:

我正在处理一个包含折线图、表格图和两个类别过滤器的仪表板,我需要弄清楚如何将多行聚合成可以在折线图上绘制的点。

鉴于谷歌表格中保存的数据集(例如我在下面列出的示例),折线图需要显示 X 轴上的年份(2014 年 - 2017 年),以及两家公司的所有满意度的平均值,以及所有部门。

第一个 CategoryFilter 允许用户选择其中一个公司。当他们选择一个时,折线图应该显示所有部门的总数量,结合起来。

第二个 CategoryFilter 允许用户选择一个部门,折线图应显示该单个公司/部门的满意度。

就目前而言,一旦我“深入”到单个公司/部门,图表就会正确显示。我此时的任务是让聚合工作,直到使用两个类别过滤器“向下钻取”到单个部门。

任何人都可以向我指出描述如何完成此任务的资源,或者指向我可以看到如何编写代码的工作示例吗?

Company    Department    Year    Satisfaction_Rate
CompA      Personnel     2014    0.8542
CompA      Personnel     2015    0.8680
CompA      Personnel     2016    0.8712
CompA      Personnel     2017    0.8832
CompA      Sales         2014    0.7542
CompA      Sales         2015    0.7680
CompA      Sales         2016    0.7712
CompA      Sales         2017    0.7832
CompA      Labor         2014    0.6542
CompA      Labor         2015    0.6680
CompA      Labor         2016    0.6712
CompA      Labor         2017    0.6832
CompB      Personnel     2014    0.9242
CompB      Personnel     2015    0.9280
CompB      Personnel     2016    0.9312
CompB      Personnel     2017    0.9132
CompB      Sales         2014    0.8742
CompB      Sales         2015    0.8880
CompB      Sales         2016    0.8112
CompB      Sales         2017    0.8632
CompB      Labor         2014    0.7942
CompB      Labor         2015    0.8080
CompB      Labor         2016    0.8112
CompB      Labor         2017    0.8232

尽管此示例数据准确地代表了我正在使用的数据类型的概念,但实际数据却大不相同,正如您在我的代码中所注意到的那样。

// Load the Visualization API and the corechart package.
google.charts.load('current', { 'packages': ['corechart', 'controls'] });

// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawCharts);

//------------------------------------------------------------------------------

function GetDataFromSheet(URL, queryString, callback) {
    var query = new google.visualization.Query(URL);
    query.setQuery(queryString);
    query.send(gotResponse);

    function gotResponse(response) {
        if (response.isError()) {
            console.log(response.getReasons());
            alert('Error in query: ' + response.getMessage() + " " + response.getDetailedMessage());
            return;
        }
        if (response.hasWarning()) {
            console.log(response.getReasons());
            alert('Warning from query: ' + response.getMessage() + " " + response.getDetailedMessage());
            return;
        }
        callback(response);
    }
}

//------------------------------------------------------------------------------

function drawCharts() {
    var URL, query;

    // PREP DATA SOURCE
    URL = 'https://docs.google.com/spreadsheets/d/1QygNPsYR041jat.../gviz/tq?gid=1339946796';
    query = 'select A, C, D, H, J, M, P, S LABEL A "AEA", C "District", D "Class of", H "Graduation Rate", J "Post-Secondary Intention Rate", M "Enrollment Rate", P "Persistence Rate", S "Completion Rate"';
    GetDataFromSheet(URL, query, handlePrep);

}



//------------------------------------------------------------------------------
// POST SECONDARY READINESS & EQUITY PARTNERSHIP

function handlePrep(response) {

    var data = response.getDataTable();

    // Attempting to aggregate...  grouping on index 2, "class of". Example: 2015
    //   averaging column 3, Graduation Rate
    var result = google.visualization.data.group(
        data,
        [2],
        [{'column': 3, 'aggregation': google.visualization.data.avg, 'type': 'number'}]
    );

    var container = new google.visualization.Dashboard(document.getElementById('divPrep'));

    var AEAControl = new google.visualization.ControlWrapper({
        controlType: 'CategoryFilter',
        containerId: 'divAEAPicker',
        options: {
            filterColumnIndex: 0,
            ui: {
                selectedValuesLayout: 'belowStacked',
                label: 'AEA Selector ->',
                caption: 'Choose an AEA...',
                allowNone: true,
                allowMultiple: false
            },
        }
    });

    var DistrictControl = new google.visualization.ControlWrapper({
        controlType: 'CategoryFilter',
        containerId: 'divDistrictPicker',
        options: {
            filterColumnIndex: 1,
            ui: {
                label: 'District Selector ->',
                caption: 'Choose a District...',
                allowNone: true,
                allowMultiple: false
            },
        }
    });

    var chart = new google.visualization.ChartWrapper({
        chartType: 'LineChart',
        containerId: 'divPrepChart',
        options: {
            height: 400,
            width: 1200,
            pointSize: 5,
            title: 'Post-Secondary Readiness & Equity Partnership (PREP) Trendlines',
            legend: { position: 'top', maxLines: 3 },
            //chartArea: { left: '10%', width: '85%'},
            tooltip:{textStyle: {color: '#000000'}, showColorCode: true},
            hAxis:{
                format: 'yyyy',
                title: 'Graduating Class Year'
            },
            vAxis: {
                format: 'percent',
                maxValue: 1,
                minValue: 0
            }
        },
        view: {'columns': [2, 3, 4, 5, 6, 7]}
    });

    var table = new google.visualization.ChartWrapper({
        chartType: 'Table',
        containerId: 'divTable',
        options: {
            title: 'Post-Secondary Readiness & Equity Partnership ',
            legend: { position: 'top', maxLines: 3 },
            //chartArea: { left: '10%', width: '85%'},
            page: 'enable',
            pageSize: 10


        }
    });

    // Create a formatter to display values as percent
    var percentFormatter = new google.visualization.NumberFormat({pattern: '0.00%'});
    percentFormatter.format(data, 3);
    percentFormatter.format(data, 4);
    percentFormatter.format(data, 5);
    percentFormatter.format(data, 6);
    percentFormatter.format(data, 7);


    // Configure the controls so that:
    // - the AEA selection drives the District one
    // - both the AEA and Disctirct selections drive the linechart
    // - both the AEA and Districts selections drive the table
    container.bind(AEAControl, DistrictControl);
    container.bind([AEAControl, DistrictControl], [chart, table]);

    // Draw the dashboard named 'container'
    container.draw(data);

    // Until we figure out how to display aggregated values at the AEA and State levels,
    // keep the line graph hidden until both an AEA and District are chosen from the category filters
    google.visualization.events.addListener(container, 'ready', function() {
        var aeaSelectedValues = AEAControl.getState()['selectedValues'];
        var districtSelectedValues = DistrictControl.getState()['selectedValues'];
        if (aeaSelectedValues.length == 0 || districtSelectedValues.length == 0) {
            document.getElementById('divPrepChart').style.visibility = 'hidden';
         } else {
            document.getElementById('divPrepChart').style.visibility = 'visible';
         }
    });

}

这是我的数据当前在使用类别过滤器选择选项之前的图形...

我需要让它看起来更像这样...

【问题讨论】:

  • @WhiteHat 我已经用代码和屏幕截图更新了这个问题。 TY

标签: charts google-visualization


【解决方案1】:

您需要独立绘制控件和图表,而不使用仪表板。
然后您可以在控件的'statechage' 事件触发时绘制图表。
当事件触发时,您可以根据所选值聚合数据,
并重新绘制图表。

请参阅以下工作 sn-p...

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

function handlePrep(response) {
    var data = google.visualization.arrayToDataTable([
      ['Company',    'Department',    'Year',    'Satisfaction_Rate'],
      ['CompA',      'Personnel',     2014,    0.8542],
      ['CompA',      'Personnel',     2015,    0.8680],
      ['CompA',      'Personnel',     2016,    0.8712],
      ['CompA',      'Personnel',     2017,    0.8832],
      ['CompA',      'Sales',         2014,    0.7542],
      ['CompA',      'Sales',         2015,    0.7680],
      ['CompA',      'Sales',         2016,    0.7712],
      ['CompA',      'Sales',         2017,    0.7832],
      ['CompA',      'Labor',         2014,    0.6542],
      ['CompA',      'Labor',         2015,    0.6680],
      ['CompA',      'Labor',         2016,    0.6712],
      ['CompA',      'Labor',         2017,    0.6832],
      ['CompB',      'Personnel',     2014,    0.9242],
      ['CompB',      'Personnel',     2015,    0.9280],
      ['CompB',      'Personnel',     2016,    0.9312],
      ['CompB',      'Personnel',     2017,    0.9132],
      ['CompB',      'Sales',         2014,    0.8742],
      ['CompB',      'Sales',         2015,    0.8880],
      ['CompB',      'Sales',         2016,    0.8112],
      ['CompB',      'Sales',         2017,    0.8632],
      ['CompB',      'Labor',         2014,    0.7942],
      ['CompB',      'Labor',         2015,    0.8080],
      ['CompB',      'Labor',         2016,    0.8112],
      ['CompB',      'Labor',         2017,    0.8232],
    ]);

    var AEAControl = new google.visualization.ControlWrapper({
        controlType: 'CategoryFilter',
        containerId: 'divAEAPicker',
        dataTable: data,
        options: {
            filterColumnIndex: 0,
            ui: {
                selectedValuesLayout: 'belowStacked',
                label: 'AEA Selector ->',
                caption: 'Choose an AEA...',
                allowNone: true,
                allowMultiple: false
            },
        }
    });

    var DistrictControl = new google.visualization.ControlWrapper({
        controlType: 'CategoryFilter',
        containerId: 'divDistrictPicker',
        dataTable: data,
        options: {
            filterColumnIndex: 1,
            ui: {
                label: 'District Selector ->',
                caption: 'Choose a District...',
                allowNone: true,
                allowMultiple: false
            },
        }
    });

    var chart = new google.visualization.ChartWrapper({
        chartType: 'LineChart',
        containerId: 'divPrepChart',
        options: {
            height: 400,
            width: 1200,
            pointSize: 5,
            title: 'Post-Secondary Readiness & Equity Partnership (PREP) Trendlines',
            legend: { position: 'top', maxLines: 3 },
            tooltip:{textStyle: {color: '#000000'}, showColorCode: true},
            hAxis:{
                format: '0',
                title: 'Graduating Class Year'
            },
            vAxis: {
                format: 'percent',
                maxValue: 1,
                minValue: 0
            }
        },
    });

    var table = new google.visualization.ChartWrapper({
        chartType: 'Table',
        containerId: 'divTable',
        options: {
            title: 'Post-Secondary Readiness & Equity Partnership ',
            legend: { position: 'top', maxLines: 3 },
            page: 'enable',
            pageSize: 10


        }
    });

    google.visualization.events.addListener(AEAControl, 'statechange', drawDashboard);
    google.visualization.events.addListener(DistrictControl, 'statechange', drawDashboard);

    function drawDashboard() {
      var view = new google.visualization.DataView(data);
      var valuesAEA = AEAControl.getState();
      var valuesDistrict = DistrictControl.getState();
      var viewRows = [];

      if (valuesAEA.selectedValues.length > 0) {
        viewRows.push({
          column: AEAControl.getOption('filterColumnIndex'),
          test: function (value) {
            return (valuesAEA.selectedValues.indexOf(value) > -1);
          }
        });
      }
      if (valuesDistrict.selectedValues.length > 0) {
        viewRows.push({
          column: DistrictControl.getOption('filterColumnIndex'),
          test: function (value) {
            return (valuesDistrict.selectedValues.indexOf(value) > -1);
          }
        });
      }
      if (viewRows.length > 0) {
        view.setRows(data.getFilteredRows(viewRows));
      }
      result = google.visualization.data.group(
        view,
        [2],
        [{'column': 3, 'aggregation': google.visualization.data.avg, 'type': 'number'}]
      );
      var percentFormatter = new google.visualization.NumberFormat({pattern: '0.00%'});
      percentFormatter.format(result, 1);

      chart.setDataTable(result);
      chart.draw();
      table.setDataTable(result);
      table.draw();
    }

    AEAControl.draw();
    DistrictControl.draw();
    drawDashboard();
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="divPrep">
  <div id="divAEAPicker"></div>
  <div id="divDistrictPicker"></div>
  <div id="divPrepChart"></div>
  <div id="divTable"></div>
</div>

【讨论】:

  • 这个问题好运吗?
猜你喜欢
  • 1970-01-01
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多