# How can I generate a heat map from AnyDice results?

I want to show some effects of changing dice rolls on a heat map, where on one axis I have task difficulty (level of a spell, quality of lock to pick etc), and on another character level / proficiency bonus. Color should represent chance of success.

Usually, graphs from AnyDice are hardly useful to just look and easily understand; it generates many lines or bars, when I want it all on one map.

Here is an example program: https://anydice.com/program/1451d - fifty lines of probabilities; not so nice to look at, and not useful to post in answers here.

How can I generate a heat map from AnyDice results?

I want something like what is described here on a sister site: What is a probability heat map? I would prefer an option in AnyDice, if they implemented it and I just don't see it. A tool that can take an export from AnyDice and generate a heat map would be great, too.

Using spreadsheet and conditional formatting, I managed to get roughly what I wanted, but it was a boring and lengthy process:

• While not really what you asked for, for your example query (and others like it with 0/1 results) the transposed or the summary view in AnyDice is at least slightly more readable. Apr 3, 2019 at 8:17

The AnyDice export format is pretty easy to parse: it's basically just CSV text. In fact, you could directly import it into a spreadsheet program, but then you'd have to rearrange the data into a grid there.

To avoid that chore, I wrote a quick Python script to read the exported data from your AnyDice code (specifically, the first section of the AnyDice summary export, from after the "mean" and "output",# lines up to the next blank line), extract the row and column numbers from the output name with a regexp and print the result as a grid:

import csv, sys, re

table = {}
columns = []
row, col = re.findall(r'-?\d+', name)
if row not in table: table[row] = {}
if col not in columns: columns.append(col)
table[row][col] = value

csvwriter = csv.writer(sys.stdout)
csvwriter.writerow([''] + columns)

for row in table:
csvwriter.writerow([row] + [table[row][col] for col in columns])


(The regexp -?\d+ matches one or more digits with an optional minus sign in front, i.e. a whole number. If there aren't exactly two such numbers in the name of each AnyDice output, the script will crash with a ValueError. Anything else in the name of the output gets ignored, so the name "0 foo 2" is just as good as "Spell Level 0, proficiency bonus 2" as far as the script is concerned.)

Running the script on your data (try it online!), it prints the following grid, also in CSV format:

,2,3,4,5,6
0,0.6,0.65,0.7,0.75,0.8
1,0.55,0.6,0.65,0.7,0.75
2,0.5,0.55,0.6,0.65,0.7
3,0.45,0.5,0.55,0.6,0.65
4,0.4,0.45,0.5,0.55,0.6
5,0.35,0.4,0.45,0.5,0.55
6,0.3,0.35,0.4,0.45,0.5
7,0.25,0.3,0.35,0.4,0.45
8,0.2,0.25,0.3,0.35,0.4
9,0.15,0.2,0.25,0.3,0.35


We can then import this into any spreadsheet software, like Microsoft Excel or Open/LibreOffice Calc. Just to do this whole thing online, I decided to use Google Sheets.

After importing the CSV file, I selected the data area (excluding the header row and column), selected FormatConditional formatting... from the menu, and chose the "Color scale" tab in the sidebar that it opens. The default color scale ("green to white") looked a bit ugly and low-contrast to me, so I changed it to "red to white to green", and got this:

Not bad for a first try, in my opinion. Here's the actual spreadsheet, if you want to see it "live". Of course, there's a lot we could do to improve the formatting, like adjusting the column widths and the horizontal alignment of the numbers and adding some labels for the headers, but this should at least demonstrate the basic workflow.