How to implement colormaps like Rainbow and Viridis in code

I've been working hard on making my very own digital wind tunnel in the Unity game engine. It's based on a tutorial from the YouTube series 10 Minute Physics called "How to write an Eulerian Fluid Simulator with 200 lines of code." I translated the code from JavaScript to C#, and I open sourced the implementation here: Ten Minute Physics in Unity. 

To simulate any fluid you need to study the Navier-Stokes equations. These are very hard to solve. In fact so hard they are a part of the Millennium Prize Problems where you can win a million dollars if you gain some insight while solving them. Therefore you need to simplify them. But even though they are simplified you can still see the vortex shedding that's happening in real wind tunnels if you put a cylinder in them. I thought this was really cool because the simulation part is just 200 lines of code running at 70 fps on the CPU.  

Common colormaps

I wanted to improve the wind tunnel by making it more realistic, by optimizing the code, and by making it look better. To make it look better I wanted to implement different colormaps. A colormap is basically a function that takes a value as input and out pops a color. 

The YouTube tutorial I followed is implementing a colormap called Rainbow - also known as Jet or hot-to-cold. Matthias Müller, who made the tutorial, is calling it the "scientific color scheme." I'm using the colormaps to visualize the pressure field. The left image is the pressure field in the wind tunnel, and the right image is the pressure field in a bathtub filled with water. 

Rainbow colormap

You can easily identify the low pressure areas (blue) and the high pressure areas (red). The tutorial I followed came with code to implement the Rainbow colormap - but without comments. To understand the code I googled something like "How to implement the Rainbow color map." The results I found were not of code - but of hate: "Don't Use the Rainbow Color Map" or "Why you should use Viridis and not Jet (rainbow) as a colormap."

The problem with the Rainbow colormap is that it can be easy to misunderstand the data. Research shows that "Physicians who use jet in diagnosing heart disease take longer and make significantly more errors than those who use decent colormaps." A good example why Rainbow can be a bad choice can be seen in this video. You can see that there's a distinctive border between the yellowish and greenish parts even though the yellowish and greenish values are very similar. 

Why the Rainbow colormap can be a bad choice

To improve the Rainbow colormap, Google came up with the Turbo colormap. It has smoother transitions between the colors while still having a high contrast between the colors. But Turbo can still be harsh on the eyes - like the Rainbow colormap. Again, red means high pressure and blue means low pressure. 

Turbo colormap

The simplest colormap of them all is the grayscale. If you use it you know the transitions between high and low pressure areas will be smooth. 

Grayscale colormap

The Rainbow colormap has been used for years. Then one day Matlab decided they had had enough of it and developed the Parula colormap. They even replaced the Rainbow with the Parula colormap as the default colormap in their software. They also decided they didn't want to share the Parula colormap with the world so it's not open source. But the open source community decided to develop their own colormap called Viridis as explained in this video: A Better Default Colormap for Matplotlib. Viridis is very similar to Parula, and looks like this: 

Viridis colormap

Another colormap developed by the same people behind the Viridis colormap (Nathaniel Smith and Stéfan van der Walt) is Inferno. This colormap is similar to a colormap called "black body" which is based on colors from black-body radiation but Inferno is supposed to be more appealing (source).  

Inferno colormap

Yet another colormap by the people behind Viridis is Plasma. It is similar to Inferno but removes the lower black colors to make it more appropriate for 3D surfaces (source).

Plasma colormap

The last colormap I experimented with was Magma which is very similar to Inferno. I haven't found why you should use Magma instead of other similar colormaps. I you know, please leave a comment. 

Magma colormap

How to implement colormaps in code

I've implemented these colormaps in C# and Unity, but you should easily figure out how to implement them in other programming languages. I'm also using Color32 so all my colors should be three bytes (red, green, blue) each in the range 0 → 255 (and also the alpha channel).

Rainbow  

After scrolling through the Rainbow hate I finally found a stackoverflow question how to implement it. The basic idea is that you split the range into four buckets, and then you lerp between the colors blue → cyan → green → yellow → red by using a strength parameter. It looks like this in C# and Unity:

Rainbow code

I think you could also use a lookup table which might be faster. You can generate the lookup table with this code. 

Grayscale

Grayscale comes next because we need it to implement the other colormaps. The secret is the InverseLerp to get a value in the rage 0 → 1. And then I inversed it because I felt that white should be low pressure and black should be high pressure. 

Grayscale code

Turbo

To implement Turbo I used a lookup table from GitHub. The array has 256 rows because a color can be split into red, green, blue where the red, green, blue can be in the range 0 → 255. To get a color from the table you need to find the index in the array based on the grayscale value. 

Turbo code
Viridis, Inferno, Plasma, Magma

The lookup table for Viridis, Inferno, Plasma, and Magma can be found here: GitHub. The problem now is that the array is in the [] format while C# wants it to be in the {} format. Unless you want to replace the brackets one-by-one, you should copy the entire array into Notepad++ (or whatever text editor you prefer) and replace all [] with {} before copying the entire gaggle into Unity. Then the code is the same as for Turbo. 

Viridis code

As a side note I asked ChatGPT to generate code that can generate the Viridis colors without using a lookup table. It generated the method ViridisColorMap which I was really excited to try out. It turned out the AI lied - it had just generated the Rainbow colormap and changed the name of the method. But the method was different from the Rainbow colormap method I implemented, and that was at least a little cool.

Comments