'Python Matplotlib - imshow but with hexagons

Code is:

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

example_data = np.random.randint(4, size=(40,44))
cmap = colors.ListedColormap(['black', 'green', 'red', 'blue'])
bounds = [0,1,2,3,4]
norm = colors.BoundaryNorm(bounds, cmap.N)

img = plt.imshow(example_data, interpolation = 'nearest', origin = 'lower',
cmap = cmap, norm = norm)

Which gets me roughly what I want. What I am looking for is if there is a way to get the shape of each tile to be hexagonal rather than square? I think imshow might not be the way to do it but if there is a way you can change the default tile it would be good.

Thanks.



Solution 1:[1]

Here is a solution using patches:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection

nx = 40
ny = 44
example_data = np.random.randint(4, size=(nx,ny))
cmap = colors.ListedColormap(['black', 'green', 'red', 'blue'])
bounds = [0,1,2,3,4]
norm = colors.BoundaryNorm(bounds, cmap.N)

x = np.linspace(0, 1, nx)
y = np.linspace(0, 1, ny)
X, Y = np.meshgrid(x, y)

dx = np.diff(x)[0]
dy = np.diff(y)[0]
ds = np.sqrt(dx**2 +  dy**2)

patches = []
for i in x:
    for n, j in enumerate(y):
        if n%2:
            polygon = mpatches.RegularPolygon([i-dx/2., j], 6, 0.6*dx)
        else:
            polygon = mpatches.RegularPolygon([i, j], 6, 0.6*dx)
        patches.append(polygon)
    
collection = PatchCollection(patches, cmap=cmap, norm=norm, alpha=1.0)

fig, ax = plt.subplots(1,1)
ax.add_collection(collection)
collection.set_array(example_data.ravel())
plt.show()

which looks like this,

enter image description here

Previous solution, it doesn't tessellate nicely and the hexagons are poorly shaped but you could use a scatter plot with coloured hexagons,

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

nx = 40
ny = 44
example_data = np.random.randint(4, size=(nx,ny))
cmap = colors.ListedColormap(['black', 'green', 'red', 'blue'])
bounds = [0,1,2,3,4]
norm = colors.BoundaryNorm(bounds, cmap.N)

x = np.linspace(0, 1, nx)
y = np.linspace(0, 1, ny)
X, Y = np.meshgrid(x, y)

img = plt.scatter(X.ravel(),Y.ravel(),c=example_data.ravel(), cmap=cmap, norm=norm, s=360, marker=(6, 0), alpha=0.4)

plt.colorbar(img)
plt.show()

which looks like,

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1