0

I have XYZ data. X and Y are coordinates of some random points inside a star-shaped domain. I want to plot a heatmap for this data. The objective is to reproduce this figure in matplotlib:

enter image description here

I have already tried the two solutions proposed for this and this question. None of them worked.

The coordinates of the star are as follows:

coords= [(0.5, 0.0), (0.8660254037844387, 0.49999999999999994), (0.25000000000000006, 0.4330127018922193), (6.123233995736766e-17, 1.0), (-0.2499999999999999, 0.43301270189221935), (-0.8660254037844385, 0.5000000000000003), (-0.5, 6.123233995736766e-17), (-0.8660254037844388, -0.4999999999999997), (-0.2500000000000002, -0.4330127018922192), (-1.8369701987210297e-16, -1.0), (0.24999999999999967, -0.4330127018922195), (0.8660254037844384, -0.5000000000000004), (0.5, -1.2246467991473532e-16)]

Let's

X=array([-0.10885458,  0.38719084,  0.126246  ,  0.32831633, -0.43470323,
       -0.14589308,  0.03527489, -0.30802489,  0.03631802, -0.6407443 ,
        0.1420586 , -0.04242902,  0.56713419,  0.03697127,  0.56324232,
       -0.17307027,  0.23414952, -0.1249898 ,  0.10993816, -0.15574171,
        0.22480668, -0.16938372,  0.46415079,  0.05454076,  0.63360403,
       -0.43812225,  0.39817569, -0.31963035, -0.31926434,  0.16913435,
        0.68687168, -0.14839105,  0.53042922, -0.04944691, -0.20848955,
        0.60348851, -0.23746634, -0.00968032, -0.63404439, -0.05204527,
        0.27697056, -0.0023835 , -0.60480204, -0.29335925,  0.08750121,
        0.13853292,  0.01434203, -0.51095204,  0.17537239, -0.21610341])

and

Y = array([-0.10566327,  0.36444335,  0.50664288,  0.34520176,  0.12666237,
        0.24523639,  0.45936775,  0.36855297, -0.89093646,  0.25080176,
       -0.21871761,  0.56413549, -0.37842424, -0.85040143,  0.28691973,
       -0.02916441,  0.20025945, -0.25469069,  0.52055077, -0.23973923,
       -0.03349382, -0.4850852 , -0.22147722,  0.82357372,  0.19736351,
        0.16366808, -0.30763208, -0.07932644,  0.18458957,  0.19116663,
       -0.37589083, -0.62173701, -0.08265561,  0.28642521, -0.3096187 ,
        0.18280694,  0.0287418 , -0.35277588,  0.41465303,  0.77087622,
       -0.20084426,  0.72120447, -0.29936638,  0.39579946,  0.35693334,
        0.41785566, -0.39066645,  0.01689062,  0.25396642,  0.12154352])

and

Z = array([0.36857377, 0.08481739, 0.08529314, 0.09577443, 0.12750615,
       0.22158901, 0.18614892, 0.0703758 , 0.0111191 , 0.03745636,
       0.24347694, 0.13703608, 0.08855241, 0.03235803, 0.11979384,
       0.33964959, 0.23354923, 0.23385712, 0.09479431, 0.22835837,
       0.29181292, 0.0550857 , 0.15981413, 0.02425207, 0.01008352,
       0.14666378, 0.14105369, 0.20266958, 0.25451451, 0.25561241,
       0.07160838, 0.0181599 , 0.02512438, 0.25329402, 0.14160124,
       0.02455915, 0.275493  , 0.25261528, 0.05976918, 0.04502752,
       0.23377016, 0.11031544, 0.09229812, 0.04252507, 0.1807899 ,
       0.11100155, 0.23271334, 0.00184005, 0.19467501, 0.31437854])

I think the problem is that the shape is not convex and that's why most of the interpolation methods fail. Your thoughts would be appreciated.

Basilique
  • 150
  • 1
  • 11

1 Answers1

1

The matplotlib routine tripcolor, I think gets you close to what you are after. You will need additional triangulation than I have used in the example below.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as mtri

xy = [(0.5, 0.0),(0.8660254037844387, 0.5),(0.25, 0.4330127018922193),(0, 1.0),
      (-0.25, 0.43301270189221935),(-0.8660254037844385, 0.5),(-0.5, 0), (-0.8660254037844388, -0.5),
      (-0.25, -0.4330127018922192),(0, -1.0),(0.25, -0.4330127018922195),(0.8660254037844384, -0.5),
      (0.5, 0),(0,0)]

z = [ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5 ]
xy = np.array(xy)

triangles = [[0,1,13],[1,2,13],[2,3,13],[3,4,13],[4,5,13],[5,6,13],[6,7,13],[7,8,13],
             [8,9,13],[9,10,13],[10,11,13],[11,12,13],[12,0,13]]
triang = mtri.Triangulation(xy[:,0], xy[:,1], triangles=triangles)

fig1, ax1 = plt.subplots()
ax1.set_aspect('equal')
tpc = ax1.tripcolor(triang, z, shading ='gouraud')

enter image description here

Chris Seeling
  • 606
  • 4
  • 11
  • Thanks Chris. Your solution works perfectly for the triangles you defined manually. However, when I use the `mtri.Triangulation` for the real `x`, `y` inside the star and giving `triangles=None`, and then applying the `tripcolor`, it still generates triangles outside of the star. What is the proper way to generate the internal triangle grid based on some given `xy` points ? Thank you again. – Basilique Jul 18 '22 at 11:57
  • It seems that I should mask the unwanted triangles but the masking condition is not straightforward to set. Do you have any thoughts on this? – Basilique Jul 18 '22 at 12:31
  • The solution proposed [here](https://stackoverflow.com/questions/52457964/how-to-deal-with-the-undesired-triangles-that-form-between-the-edges-of-my-geo/52463638#:~:text=If%20the%20shape%20of%20the%20geometry%20is%20well%20defined%2C%20say%20by%20a%20curve%2C%20one%20can%20check%20for%20each%20triangle) works for masking unwanted triangles. The problem is that the [final result](https://ibb.co/C1qcvNz) is not flawless near the edges. Please see the figure. – Basilique Jul 18 '22 at 13:20
  • 1
    Try a different approach for triangulation. For example the shape has 6 parts that only differ by a rotation. – Chris Seeling Jul 18 '22 at 22:06
  • 1
    Another approach to avoid the extra triangles is to map your domain to a convex shape. A simple way to do this is to first transform to polar, then stretch the r coordinate with a linear periodic function. I used `R*(np.mod(T,60)/30+1)` where T are the angles in degrees and R are the coordinate radiis. Run the triangulation on the transformed coordinates. Then use this triangulation for plotting by loading back the original X and Y. – Chris Seeling Jul 19 '22 at 00:55