123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- import UnityEngine as ue
- import numpy as np
- import seaborn as sns
- import matplotlib.pyplot as plt
- import matplotlib.patches as patches
- from matplotlib.colors import LinearSegmentedColormap
- import pandas as pd
- WIDTH = int(70)
- HEIGHT = int(35)
- OBSTACLE_PATH = "Assets/Data_image/obstacle.pkl"
- POSITION_PATH = ue.Application.dataPath + "/Data_position/80/Walk4.csv"
- HEATMAP_PATH = "Assets/Data_image/80/heatmap4.png"
- # Generate only if obstacles change
- def set_obstacles(maximum):
- """
- set_obstacles creates a DataFrame which marks the positions of the obstacles.
- The obstacles are marked with the negative maximum and the file is placed at the path.
- The negative maximum is used so that the cmap can assign the correct colors to the values.
- Since no other negative numbers exist and the next highest number is 0, the negative values are painted 'grey'
- and the other [0-maximum] are painted according to the color gradient between the two specified colors.
-
- :param maximum: Is the maximum to the associated positions file
- """
- global list_obstacle_length
- positions = pd.DataFrame(np.zeros((HEIGHT, WIDTH)))
- obstacles = ue.Object.FindObjectsOfType(ue.GameObject)
- for obstacle in obstacles:
- if(obstacle.layer == 15 or obstacle.layer == 12):
- startWidth = int(obstacle.transform.position.x - obstacle.transform.localScale.x / 2)
- endWidth = int(obstacle.transform.position.x + obstacle.transform.localScale.x / 2)
- startHeight = int(obstacle.transform.position.z - obstacle.transform.localScale.z / 2)
- endHeight = int(obstacle.transform.position.z + obstacle.transform.localScale.z / 2)
- for currentW in range(startWidth, endWidth, 1):
- for currentH in range(startHeight, endHeight, 1):
- positions[currentW][currentH] = -maximum
- positions.to_pickle(OBSTACLE_PATH)
- def set_patches(plt):
- """
- set_patches uses the positions of the obstacles to draw a black border around them.
-
- :param plt: The plot, where the figure is placed, so it can be modified by this function
- """
- obstacles = ue.Object.FindObjectsOfType(ue.GameObject)
- for obstacle in obstacles:
- if(obstacle.layer == 15):
- startWidth = int(obstacle.transform.position.x - obstacle.transform.localScale.x / 2)
- endWidth = int(obstacle.transform.position.x + obstacle.transform.localScale.x / 2)
- startHeight = int(obstacle.transform.position.z - obstacle.transform.localScale.z / 2)
- endHeight = int(obstacle.transform.position.z + obstacle.transform.localScale.z / 2)
- # plt.gca().add_patch(
- plt.add_patch(
- patches.Rectangle(
- (startWidth, startHeight),
- endWidth - startWidth,
- endHeight - startHeight,
- fill=False,
- color='black'
- )
- )
- # 1. Get position data from csv file
- data = pd.read_csv(POSITION_PATH, sep=';', usecols=["Position x", "Position z"], decimal=',', dtype={'Position x': float, 'Position z': float})
- data = data.round(0)
- # 2. Group by positions and count appearance
- data_count = data.groupby(['Position x', 'Position z']).size().reset_index(name='counts')
- # 3. Create wide-form DataFrame for generating heatmap
- positions = data_count.loc[:,:].reset_index().pivot(index='Position z', columns='Position x', values='counts')
- # 4. Fill missing values
- positions.fillna(0, inplace=True)
- # 5. Reindex DataFrame (70,35) size of Surface; (70, 35) first x width then z height
- positions = positions.reindex_axis(range(0, HEIGHT), axis=0, fill_value=0)
- positions = positions.reindex_axis(range(0, WIDTH), axis=1, fill_value=0)
- # 6.1 Get maximum value of positions data
- max1 = pd.DataFrame(positions).max().max() # Gets the maximum of each column and than the maximum of the maximums
- # 6. Get obstacles (obstacles, market stalls) and paste specific value in positions
- # Therefore save pkl file in folder and read from it afterwards
- set_obstacles(max1)
- positions_heatmap = pd.read_pickle(OBSTACLE_PATH)
- # 6.1 Merge positions data with obstacles data
- positions_heatmap.where(positions_heatmap != 0, positions, inplace=True)
- # 6.2 Debug Output
- # positions_heatmap = pd.DataFrame(positions_heatmap)
- # positions_heatmap.to_html('Assets/Data_image/positions_heatmap.html')
- # 7. Plot the heatmap
- fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
- ax4.remove()
- # cmap = LinearSegmentedColormap.from_list(name='greenToRed', colors=['grey', 'limegreen', 'chartreuse', 'yellow', 'darkorange', 'red'])
- cmap19 = LinearSegmentedColormap.from_list(name='2019', colors=['grey', (0.40,0.76,0.65), (0.11,0.62,0.47)])
- cmap20 = LinearSegmentedColormap.from_list(name='2020', colors=['grey', (0.99,0.55,0.38), (0.85,0.37,0.01)])
- cmap21 = LinearSegmentedColormap.from_list(name='2021', colors=['grey', (0.55,0.63,0.80), (0.46,0.44,0.70)])
- heatmap = sns.heatmap(positions_heatmap, cmap=cmap19, cbar=False, square=True, yticklabels=False, xticklabels=False, ax=ax1)
- heatmap.invert_yaxis()
- heatmap.set_title(cmap19.name)
- heatmap2 = sns.heatmap(positions_heatmap, cmap=cmap20, cbar=False, square=True, yticklabels=False, xticklabels=False, ax=ax2)
- heatmap2.invert_yaxis()
- heatmap2.set_title(cmap20.name)
- heatmap3 = sns.heatmap(positions_heatmap, cmap=cmap21, cbar=False, square=True, yticklabels=False, xticklabels=False, ax=ax3)
- heatmap3.invert_yaxis()
- heatmap3.set_title(cmap21.name)
- plt.xlabel('')
- plt.ylabel('')
- # 9. Mark the Market stalls
- set_patches(ax1)
- set_patches(ax2)
- set_patches(ax3)
- # 9.1
- plt.show()
- # 10. Save Heatmap
- # heatmap.get_figure().savefig(HEATMAP_PATH, transparent=True)
- fig.savefig(HEATMAP_PATH, transparent=True)
|