Browse Source

Added 3D Heatmap Visualization

Furkan Karakocaoglu 1 year ago
parent
commit
10ddca9497

BIN
testumgebung/CrowdModelling/Assets/Data_image/80/heatmap3D4.png


+ 92 - 0
testumgebung/CrowdModelling/Assets/Data_image/80/heatmap3D4.png.meta

@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 13408ba31dc3df54d8d9d1f5d146896b
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 11
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 0
+    wrapV: 0
+    wrapW: 0
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 0
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  singleChannelComponent: 0
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  applyGammaDecoding: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
testumgebung/CrowdModelling/Assets/Data_image/80/heatmap3DMultiple1.png


+ 92 - 0
testumgebung/CrowdModelling/Assets/Data_image/80/heatmap3DMultiple1.png.meta

@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: dd74aa3b9098e99488e0a92c698b2b5b
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 11
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 0
+    wrapV: 0
+    wrapW: 0
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 0
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  singleChannelComponent: 0
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  applyGammaDecoding: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
testumgebung/CrowdModelling/Assets/Data_image/80/heatmap3DMultiple4.png


+ 92 - 0
testumgebung/CrowdModelling/Assets/Data_image/80/heatmap3DMultiple4.png.meta

@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: ad7f04abe2a4eee41bb8d9f14193f6ac
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 11
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 0
+    wrapV: 0
+    wrapW: 0
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 0
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  singleChannelComponent: 0
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  applyGammaDecoding: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 43 - 104
testumgebung/CrowdModelling/Assets/Depictions_Years/Scripts/Python/Heatmap_3D.py

@@ -1,65 +1,23 @@
 import UnityEngine as ue
+import pandas as pd
 import numpy as np
-import seaborn as sns
 import matplotlib.pyplot as plt
-import matplotlib.patches as patches
+import matplotlib.cm as cm
+# import seaborn as sns
+# import matplotlib.patches as patches
+# import matplotlib.colors as colors
+# from sklearn import preprocessing
+# from pylab import *
+# from matplotlib import style
 from matplotlib.colors import LinearSegmentedColormap 
-import pandas as pd
+from mpl_toolkits.mplot3d import Axes3D
+
 
 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'
-                )
-            )
+HEATMAP_PATH = "Assets/Data_image/80/heatmap3D4.png"
 
 # 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})
@@ -68,58 +26,39 @@ 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 
+# 3. Assign x, y, z, width, depth, height
+x = data_count["Position x"].tolist()
+y = data_count["Position z"].tolist()
+z = np.zeros_like(len(x))
+dz = data_count["counts"].tolist() # Change
+
+# 4. Create figure and axes
+fig = plt.figure()
+ax = fig.add_subplot(111, projection='3d')
+
+# 5.1 Create custom colormap Day1, Day2, Day3
+cmap = LinearSegmentedColormap.from_list(name='day1', colors=[(0.40,0.76,0.65), (0.11,0.62,0.47)])
+# cmap = LinearSegmentedColormap.from_list(name='day2', colors=['grey', (0.99,0.55,0.38), (0.85,0.37,0.01)])
+# cmap = LinearSegmentedColormap.from_list(name='day3', colors=['grey', (0.55,0.63,0.80), (0.46,0.44,0.70)])
+
+# 5.2 Initialize array for coloring the bars
+dz_array = np.array(data_count['counts'])
+fracs = dz_array.astype(float) / dz_array.max()
+color_values = cmap(fracs.tolist())
+
+# 6. Create the bars
+# for i in range(len(x)):
+#     img = ax.bar3d(x[i], y[i], z, 1, 1, dz[i], color=color_values[i], shade=False)
+img = ax.bar3d(x, y, z, 1, 1, dz, color=color_values, shade=False)
+
+# 7. Create Colorbar
+color_map = cm.ScalarMappable(cmap=cmap)
+color_map.set_array(dz)
+fig.colorbar(color_map)
+
+# 8. 
 plt.show()
 
-# 10. Save Heatmap
+# 10. Save 3D Heatmap
 # heatmap.get_figure().savefig(HEATMAP_PATH, transparent=True)
 fig.savefig(HEATMAP_PATH, transparent=True)

+ 103 - 0
testumgebung/CrowdModelling/Assets/Depictions_Years/Scripts/Python/Heatmap_3D_Multiple.py

@@ -0,0 +1,103 @@
+import UnityEngine as ue
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.cm as cm
+# import seaborn as sns
+# import matplotlib.patches as patches
+# import matplotlib.colors as colors
+# from sklearn import preprocessing
+# from pylab import *
+# from matplotlib import style
+from matplotlib.colors import LinearSegmentedColormap 
+from mpl_toolkits.mplot3d import Axes3D
+
+
+WIDTH = int(70)
+HEIGHT = int(35)
+OBSTACLE_PATH = "Assets/Data_image/obstacle.pkl"
+POSITION_PATH1 = ue.Application.dataPath + '/Data_position/80/Walk1.csv'
+POSITION_PATH2 = ue.Application.dataPath + '/Data_position/80/Walk2.csv'
+POSITION_PATH3 = ue.Application.dataPath + '/Data_position/80/Walk4.csv'
+HEATMAP_PATH = "Assets/Data_image/80/heatmap3DMultiple1.png"
+
+# 1. Get position data from csv file
+data1 = pd.read_csv(POSITION_PATH1, sep=';', usecols=["Position x", "Position z"], decimal=',', dtype={'Position x': float, 'Position z': float})
+data1 = data1.round(0)
+data2 = pd.read_csv(POSITION_PATH2, sep=';', usecols=["Position x", "Position z"], decimal=',', dtype={'Position x': float, 'Position z': float})
+data2 = data2.round(0)
+data3 = pd.read_csv(POSITION_PATH3, sep=';', usecols=["Position x", "Position z"], decimal=',', dtype={'Position x': float, 'Position z': float})
+data3 = data3.round(0)
+
+# 2. Group by positions and count appearance
+data_count1 = data1.groupby(['Position x', 'Position z']).size().reset_index(name='counts')
+data_count2 = data2.groupby(['Position x', 'Position z']).size().reset_index(name='counts')
+data_count3 = data3.groupby(['Position x', 'Position z']).size().reset_index(name='counts')
+
+# 3.1 Assign x, y, z, width, depth, height
+x1 = data_count1["Position x"].tolist()
+y1 = data_count1["Position z"].tolist()
+z1 = np.zeros_like(len(x1))
+dz1 = data_count1["counts"].tolist() # Change
+
+x2 = data_count2["Position x"].tolist()
+y2 = data_count2["Position z"].tolist()
+z2 = np.zeros_like(len(x2))
+dz2 = data_count2["counts"].tolist() # Change
+
+x3 = data_count3["Position x"].tolist()
+y3 = data_count3["Position z"].tolist()
+z3 = np.zeros_like(len(x3))
+dz3 = data_count3["counts"].tolist() # Change
+
+# 3.2 Add offset to day2 and day3
+x2[:] = [a+0.5 for a in x2[:]]
+x3[:] = [a+0.5 for a in x3[:]]
+y3[:] = [a+0.5 for a in y3[:]]
+
+# 4. Create figure and axes
+fig = plt.figure(figsize=(10,10))
+ax = fig.add_subplot(111, projection='3d')
+
+# 5.1 Create custom colormap Day1, Day2, Day3
+cmap1 = LinearSegmentedColormap.from_list(name='day1', colors=[(0.40,0.76,0.65), (0.11,0.62,0.47)])
+cmap2 = LinearSegmentedColormap.from_list(name='day2', colors=[(0.99,0.55,0.38), (0.85,0.37,0.01)])
+cmap3 = LinearSegmentedColormap.from_list(name='day3', colors=[(0.55,0.63,0.80), (0.46,0.44,0.70)])
+
+# 5.2 Initialize array for coloring the bars
+dz_array1 = np.array(data_count1['counts'])
+fracs1 = dz_array1.astype(float) / dz_array1.max()
+color_values1 = cmap1(fracs1.tolist())
+
+dz_array2 = np.array(data_count2['counts'])
+fracs2 = dz_array2.astype(float) / dz_array2.max()
+color_values2 = cmap2(fracs2.tolist())
+
+dz_array3 = np.array(data_count3['counts'])
+fracs3 = dz_array3.astype(float) / dz_array3.max()
+color_values3 = cmap3(fracs3.tolist())
+
+# 6. Create the bars
+img = ax.bar3d(x1, y1, z1, 0.5, 0.5, dz1, color=color_values1, shade=False)
+img = ax.bar3d(x2, y2, z2, 0.5, 0.5, dz2, color=color_values2, shade=False)
+img = ax.bar3d(x3, y3, z3, 0.5, 0.5, dz3, color=color_values3, shade=False)
+
+# 7. Create Colorbar
+# color_map1 = cm.ScalarMappable(cmap=cmap1)
+# color_map1.set_array(dz1)
+# fig.colorbar(color_map1)
+
+# color_map2 = cm.ScalarMappable(cmap=cmap2)
+# color_map2.set_array(dz2)
+# fig.colorbar(color_map2)
+
+# color_map3 = cm.ScalarMappable(cmap=cmap3)
+# color_map3.set_array(dz3)
+# fig.colorbar(color_map3)
+
+# 8. 
+plt.show()
+
+# 10. Save 3D Heatmap
+# heatmap.get_figure().savefig(HEATMAP_PATH, transparent=True)
+fig.savefig(HEATMAP_PATH, transparent=True)

+ 7 - 0
testumgebung/CrowdModelling/Assets/Depictions_Years/Scripts/Python/Heatmap_3D_Multiple.py.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: b2a1b49abf7e4274c806b8216b7a9f39
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 7 - 0
testumgebung/CrowdModelling/Assets/Depictions_Years/Scripts/Python/PythonManager.cs

@@ -17,4 +17,11 @@ public class PythonManager
         string scriptPath = Application.dataPath + @"/Depictions_Years/Scripts/Python/Heatmap_Multiple.py";
         PythonRunner.RunFile(scriptPath);
     }
+    
+    [MenuItem("Python/Create 3D Heatmap")]
+    static void RunPythonFile3D()
+    {
+        string scriptPath = Application.dataPath + @"/Depictions_Years/Scripts/Python/Heatmap_3D.py";
+        PythonRunner.RunFile(scriptPath);
+    }
 }