Search code examples
rdata-visualizationvisualizationhexagonal-tiles

Constructing a hexagonal heat-map with custom colors in each cell


I would like to generate a hexagonal lattice heat-map in which each cell represents a group. Likewise, each cell would be a hexagon with a unique color (fill, set by a column color in the data-frame) value, and a saturation (alpha) value corresponding to continuous decimal values from a chemical concentration dateset.

I would like to use a standardized data format which would allow me to quickly construct figures based on standardized datasets containing 25 groups.

For example, a datasheet would look like this:

      structure(list(group = 1:25, color = c("red", "brown1", "hotpink1", 
      "orange", "indianred1", "magenta", "darkgoldenrod1", "goldenrod1", 
      "gold", "deeppink", "yellow", "darkseagreen1", "aquamarine", 
      "plum", "mediumorchid4", "olivedrab1", "limegreen", "thistle1", 
      "violetred", "green4", "mediumseagreen", "darkviolet", "lightseagreen", 
      "dodgerblue2", "deepskyblue4"), alpha = c(NA, NA, NA, NA, NA, 
      NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
      NA, NA, NA, NA), x = c(1, 1.5, 1.5, 2, 2, 2, 2.5, 2.5, 2.5, 2.5, 
      3, 3, 3, 3, 3, 3.5, 3.5, 3.5, 3.5, 4, 4, 4, 4.5, 4.5, 5), y = c(3, 
      3.5, 2.5, 4, 3, 2, 4.5, 3.5, 2.5, 1.5, 5, 4, 3, 2, 1, 4.5, 3.5, 
      2.5, 1.5, 4, 3, 2, 3.5, 2.5, 3)), class = "data.frame", row.names = c(NA, 
      -25L))

A plot of this kind in which alpha = 1 for all groups might look like this:

key plot - all cells fully saturated (`alpha = 1~)

Whereas plots of dataset1 and dataset2 (included below) would look like these, respectively:

dataset1

dataset2

I would like to use something simple, like hexbin(), but I haven't figured out how to get that to work for this application.

Dataset1:

  structure(list(group = 1:25, color = c("red", "brown1", "hotpink1", 
  "orange", "indianred1", "magenta", "darkgoldenrod1", "goldenrod1", 
  "gold", "deeppink", "yellow", "darkseagreen1", "aquamarine", 
  "plum", "mediumorchid4", "olivedrab1", "limegreen", "thistle1", 
  "violetred", "green4", "mediumseagreen", "darkviolet", "lightseagreen", 
  "dodgerblue2", "deepskyblue4"), alpha = c(1, 1, 0.5, 0.5, 0.2, 
  0.2, 0, 0, 0.3, 0.1, 1, 0, 0, 0, 0.7, 0, 0, 0, 0, 0, 0, 0, 0, 
  0.5, 0.9), x = c(1, 1.5, 1.5, 2, 2, 2, 2.5, 2.5, 2.5, 2.5, 3, 
  3, 3, 3, 3, 3.5, 3.5, 3.5, 3.5, 4, 4, 4, 4.5, 4.5, 5), y = c(3, 
  3.5, 2.5, 4, 3, 2, 4.5, 3.5, 2.5, 1.5, 5, 4, 3, 2, 1, 4.5, 3.5, 
  2.5, 1.5, 4, 3, 2, 3.5, 2.5, 3)), class = "data.frame", row.names = c(NA, 
  -25L))

Dataset2:

structure(list(group = 1:25, color = c("red", "brown1", "hotpink1", 
"orange", "indianred1", "magenta", "darkgoldenrod1", "goldenrod1", 
"gold", "deeppink", "yellow", "darkseagreen1", "aquamarine", 
"plum", "mediumorchid4", "olivedrab1", "limegreen", "thistle1", 
"violetred", "green4", "mediumseagreen", "darkviolet", "lightseagreen", 
"dodgerblue2", "deepskyblue4"), alpha = c(0.3, 0.5, 0.6, 0, 0.7, 
0, 0, 0, 0, 0, 0, 0.5, 0.3, 0, 0, 0, 0, 0.6, 0.8, 0.5, 0.7, 0.5, 
0.5, 0.7, 0.5), x = c(1, 1.5, 1.5, 2, 2, 2, 2.5, 2.5, 2.5, 2.5, 
3, 3, 3, 3, 3, 3.5, 3.5, 3.5, 3.5, 4, 4, 4, 4.5, 4.5, 5), y = c(3, 
3.5, 2.5, 4, 3, 2, 4.5, 3.5, 2.5, 1.5, 5, 4, 3, 2, 1, 4.5, 3.5, 
2.5, 1.5, 4, 3, 2, 3.5, 2.5, 3)), class = "data.frame", row.names = c(NA, 
-25L))

Solution

  • If you're open to creating the plot in Python, the following approach would work:

    import matplotlib.pyplot as plt
    from matplotlib.patches import RegularPolygon
    import numpy as np
    
    data = {'group': np.arange(1, 26),
            'color': ["red", "brown", "hotpink", "orange", "indianred", "magenta", "darkgoldenrod", "goldenrod", "gold", "deeppink", "yellow", "darkseagreen", "aquamarine", "plum", "mediumorchid", "olivedrab", "limegreen", "thistle", "violet", "green", "mediumseagreen", "darkviolet", "lightseagreen", "dodgerblue", "deepskyblue"],
            'alpha': np.ones(25)}
    
    fig, ax = plt.subplots()
    ax.set_aspect('equal')
    ax.axis('off')
    
    ind = 0
    N = 5
    for x in np.arange(1, 2*N):
        num_y = N - abs(x - N)
        for y in range(N + num_y, N - num_y, -2):
            hexagon = RegularPolygon((x, y/np.sqrt(3)), numVertices=6, radius=2 / 3, orientation=np.pi/2,
                                     alpha=data['alpha'][ind],
                                     facecolor=data['color'][ind], edgecolor='k')
            ax.add_patch(hexagon)
            ax.text(x, y/np.sqrt(3), f"Group{data['group'][ind]}", color='black', ha='center', va='center')
            ind += 1
    plt.autoscale(enable=True)
    plt.show()
    

    hexagonal grid