Search code examples
pythonmatplotlibcolorscolorbar

Color according to 3 variables - Maxwell triangle


I have a model consisting of three variables u,v,w which change with respect to time and with respect to space. I am especially interested in the ratio of the three variables. But instead of showing three plots, each one for one variable, I would rather like to use only one plot.

My idea is to use the Maxwell triangle (color triangle, see http://homepages.abdn.ac.uk/npmuseum/article/Maxwell/MaxTri.html). I can easily scale each variable that its maximum is at 1. But I don't know whether this idea is realizable. If it makes sense, it should already exist. My question:

  1. How do I convert the three variables to a single value which represents a color (e.g., if I have a filled contour plot, I want each grid cell to have "its ratio")?
  2. Can I use the color triangle as a colorbar?

I try to give a short example to make it easier to understand:

import numpy as np
import matplotlib.pyplot as plt
# create three arrays for the state variables
# space is a 200x200 grid
size = 200
u = np.random.rand(size,size)
v = np.random.rand(size,size)
w = np.random.rand(size,size)
# now I could create 3 subplots and plot the spatial distribution
# for each variable
# but I want something like
col = np.zeros((200,200))
for i in range(200): # loop in x-direction
    for j in range(200): # loop in y-direction
        col[i,j] = colorTriangle(u[i,j],v[i,j],w[i,j])
plt.contourf(col)

The funtion colorTriangle does not exist. But I want something like this: If each variable has the same value at (i,j), the color should be white (see Maxwell triangle). If we have only u, it should be green. If we have only v, it should be red. If we have only w, it should be blue.
If the combination is more complex, each variable should "pull" in one color direction and the color should be chosen according to the location in the Maxwell triangle.

Do you get the idea? It does not necessarily have to be a color triangle but I would have this kind of information in one contourf plot. And the color triangle would help interpreting the colors.


Solution

  • To answer the first question, there are many things that should be noted.

    To start with, the only way that a single value can represent a color is using a colormap, which maps a scalar to a color. However, the Maxwell triangle cannot be reduced to a single value.

    That does not mean that the maxwell triangle cannot be used as a kind of 3D colormap, mapping 3 values to a color. In fact it is quite natural to do, because the Maxwell uses 3 values a, b and c so that the color can be represented in RGB coordinates as (a,b,c). The only thing missing is the normalization.

    In the link provided, the Maxwell triangle is defined such that a+b+c=1. However, matplotlib accepts RGB coordinates as 3 floats between 0 and 1, where white is obvsiously 1,1,1, instead of 1/3,1/3,1/3. Thus, each i,j will have three values that must be converted to 3 floats between 0 and 1 taking this into account.

    Therefore, instead of normalizing dividing by the sum (to get a+b+c=1) we have to normalize dividing by the maximum value of each trio.

    Eventually, the resulting image can be shown using imshow.

    def colorTriangle(r,g,b):
        image = np.stack([r,g,b],axis=2)
        return image/image.max(axis=2)[:,:,None]
    
    size = 200
    X,Y = np.meshgrid(np.linspace(0,1,200),np.linspace(0,1,200))
    u = np.full_like(X,.2)
    v = Y
    w = X**2
    plt.imshow(colorTriangle(v,u,w),origin='lower',extent=(0,1,0,1)) 
    # Note that v is first in order to be represented by red
    

    The output image is the following:

    color triangle

    Here it can be clearly seen that for small values of x and y, where v and w are zero, the color is green, as u is different than zero and much larger than v and w. For large x and small y, w dominates, and the color is indeed blue, and when v dominates (large y and small x), the color is red. It is also shown that for equal values of all three matrices, the resulting color is white.