Editor’s note: Viz Variety Show is an occasional series that aims to help you go beyond bar and line charts. In it, we will showcase various types of visualizations and outline how to build them, when they should be used, and when they should be avoided altogether. Tableau Zen Master Andy Kriebel also has a great post on this chart type. Check out the post on his blog, VizWiz.

It’s rare when I recommend a chart to customers that they’ve never seen before. While I’m confident I can teach one Tableau user at a time, I generally don’t think it’s useful to require a walkthrough for others just so they can understand parts of a dashboard. The exception to this rule happens to be today’s blog topic: the waffle chart. It’s simple enough that people understand it instantly, but it’s also different enough to require explanation. And the explanation often improves the readability and general aesthetic of Key Performance Indicator (KPI) dashboards, which usually have percentages, bullet graphs, and donut charts.

While I find the waffle chart shares almost identical use cases to the donut chart, it excels at showing a more compelling way to visualize 0-100% KPI attainment than an isolated metric can. It also has a niche for showing parts-to-whole contribution. Other than these use cases, you’re mostly forcing things a bit. To me, the second scenario is the differentiator—a higher stressing of the individual points which make up the larger whole.

Good use cases

  • Comparing high-level items or seeing how they contribute to a whole
  • Placing increased emphasis on the part of the whole
  • Using KPI charts as % of total

Bad use cases

  • When many values contribute to a whole
  • When KPI being measured could exceed 100%
  • When exact percentages are vital, as showing fraction of a percent is more difficult to see beyond a rough approximation

Much like the donut chart, there are also two main variants: the same parts-to-a-whole and KPI options. I believe that waffle charts are much better suited for the 1-100% KPI variant than the stacked variant, unlike a donut chart which is a bit more flexible to do either.

In the example above, I’ve shown the stacked variant, where you can start to see some of the ways a waffle chart falls short. The primary issue is that comparing the sections labeled In transit (orange) to Delivered (Blue) is quite difficult unless you look at the actual number. In transit has a partial row on both the top and bottom, something we have to perform math to comprehend and compare effectively. Due to these issues, I prefer the KPI alternative, which is what I will walk through below.

This builds on a much earlier take on the same chart by our very own Jesse Gebhardt. The standard way to make waffle charts is often to round the values and have only whole squares shaded. In this example, I’m going show you how to make waffle charts accurate out to several decimal points.

I’m calling them “Precise Waffle Charts”, as I can’t find an actual name that denotes this distinction, but if you prefer the less precise, rounded variant, you can view and download a workbook with descriptions for each step here.

Keep in mind that even the precise waffle chart will never be ideal for extreme precision on its own because the human eye is unlikely to accurately guess how much of a square is shaded past a decimal or so. The label should be able to clarify the exact number to whatever decimal precision you prefer.


The first thing to know about waffle charts is that they require data blending. Have no fear if your blending skills aren’t up to scratch—there is actually no shared field necessary, and there is also no need for the step of establishing relationships. The blended data set is simply a lattice/densified matrix of data. It holds only two fields, one for Rows and another for Columns. Each has a value from 1-10, and the result is the matrix of 100 rows with every row and column combination. Here we are really just trying to get a data point for each “square”, or cell, of data. This small size of data (and lack of a true blend) means performance is not adversely affected from the additional data set. Once you have this done, you only need some metric to shade on (ideally some ratio that is always 0-100%).

Step 1

To make the skeleton of the waffle chart, we first need to generate the 100 cell matrix. To do this, drag Columns to Columns and Rows to Rows. Then convert the chart to a Bar mark type. You should end up with 100 bars like the below.

Step 2

We’ll tackle the fit and finish of sizing the bars in a moment, but for now let’s work on the shading for individual “cells”. There are multiple ways to do this: build the number into the data, use table calculations, or write a standard, arithmetic calculation. It’s dealer’s choice on what you find easiest, though I like to write a calculation in the few cases where I might want to get clever and manipulate my waffle chart (for reasons like weighting specific items or making fewer than 100 squares). Remember that this data set isn’t our actual data, so the calculation must refer to an aggregate calculation from somewhere else. I use a calculation called Shaded:

IF AVG(100-(10*[Rows])+[Columns]) ELSEIF AVG(100-(10*[Rows])+[Columns]) = FLOOR([Sample - Superstore].[Southwest Sales]*100) THEN 1-((([Sample - Superstore].[Southwest Sales]*100)-FLOOR([Sample - Superstore].[Southwest Sales]*100)))

While you can generally just copy/paste this calculation, then substitute your field names to make everything work correctly, I’ll take a minute to break down what this calculation is doing. The first line generates a “full” bar from 0 to 1. The second section provides the logic for what Tableau needs to do in the event that only part of the bar should be shaded. I use this in conjunction with a calculation called Unshaded, which is the corollary to the above:

IF AVG(100-(10*[Rows])+[Columns]) > FLOOR([Sample - Superstore].[Southwest Sales]*100) THEN 1
ELSEIF AVG(100-(10*[Rows])+[Columns]) = FLOOR([Sample - Superstore].[Southwest Sales]*100) THEN (([Sample - Superstore].[Southwest Sales]*100)-FLOOR([Sample - Superstore].[Southwest Sales]*100))

This is the complete opposite of Shaded—only shading the parts of the bars that were not shaded by the previous calculation.

Now that we have created the calculations, let’s get them drawn in the viz. Take Measure Values and drag it to Columns, then Take Measure Names and drag this to Color. Finally, drag all measures off of your Measure Values card which are not Shaded or Unshaded. You should end up with something like this:

In the event that the bar split into two colors is in the wrong order, simply reorder the fields on your Measure Values card, and this should correct itself.

Step 3

Our waffle chart is shaping up nicely, but we need to trim out some headers, space things correctly, and add a label for easy reference. Find a darker color for “shaded”, and a lighter variant of the same color, or a light gray, for the unshaded portion.
Next, you’ll want to size the chart correctly. As waffle charts are highly sensitive to the size of the visualization (resizing adds or removes the whitespace between squares), they work best in fixed-sized containers or dashboards. My recommendation is to hide all headers first, set the sheet to Fit Entire View on your dashboard, then work out the ideal size of the container for the bars. For the last part, increase the size of the Size slider until the gap is about the desired size, then fix the width of the container to make the gap the same size.

Step 4

Last, I want to provide a label for easy reference to the overall percentage. To do this, I use an annotation, then orient the label wherever I think appropriate.

On this one, I waffle (hah!) between centered and upper left/right. Play around a bit to find what fits the format of your data/dashboard best. To start labeling, make sure your underlying calculation is on Detail or exists somewhere on your waffle chart. Next, annotate your chart by right-clicking a square (I prefer in the lower right), and then selecting Annotate Mark (it won’t matter which square you choose). Delete everything but the AVG([Rating %]) or whatever your field happens to be. I just wrap my metric in WINDOW_SUM() to get my total of 47.37%, but you could use a different value that wasn’t blended, if you prefer. Right-click and format to remove the line, adjust shading, or tweak sizing and shading or any other parameters.

I’ve also removed all the lines and borders from the chart for cleaner formatting, to get a final result which looks a bit like this:

Bonus: If you notice circles dancing around at the intersections of the waffle chart, you’re noticing another guest appearance by the Moiré Effect that I mentioned when talking about Lollipop charts.

If you’re looking for some real-world use cases of waffle charts (or similar), you may have seen a viral video that went around last year, visualizing loss of life by various countries in WWII. While technically a pictogram (a good waffle chart alternative for when metrics don’t add up to 100%), the two charts share many similarities. There are a number of similar videos and visualizations which utilize the same technique of icons related to the subject matter - the trick is to make sure these don't detract from the visualization.

You might also be interested in...


Waffle Chart Example 1 is incorrect. Firstly the labels for West and Central need swapping. I'd also recommend the values in the labels match the number of squares and therefore a round() function should should be introduced to the calculations to ensure the labels and colours round the same way, i.e.

IF AVG(([Rows]*10)-(10-[Columns])) <= ROUND([Sample - Superstore].[Central Sales]*100,0) THEN "Central"
ELSEIF AVG(([Rows]*10)-(10-[Columns])) <= round(([Sample - Superstore].[Central Sales]+[Sample - Superstore].[East Sales])*100,0) THEN "East"
ELSEIF AVG(([Rows]*10)-(10-[Columns])) <= round(([Sample - Superstore].[Central Sales]+[Sample - Superstore].[East Sales]+[Sample - Superstore].[West Sales])*100,0) THEN "West"
ELSE "South" END

It's a fair comment Chris - thanks for the catch!

I've updated the published versions to use the same rounding logic as the cells themselves, but I've switched to showing a decimal point in the viz. Though it sacrifices simplicity for accuracy, this is probably better than labels which do not match the viz.

Honestly, this probably just underscores why the stacked variant is really not my preferred option for waffle charts. To explain further, even with updating the viz with your calculations, you would get a label with East at 30% but a chart which shows 29%. The simple fact is that with more than 2 members, you run a high chance of having to round one of the items "improperly" to match the viz (or the reverse), as it's rare you have a perfect split of items that round up and down. Either way, with rounding the underlying problem remains that 22+30+32+17 != 100. The only real way to do this would be to weight all the decimals/fractions, rank them, and allocate the "extra" square/cell(s) to the highest ranking values, then make the labels match appropriately. Something which I've done before, but is probably outside the scope of this tutorial as it was really meant to be about waffle chart precision as there are already a few good posts on the basic waffle chart type in the community (see the link in the preface). Sounds like a good opportunity for someone in the community to do a follow-up post which explains the rounding/ranking issue and incorporates the ranking logic I mentioned above :)

Add new comment

Subscribe to our blog