matplotlib imshow a matrix of data has white lines, draw a heatmap of a function y=f(x)

Question:

I want to plot a heatmap of a function y = f(x). y is in [0, 1] and x is in [0, 2]. When x <= 1, f(x)=1; and when x > 1, f(x) = y.

First of all, I generate a matrix of data with a grid size of 0.1, which looks fine. But I want to make the color change smoothly, so I decreased the grid size to 0.02 and 0.01. The strange thing is that now the figure has some weird white lines.

I search online and found some solutions (e.g. How to get rid of white lines in confusion matrix?) like plt.grid(None), ax.grid(None), or plt.rcParams["axes.grid"] = False. I tried all of them, but none of them works for me. Here is my code for drawing the map when gridsize = 0.01.

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
plt.rcParams["axes.grid"] = False

if __name__ == '__main__':

    heat_results = np.empty((101, 101))
    heat_results[:, :] = np.nan
    for x in np.arange(0.0, 1.01, 0.01):
         for y in np.arange(0.0, 2.02, 0.02):
              ind_x = int(x*100)
              ind_y = int(y*50)
              if y <= 1.0: heat_results[ind_x][ind_y] = 1.0
              else: heat_results[ind_x][ind_y] = x

    minv = np.nanmin(heat_results)
    maxv = np.nanmax(heat_results)

    # print('minv, maxv:')

    # print(minv)
    # print(maxv)

    colors = ["lime", "saddlebrown"]
    cmap = LinearSegmentedColormap.from_list("mycmap", colors)

    heat_results = (heat_results - minv) / (maxv - minv)

    fig, ax = plt.subplots()
    ax.grid(False)
    plt.grid(None)
    plt.grid(False)
    im = ax.imshow(heat_results, origin='lower',cmap=cmap)
    ax.grid(False)
    plt.grid(None)
    plt.grid(False)

    cbar = ax.figure.colorbar(im, ax=ax)

    plt.xticks(np.arange(0, 101, 10), np.array([0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0]))
    plt.yticks(np.arange(0, 101, 10), np.array([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]))

    plt.xlabel('t')
    plt.ylabel('x')


    plt.savefig('fig/heat.pdf')
    plt.close()

I also attach my three figures here, you can see how the white line appears when I decrease the step size (smooth the color change).
enter image description here
enter image description here
enter image description here

Any ideas about why these white lines appear when I decrease the grid size? Or any ideas about how to draw the heatmap of the function I described before, besides generating a matrix of data? Basically, I want a figure that looks like the first figure but with a smooth color change (like the color changes in the color bar), and the separation of the left part and the right part of the figure happens exactly at 1.0 (figure 1 does not lie at 1.0 because the grid size is too large).

Asked By: Francis

||

Answers:

Your white lines aren’t related to the grid. These are NaN values that are still in the heat_results. Due to floating point approximation errors, int(x*100) sometimes gets a lower value. In your case, you could use int(round(x*100)), but it would be much better to fully use numpy functions. These are much faster (and also easier to read once you get used to them).

The recommended way to automatically set tick labels for a heatmap uses extent=[x0,x1,y0,y1].

Filling arrays can be simplified using numpy’s broadcasting. For an if test, numpy works with np.where.

import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np

x = np.linspace(0, 1, 101)
y = np.linspace(0, 2, 101)
ys, xs = np.meshgrid(y, x)

heat_results = np.where(ys <= 1, 1.0, xs)

colors = ["lime", "saddlebrown"]
cmap = LinearSegmentedColormap.from_list("mycmap", colors)

fig, ax = plt.subplots()
im = ax.imshow(heat_results, origin='lower', cmap=cmap, extent=[y.min(), y.max(), x.min(), x.max()], aspect='auto')

cbar = ax.figure.colorbar(im, ax=ax)

plt.xlabel('t')
plt.ylabel('x')
plt.show()

heatmap

Answered By: JohanC
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.