2

I'm having a 2D grid of points where each of the points have a corresponding label, which is in the range [0.0, 5.0]. Now I want to do the following:

Plot all points in the grid and color them according to their label.

However, I don't want to do this using a scatter plot. I've tried to do it with a contourf and pcolormesh plot:

import matplotlib.pyplot as plt

np.random.seed(1234)

x = np.linspace(-1.0, 1.0, num=5)
xx, yy = np.meshgrid(x, x)
z = np.random.randint(low=0, high=6, size=xx.shape)
levels = np.arange(0, 6)

fig, axes = plt.subplots(nrows=2, ncols=2)
axes[0, 0].contourf(xx, yy, z)
axes[0, 1].contour(xx, yy, z, colors='k')
axes[1, 0].scatter(xx, yy, marker='.', c=z)
axes[1, 1].pcolormesh(xx, yy, z)
plt.show()

How should I specify the levels of the contourf plot such that I get contour lines separating the labels. (Similar to the pcolormesh plot)

Additionally, how can I fix the color for every label, i.e label 4 should always have color red?

EDIT: This is an example of a contourf plot which produces too many coloured areas:

Actually, there are only two labels in the grid. However, at the border between the two areas, several additional contour lines are drawn.

For the example above, there should be a single contour line separating the two areas (cyan and blue)

I appreciate any help.

kmario23
  • 57,311
  • 13
  • 161
  • 150
Marius Mosbach
  • 105
  • 1
  • 8
  • I do not understand the problem. Using the current code you get the labels as colored areas in the contourf plot. In how far is this not what you want and what is the problem achieving what you need? – ImportanceOfBeingErnest Jan 28 '18 at 14:29
  • Perhaps you are looking for [`plt.clabel`](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.clabel.html)? Here is [an example](https://stackoverflow.com/q/24897681/190597). – unutbu Jan 28 '18 at 14:36

2 Answers2

1

If I understand you correctly, you want something like the pcolormesh plot, but with only the outlines. One way to achieve this is to extend (or widen) your array such that it contains the same value many times in x and y direction. This basically means that your z consists of many plateaus with very steep gradients in between. You can do this easily with np.repeat. Below I show an example where each point in the original data is expanded to a 20x20 plateau.

The colours of the plots can be fixed by creating a custom colormap. In your case, using a ListedColormap should be enough. When using contour, you also have to specify the levels at which the contours should be drawn in order to make it work correctly.

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

cmap = colors.ListedColormap([
    'royalblue', 'cyan','yellow', 'orange', 'red', 'green'
])

np.random.seed(1234)

num = 5
x = np.linspace(-1.0, 1.0, num=num)
xx, yy = np.meshgrid(x, x)
z = np.random.randint(low=0, high=6, size=xx.shape)
levels = np.arange(0, 6)

fig, axes = plt.subplots(nrows=2, ncols=2)
axes[0, 0].contourf(xx, yy, z)
axes[0, 1].contour(xx, yy, z, colors='k')
axes[1, 0].scatter(xx, yy, marker='.', c=z)
axes[1, 1].pcolormesh(xx, yy, z, cmap=cmap)  ##I added here the custom colormap for reference

##expanding the arrays
N = 20
x1 = np.linspace(-1.0, 1.0, num=N*num)
xx1, yy1 = np.meshgrid(x1,x1)
z1 = np.repeat(np.repeat(z, N,axis=0),N).reshape(xx1.shape)

fig2, ax2 = plt.subplots()
ax2.contour(xx1, yy1, z1, cmap=cmap, levels = levels)

plt.show()

produces this kind of plot:

result of the code above

As you can see, the lines are still not quite straight and sometimes two lines next to each other can be seen. This is because the gradients between different plateaus are not equal. I ran another example using N=200, in which case the lines are much straighter:

same as above, but with N=200

Hope this helps.

Thomas Kühn
  • 9,412
  • 3
  • 47
  • 63
  • Thanks for your detailed answer but unfortunately this is not what I want. Assume you have a grid of 100 points and the grid is centered at (0,0). All points on the left have label 2 and all points on the right label 5. What I want is a contourf plot whith a single contour line. Namely the vertical line at x = 0 separating the 2s from the 5s. – Marius Mosbach Jan 28 '18 at 15:34
  • @MariusMosbach Ok, then I guess the other answer does what you want. – Thomas Kühn Jan 28 '18 at 15:35
  • @MariusMosbach Have a look, how I set up the colormap (I just edited the answer) -- is this at least what you have been looking for in your secondary question? – Thomas Kühn Jan 28 '18 at 15:37
1

Possibly you simply forgot to provide the levels you want to show. For N labels, one would need 7 levels, e.g. for labels [0 1 2 3 4 5] one would choose levels such that the labels are in the middle of the level interval, [-0.5 0.5 1.5 2.5 3.5 4.5 5.5].

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

np.random.seed(1234)

x = np.linspace(-1.0, 1.0, num=5)
xx, yy = np.meshgrid(x, x)
z = np.random.randint(low=0, high=6, size=xx.shape)

levels = np.arange(0, z.max()+2)-0.5

fig, ax = plt.subplots()
im = ax.contourf(xx, yy, z, levels=levels)

fig.colorbar(im, ax=ax, ticks=np.unique(z))
ax.contour(xx, yy, z, colors='k',levels=levels)
ax.scatter(xx, yy, marker='.', c=z)

plt.show()

enter image description here

Note that the colors of the contourf plot are slightly different than those of the scatter. The reason is explained in the answer to the question: How does pyplot.contourf choose colors from a colormap?

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712