Lattice Grid

blog

Waffle Chart for Survey Answers

Building…
Loading a live grid…

If you are the researcher reporting a survey, the question for each result is plain: out of every hundred people who answered, how many gave each answer? A percentage on a slide makes the reader do that sum in their head. A reader would rather count.

A waffle chart lets them. It draws a hundred squares, each one percent of respondents, and fills them in the proportion each answer holds, so 46 percent agreeing is forty-six squares you can count. The chart above is bound to the grid beneath it, one row per question and answer, so filtering the rows redraws the squares. Filter the Question column to one question and the chart is that question’s hundred.

Why a waffle and not a pie

A pie asks the reader to judge angles, and a slice of 8 percent next to one of 11 percent looks the same. In a waffle the difference is three squares, and small answers stay legible because a square is a square at any size.

The chart over a grid

The chart reads the grid’s rows, so there is nothing to keep in step. Waffle is an opt-in chart type, so you import its module once after the charts module. x names the answer and y is the share. Here is the example in plain JavaScript, with sample rows inline in place of your own.

import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import { createChart } from '@toclocoinc/lattice-grid/modules/charts';
import '@toclocoinc/lattice-grid/modules/chart-waffle';

const rows = [
  { id: 1, question: 'Easy to get started', answer: 'Agree', share: 46 },
  { id: 2, question: 'Easy to get started', answer: 'Neutral', share: 27 },
  { id: 3, question: 'Easy to get started', answer: 'Disagree', share: 19 },
  { id: 4, question: 'Easy to get started', answer: 'Unsure', share: 8 },
  { id: 5, question: 'Would recommend', answer: 'Agree', share: 63 },
  { id: 6, question: 'Would recommend', answer: 'Neutral', share: 21 },
  { id: 7, question: 'Would recommend', answer: 'Disagree', share: 10 },
  { id: 8, question: 'Would recommend', answer: 'Unsure', share: 6 },
];

const gridEl = document.createElement('div');
const chartEl = document.createElement('div');
gridEl.style.height = '260px';
chartEl.style.height = '420px';
document.body.append(gridEl, chartEl);

const grid = createGrid(gridEl, {
  rowKey: 'id',
  rows,
  columns: [
    { field: 'question', title: 'Question', filter: { type: 'set' } },
    { field: 'answer', title: 'Answer' },
    { field: 'share', title: 'Share (%)', type: 'number' },
  ],
});

createChart({ grid, container: chartEl, type: 'waffle', x: 'answer', y: 'share',
  legend: { values: true }, title: 'Share of respondents by answer' });

The same thing in React

The React adapter is a factory, so you build the component once at module scope. The ref’s grid is the real grid, which is what the chart binds to.

import React, { useEffect, useRef } from 'react';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import { createLatticeGrid } from '@toclocoinc/lattice-grid/modules/react';
import { createChart } from '@toclocoinc/lattice-grid/modules/charts';
import '@toclocoinc/lattice-grid/modules/chart-waffle';

const LatticeGrid = createLatticeGrid({ React, createGrid });
const rows = [
  { id: 1, question: 'Easy to get started', answer: 'Agree', share: 46 },
  { id: 2, question: 'Easy to get started', answer: 'Neutral', share: 27 },
  { id: 3, question: 'Easy to get started', answer: 'Disagree', share: 19 },
  { id: 4, question: 'Easy to get started', answer: 'Unsure', share: 8 },
  { id: 5, question: 'Would recommend', answer: 'Agree', share: 63 },
  { id: 6, question: 'Would recommend', answer: 'Neutral', share: 21 },
  { id: 7, question: 'Would recommend', answer: 'Disagree', share: 10 },
  { id: 8, question: 'Would recommend', answer: 'Unsure', share: 6 },
];
const columns = [
  { field: 'question', title: 'Question', filter: { type: 'set' } },
  { field: 'answer', title: 'Answer' },
  { field: 'share', title: 'Share (%)', type: 'number' },
];

export function SurveyWaffle() {
  const gridRef = useRef(null);
  const chartRef = useRef(null);
  useEffect(() => {
    const chart = createChart({ grid: gridRef.current.grid, container: chartRef.current,
      type: 'waffle', x: 'answer', y: 'share', legend: { values: true } });
    return () => chart.destroy();
  }, []);
  return (<>
    <LatticeGrid ref={gridRef} rowKey="id" columns={columns} rows={rows} style={{ height: 220 }} />
    <div ref={chartRef} style={{ height: 380 }} />
  </>);
}

The options used

These are the rows of the charts reference for the options in the listings above.

Option Type What it does
grid Grid Required. The grid to read.
container Element or string Required. Where to draw.
type string 'waffle' here, one of the chart types the charts module draws.
x string The category column. Here the answer.
y string The measure column that sizes each part. Here the share of respondents.
legend boolean or object Shows the legend. values: true appends each entry’s own total after its name.
title string Drawn above the plot.

Reading the squares

Filter the Question column to one question and count. In the example, Would recommend fills most of its hundred with agreement, while Good value splits closer to even between agree, neutral and disagree. With no filter the chart pools every question’s rows, so filter to one question when you want a single hundred. Because each question’s shares add to 100, the squares match the percentages exactly.

Next

See the waffle beside the other part-to-whole charts in the part-to-whole family demo, read the full list of chart types on the charts page, or follow the how-to for a chart that follows the grid.

Read next

  • Treemap of Disk Usage by Folder

    Bind a treemap to a grid of folders: tile size is bytes, branches are age bands, so stale space stands out. Filter the rows to redraw the chart.

  • Sunburst Chart of Spend by Department

    Bind a sunburst chart to a grid of spend by department, cost centre and vendor: three rings in one chart, and filtering the rows redraws them.

  • Donut Chart of Budget Used Against Remaining

    Bind a donut chart to a grid of budget lines: show spend by category with the remaining budget in the centre, and filter the rows to redraw both.

All posts RSS