我的目标是获得一个2d阵列(即矩阵)的浮点数,可以将其视为数字高程模型(即等高线图),其中平滑轮廓如下图所示,只要我能够控制每次运行脚本时产生的白山数量和彼此之间的距离。
白色山脉代表CSV文件中包含大于0.9的值的单元格群,如色标所示。在图中,我们看到两个山脉被值小于0.9的区域划分。 这是我的完整代码,其中包含详细注释,其中我使用卷积滤镜来创建这样的图像:
import numpy as np
import pandas as pd
from scipy import signal
import plotly
import plotly.graph_objs as go
def rndmtx():
"""Generate random 2d-array as a digital elevation model."""
nx = 100
ny = 100
dem1 = np.random.rand(nx, ny)
# Save array to csv file befor Gaussian filter.
# Comment the next two lines if reading from the csv file.
dafr = pd.DataFrame(dem1)
dafr.to_csv('G_dem1.csv', header=False, index=False)
# Uncomment the next two lines to read from csv file.
# dafr = pd.read_csv('G_dem1.csv', header=None)
# dem1 = dafr.values
# Apply the first Gaussian filter.
sizex = 5 # The less sizex and sizey the more highlands.
sizey = 5 # The more sizex and sizey the more water.
x, y = np.mgrid[-sizex:sizex+1, -sizey:sizey+1]
scale = 0.33 # The more scale the bigger the difference in elevation.
g = np.exp(-scale*(x**2/sizex+y**2/sizey))
filter1 = g/g.sum() # Normalise the Gaussian function.
dem_smooth = signal.convolve(dem1, filter1, mode='valid')
# Rescale so it lies between 0 and 1.
dem_smooth = ((dem_smooth - dem_smooth.min())
/ (dem_smooth.max() - dem_smooth.min()))
# Apply the second Gaussian filter to make the boundaries smoother.
sizex = 5
sizey = 5
x, y = np.mgrid[-sizex:sizex+1, -sizey:sizey+1]
g = np.exp(-0.33*(x**2/sizex+y**2/sizey))
filter2 = g/g.sum()
dem_smooth1 = signal.convolve(dem_smooth, filter2, mode='valid')
dem_smooth1 = ((dem_smooth1 - dem_smooth1.min())
/ (dem_smooth1.max() - dem_smooth1.min()))
return dem_smooth1
# Get the raw random array of the digital elevation model
# and assign it to the variable.
contour_xy = rndmtx()
# Save the array into CSV file in the working directory.
df = pd.DataFrame(contour_xy)
df.to_csv('last_data.csv', header=False, index=False)
data = [
go.Contour(
z=contour_xy,
colorscale=[
[0, 'rgb(0, 161, 233)'], [0.28, 'rgb(0, 161, 233)'],
[0.28, 'rgb(29, 210, 108)'], [0.50, 'rgb(29, 210, 108)'],
[0.50, 'rgb(141, 232, 130)'], [0.65, 'rgb(141, 232, 130)'],
[0.65, 'rgb(254, 254, 152)'], [0.75, 'rgb(254, 254, 152)'],
[0.75, 'rgb(192, 182, 122)'], [0.82, 'rgb(192, 182, 122)'],
[0.82, 'rgb(142, 110, 92)'], [0.88, 'rgb(142, 110, 92)'],
[0.88, 'rgb(171, 147, 142)'], [0.93, 'rgb(171, 147, 142)'],
[0.93, 'rgb(227, 219, 217)'], [0.97, 'rgb(227, 219, 217)'],
[0.97, 'rgb(255, 255, 255)'], [1, 'rgb(255, 255, 255)']
],
),
]
layout = go.Layout(
yaxis=dict(
autorange='reversed'
)
)
figure = go.Figure(data=data, layout=layout)
plotly.offline.plot(figure, filename='dem.html')
每次运行脚本时,我都会得到一个独特的随机数组。
如何控制要生成的白山的数量和距离?
例如,现在我想在地块上放置10座白山,然后我只想要2座山,依此类推。
目前,我使用的是暴力算法,最终使用所需数量的山脉建立绘图,但我无法设置山脉的特定坐标来控制它们之间的距离。
慷慨解答并指出正确的方向非常受欢迎。喜欢玩代码!
答案 0 :(得分:0)
其中一个笨重的解决方案是在高斯滤波器之前将CSV文件中的某些单元簇填充高于0.9的值,例如全部,如下图所示。
这只是在Excel中打开的CSV文件,具有应用的色阶功能。左边是随机矩阵。在右侧,您可以看到我尝试设置四个相同大小的6x4单元格的山脉,所有单元格都包含值" 1"。 应用卷积滤镜后,我得到以下结果: 这不好,因为我只有两座山和两座棕色高地。另外,还有很多水。我希望尽可能少用水。
如果您能指出其他技巧,我不介意从头开始重写脚本。
<强>更新强>
感谢社区,我终于找到了一个稳定的解决方案: 构建散点图,然后将其转换为轮廓。
请参阅问题Convert Scatter to Contour, every dot turns into a highland