Heatmap_3D.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import UnityEngine as ue
  2. import numpy as np
  3. import seaborn as sns
  4. import matplotlib.pyplot as plt
  5. import matplotlib.patches as patches
  6. from matplotlib.colors import LinearSegmentedColormap
  7. import pandas as pd
  8. WIDTH = int(70)
  9. HEIGHT = int(35)
  10. OBSTACLE_PATH = "Assets/Data_image/obstacle.pkl"
  11. POSITION_PATH = ue.Application.dataPath + "/Data_position/80/Walk4.csv"
  12. HEATMAP_PATH = "Assets/Data_image/80/heatmap4.png"
  13. # Generate only if obstacles change
  14. def set_obstacles(maximum):
  15. """
  16. set_obstacles creates a DataFrame which marks the positions of the obstacles.
  17. The obstacles are marked with the negative maximum and the file is placed at the path.
  18. The negative maximum is used so that the cmap can assign the correct colors to the values.
  19. Since no other negative numbers exist and the next highest number is 0, the negative values are painted 'grey'
  20. and the other [0-maximum] are painted according to the color gradient between the two specified colors.
  21. :param maximum: Is the maximum to the associated positions file
  22. """
  23. global list_obstacle_length
  24. positions = pd.DataFrame(np.zeros((HEIGHT, WIDTH)))
  25. obstacles = ue.Object.FindObjectsOfType(ue.GameObject)
  26. for obstacle in obstacles:
  27. if(obstacle.layer == 15 or obstacle.layer == 12):
  28. startWidth = int(obstacle.transform.position.x - obstacle.transform.localScale.x / 2)
  29. endWidth = int(obstacle.transform.position.x + obstacle.transform.localScale.x / 2)
  30. startHeight = int(obstacle.transform.position.z - obstacle.transform.localScale.z / 2)
  31. endHeight = int(obstacle.transform.position.z + obstacle.transform.localScale.z / 2)
  32. for currentW in range(startWidth, endWidth, 1):
  33. for currentH in range(startHeight, endHeight, 1):
  34. positions[currentW][currentH] = -maximum
  35. positions.to_pickle(OBSTACLE_PATH)
  36. def set_patches(plt):
  37. """
  38. set_patches uses the positions of the obstacles to draw a black border around them.
  39. :param plt: The plot, where the figure is placed, so it can be modified by this function
  40. """
  41. obstacles = ue.Object.FindObjectsOfType(ue.GameObject)
  42. for obstacle in obstacles:
  43. if(obstacle.layer == 15):
  44. startWidth = int(obstacle.transform.position.x - obstacle.transform.localScale.x / 2)
  45. endWidth = int(obstacle.transform.position.x + obstacle.transform.localScale.x / 2)
  46. startHeight = int(obstacle.transform.position.z - obstacle.transform.localScale.z / 2)
  47. endHeight = int(obstacle.transform.position.z + obstacle.transform.localScale.z / 2)
  48. # plt.gca().add_patch(
  49. plt.add_patch(
  50. patches.Rectangle(
  51. (startWidth, startHeight),
  52. endWidth - startWidth,
  53. endHeight - startHeight,
  54. fill=False,
  55. color='black'
  56. )
  57. )
  58. # 1. Get position data from csv file
  59. data = pd.read_csv(POSITION_PATH, sep=';', usecols=["Position x", "Position z"], decimal=',', dtype={'Position x': float, 'Position z': float})
  60. data = data.round(0)
  61. # 2. Group by positions and count appearance
  62. data_count = data.groupby(['Position x', 'Position z']).size().reset_index(name='counts')
  63. # 3. Create wide-form DataFrame for generating heatmap
  64. positions = data_count.loc[:,:].reset_index().pivot(index='Position z', columns='Position x', values='counts')
  65. # 4. Fill missing values
  66. positions.fillna(0, inplace=True)
  67. # 5. Reindex DataFrame (70,35) size of Surface; (70, 35) first x width then z height
  68. positions = positions.reindex_axis(range(0, HEIGHT), axis=0, fill_value=0)
  69. positions = positions.reindex_axis(range(0, WIDTH), axis=1, fill_value=0)
  70. # 6.1 Get maximum value of positions data
  71. max1 = pd.DataFrame(positions).max().max() # Gets the maximum of each column and than the maximum of the maximums
  72. # 6. Get obstacles (obstacles, market stalls) and paste specific value in positions
  73. # Therefore save pkl file in folder and read from it afterwards
  74. set_obstacles(max1)
  75. positions_heatmap = pd.read_pickle(OBSTACLE_PATH)
  76. # 6.1 Merge positions data with obstacles data
  77. positions_heatmap.where(positions_heatmap != 0, positions, inplace=True)
  78. # 6.2 Debug Output
  79. # positions_heatmap = pd.DataFrame(positions_heatmap)
  80. # positions_heatmap.to_html('Assets/Data_image/positions_heatmap.html')
  81. # 7. Plot the heatmap
  82. fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
  83. ax4.remove()
  84. # cmap = LinearSegmentedColormap.from_list(name='greenToRed', colors=['grey', 'limegreen', 'chartreuse', 'yellow', 'darkorange', 'red'])
  85. cmap19 = LinearSegmentedColormap.from_list(name='2019', colors=['grey', (0.40,0.76,0.65), (0.11,0.62,0.47)])
  86. cmap20 = LinearSegmentedColormap.from_list(name='2020', colors=['grey', (0.99,0.55,0.38), (0.85,0.37,0.01)])
  87. cmap21 = LinearSegmentedColormap.from_list(name='2021', colors=['grey', (0.55,0.63,0.80), (0.46,0.44,0.70)])
  88. heatmap = sns.heatmap(positions_heatmap, cmap=cmap19, cbar=False, square=True, yticklabels=False, xticklabels=False, ax=ax1)
  89. heatmap.invert_yaxis()
  90. heatmap.set_title(cmap19.name)
  91. heatmap2 = sns.heatmap(positions_heatmap, cmap=cmap20, cbar=False, square=True, yticklabels=False, xticklabels=False, ax=ax2)
  92. heatmap2.invert_yaxis()
  93. heatmap2.set_title(cmap20.name)
  94. heatmap3 = sns.heatmap(positions_heatmap, cmap=cmap21, cbar=False, square=True, yticklabels=False, xticklabels=False, ax=ax3)
  95. heatmap3.invert_yaxis()
  96. heatmap3.set_title(cmap21.name)
  97. plt.xlabel('')
  98. plt.ylabel('')
  99. # 9. Mark the Market stalls
  100. set_patches(ax1)
  101. set_patches(ax2)
  102. set_patches(ax3)
  103. # 9.1
  104. plt.show()
  105. # 10. Save Heatmap
  106. # heatmap.get_figure().savefig(HEATMAP_PATH, transparent=True)
  107. fig.savefig(HEATMAP_PATH, transparent=True)