简体   繁体   English

如何在 plotly 3D 表面 plot 中标记一个区域?

[英]How to mark an area in plotly 3D surface plot?

I use plotly to create a 3D elevation profile from xyz data which works pretty well with the following code:我使用 plotly 从 xyz 数据创建 3D 高程剖面,该剖面与以下代码配合得很好:

import plotly.graph_objects as go
import pandas as pd
import numpy as np

# Read data
contour_data = pd.read_csv(r"C:\Elevation.xyz", delimiter=' ', names=["x","y","z"])
print(contour_data.head())

# Create 2D grids for X,Y and Z
Z = contour_data.pivot_table(index='x', columns='y', values='z').T.values
X_unique = np.sort(contour_data.x.unique())
Y_unique = np.sort(contour_data.y.unique())
X, Y = np.meshgrid(X_unique, Y_unique)

# Generate 3D plot
fig = go.Figure(data=[go.Surface(z=Z,x=X_unique,y=Y_unique)])
fig.update_layout(title='Elevation', autosize=True, margin=dict(l=65, r=50, b=65, t=90))
fig.update_layout(scene=dict(aspectratio=dict(x=2, y=2, z=0.4)))
fig.show(renderer="browser")

3D 高程图

Now I want to mark an area on this surface as in this example .现在我想在这个表面上标记一个区域,如本例所示 Alternatively just the border of this area would be nice.或者只是这个区域的边界会很好。

Is there a way to mark this area by just providing some x,y coordinates?有没有办法通过提供一些 x,y 坐标来标记这个区域?

Thank you @vestland for suggesting a solution.感谢@vestland 提出解决方案。 Starting from your approach I have implemented a solution that is working with non-rectangle areas by just defining a polygon with x,y coordinates.从您的方法开始,我已经实现了一个解决方案,该解决方案仅通过定义具有 x,y 坐标的多边形来处理非矩形区域。

带有标记多边形区域的高程数据

import matplotlib.pyplot as plt
from matplotlib import rcParams
import plotly.graph_objects as go
import pandas as pd
import numpy as np
from shapely.geometry import Point, Polygon

# Read data
contour_data = pd.read_csv(r"C:\Elevation.xyz", delimiter=' ', names=["x","y","z"])

# Create 2D grids for X,Y and Z
# https://alex.miller.im/posts/contour-plots-in-python-matplotlib-x-y-z/
Z = contour_data.pivot_table(index='x', columns='y', values='z').T
X_unique = np.sort(contour_data.x.unique())
Y_unique = np.sort(contour_data.y.unique())
X, Y = np.meshgrid(X_unique, Y_unique)

# Generate 3D plot
# https://www.geodose.com/2019/09/3d-terrain-modelling-in-python.html
# https://plotly.com/python/3d-surface-plots/ 
fig = go.Figure(data=go.Surface(z=Z,x=X_unique,y=Y_unique))
fig.update_layout(scene = dict(
        xaxis = dict(title='x Longitude',dtick=0.005),
        yaxis = dict(title='y Latitude',dtick=0.005),
        zaxis = dict(title='z Elevation',range=[100, 400])))
fig.update_layout(title='Elevation',autosize=True, margin=dict(l=65, r=50, b=65, t=90))
fig.update_layout(scene=dict(aspectratio=dict(x=2, y=2, z=0.3)))

# Create a Polygon
coords = [(9.185, 51.39), (9.175, 51.39), (9.175, 51.4), (9.2, 51.395)]
poly = Polygon(coords)

marked_area=Z.copy()
i=0
for x in X_unique:
    j=0
    for z in Z.iloc[i]:
        if (Point(x,Y_unique[j]).within(poly)):
            marked_area.iloc[i,j]=z+0.1
        else:
            marked_area.iloc[i,j]=0
        j=j+1
    i=i+1
    
fig.add_trace(go.Surface(z=marked_area,x=X_unique,y=Y_unique,
                         colorscale = ['rgba(0,0,250,1)', 'rgba(0,0,250,1)'],
                         colorbar = None,showlegend=False))

fig.show(renderer="browser")

Since you haven't provided a sample of your data, I'm basing an initial suggestion on the example from Topographical 3D Surface Plot .由于您尚未提供数据样本,因此我根据Topographical 3D Surface Plot中的示例提出初步建议。 This might need some additional tweaking, but you can use fig.add_trace(go.Scatter3D) to highlight a subset of your coordinates like this:这可能需要一些额外的调整,但您可以使用fig.add_trace(go.Scatter3D)来突出显示您的坐标子集,如下所示:

在此处输入图像描述

Let me know how this works out for you and we can take a closer look at the details.让我知道这对你来说是如何工作的,我们可以仔细看看细节。

Complete code:完整代码:

import plotly.graph_objects as go

import pandas as pd

# Read data from a csv
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')

fig = go.Figure(data=[go.Surface(z=z_data.values)])

fig.update_layout(title='Mt Bruno Elevation', autosize=False,
                  width=500, height=500,
                  margin=dict(l=65, r=50, b=65, t=90))
df2 = z_data.iloc[8:15, 7:21]
fig.add_trace(go.Surface(x = df2.columns, y = df2.index, z=df2.values,
                         colorscale = ['rgba(250,0,0,0.8)', 'rgba(250,0,0,0.8)'],
                         colorbar = None))

fig.show()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM