I am processing x, y, and z data to have a floor map with high and lows. Z being a displacement sensor. I need to plot a topographical map with gradients. I currently have a 3D scatter plot and a contour plot using matplotlib widgets. Those work great, but a wireframe map or topgraphical map would work best. Either 2D or 3D work as well. Thank you in advance!
Current outputs:
Example of what I am trying to achieve:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import holoviews as hv
from bokeh.models import ColumnDataSource
from mpl_toolkits.mplot3d import Axes3D
from holoviews import opts
hv.extension('bokeh', 'matplotlib')
%matplotlib widget
%matplotlib inline
%matplotlib nbagg
%matplotlib ipympl
plt.style.use('seaborn-white')
#Extend width of Jupyter Notebook
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
#Read CSV
df = pd.read_csv('Floor Scan.csv')
clean_df = df.dropna(axis = 0, how ='any')
print(clean_df)
print('')
z_offset = (clean_df['Displacement (in)'].min())
z_offset_abs = abs(z_offset)
print("Minimum Z:" str(z_offset))
#3D SCATTER
fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(111, projection='3d')
x = clean_df['fActualPosition_X (-)']
y = clean_df['fActualPosition_Y (-)']
z = clean_df['Displacement (in)']
ax.scatter(x, y, (z z_offset_abs), c='b', marker='^')
plt.xlabel("fActualPosition_X (-)")
plt.ylabel("fActualPosition_Y (-)")
plt.show()
plt.savefig('Floor_Map_Scatter_3D.svg')
#3D CONTOUR
fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(111, projection='3d')
X = clean_df['fActualPosition_X (-)'].astype(np.uint8)
Y = clean_df['fActualPosition_Y (-)'].astype(np.uint8)
Z = clean_df['Displacement (in)'].astype(np.uint8)
flatX = np.asarray(clean_df['fActualPosition_X (-)'])
flatY = np.asarray(clean_df['fActualPosition_Y (-)'])
flatZ = np.asarray(clean_df['Displacement (in)'])
# flatX, flatY = np.meshgrid(X, Y)
# flatZ = function(flatX, flatY, Z)
# print(flatX)
# print('')
# print(flatY)
# print('')
# print(flatZ)
# print('')
plt.tricontourf(flatX, flatY, (flatZ z_offset_abs),20)
plt.show();
plt.savefig('Floor_Map_Contour_3D.svg')
CodePudding user response:
It sounds like your original data is in the form of isolated points (from a range-measuring device like LIDAR?), and what you want is not simply to plot those points, but first to infer or interpolate a surface from those points and then plot that surface. The two desired examples both take an already calculated grid of values and plot them either as a surface or as an image, so first you need to make such a grid, which is not strictly a plotting problem but one of data processing.
One typical way of creating the grid is to aggregate the values into Cartesian coordinates, basically just counting the average value of the scatter points per grid cell. Another is to connect up all the points into a triangular mesh, which may or may not actually form a surface (a function mapping from x,y -> z).
You can use our library Datashader to aggregate just about any set of data into a regular grid, and can then display it as images or contours using hvPlot (https://hvplot.holoviz.org/user_guide/Gridded_Data.html) or as a surface or wireframe using HoloViews (http://holoviews.org/reference/elements/plotly/Surface.html#elements-plotly-gallery-surface).
If you want an unstructured grid, you can use scipy.spatial to compute a triangulation, then HoloViews to visualize it (http://holoviews.org/reference/elements/bokeh/TriMesh.html#elements-bokeh-gallery-trimesh).
