How to plot a heatmap under a curve?

If I were to have a data for a one-dimensional system evolving in time, essentially a two-dimensional array, and the array at each point in time is of the same size, how would I produce something like this:

(Taken from Turing’s model for biological pattern formation and the robustness problem by Maini et al., 2012)

I have tried to replicate this with matplotlib by resizing (or rather synthesising) each instance in time to an array of specific length, according to the growth of the domain, and filling the rest of the array with NaNs.

import numpy as np
import matplotlib.pyplot as plt

N = 750
x = []

t = np.linspace(0, N, N)

def asize(i, N):        # Computes the necessary size of the array
return int(N*np.exp(2*(i-N)/N))

for i in range(N):      # Concatenating data with whitespace
x.append(np.concatenate((np.sin(np.linspace(0,3*np.pi,asize(i,N)))**2,
np.NaN*np.zeros(N-asize(i,N)))))

x = np.transpose(np.array(x))
plt.imshow(x, cmap = 'Spectral_r', origin = 'lower')
plt.plot(t, N*np.exp(2*(t-N)/N), c='white', lw = 2)     # Making the boundary smoother
plt.axis([0,N,0,N])
plt.xlabel('$$t$$')
plt.ylabel('$$x$$')
plt.xticks([0,250,500,750])
plt.yticks([0,250,500,750])
plt.show()


Naturally, with actual data this method would be even more tedious, requiring to somehow squish the arrays. Is there a more reasonable way of doing this with matplotlib, Mathematica or any other tool?

• If are able to explain how the original figure is obtained, maybe we can help you with how to do it. Apr 13, 2020 at 1:53
• It is a simulation of a system on a 1D domain using finite differences. The growth of the domain is supposedly achieved by changing the value of a parameter with time, so the actual number of points doesn't change. The problem then is to "squeeze" this data under an appropriate growth curve. Apr 13, 2020 at 9:09

I answered a similar question in StackOverflow.

The main "trick" is to transform your grid before plotting. For example, using the following transformation

\begin{align} &t' = t\, ,\\ &x' = x e^t\, , \end{align}

and then use $$(t', x')$$ for your plot with contourf() or pcolormesh().

Following is a snippet showing the main idea.

import numpy as np
import matplotlib.pyplot as plt

t, x = np.pi*np.mgrid[0:1:100j, 0:1:100j]
val = x
new_x = x*np.exp(t)

# plt.contourf(t, new_x, val)
plt.pcolormesh(t, new_x, val)
plt.xlabel("t")
plt.ylabel("x")
plt.show()


And this is the result.

• Thanks, this is what I was looking for! Apr 14, 2020 at 9:31