gpt4 book ai didi

cartopy - 对沿着两点之间的路径移动的点进行动画处理

转载 作者:行者123 更新时间:2023-12-02 10:46:18 31 4
gpt4 key购买 nike

我想要制作一个点的动画,该点沿着 map 上的一个位置到另一个位置的路径移动。

例如,我使用大地测量变换绘制了从纽约到新德里的路径。例如。取自文档 Adding data to the map

plt.plot([ny_lon, delhi_lon], [ny_lat, delhi_lat],
color='blue', linewidth=2, marker='o',
transform=ccrs.Geodetic(),
)

现在我想沿着这条路径移动一个点。

我的想法是以某种方式沿着路径获取一些(比如 50 个)点,并在每帧的每个点上绘制一个标记。但我无法找到一种方法来获得路径上的点。

我发现了一个函数transform_points在类CRS下,但我无法使用它,因为这给了我相同数量的点,而不是之间的点。

提前致谢!

最佳答案

有几种方法可以实现这一点。

matplotlib 方法

如果您熟悉 matplotlib,我将从最基本的开始,但这种方法会间接使用 cartopy 的功能,因此更难配置/扩展。

Line2D 对象(从 plt.plot 返回的东西)上有一个私有(private)的 _get_transformed_pa​​th 方法。生成的 TransformedPath 对象有一个 get_transformed_pa​​th_and_affine 方法,该方法基本上将为我们提供投影线(在正在绘制的轴的坐标系中)。

In [1]: import cartopy.crs as ccrs

In [3]: import matplotlib.pyplot as plt

In [4]: ax = plt.axes(projection=ccrs.Robinson())

In [6]: ny_lon, ny_lat = -75, 43

In [7]: delhi_lon, delhi_lat = 77.23, 28.61

In [8]: [line] = plt.plot([ny_lon, delhi_lon], [ny_lat, delhi_lat],
...: color='blue', linewidth=2, marker='o',
...: transform=ccrs.Geodetic(),
...: )

In [9]: t_path = line._get_transformed_path()

In [10]: path_in_data_coords, _ = t_path.get_transformed_path_and_affine()

In [11]: path_in_data_coords.vertices
Out[11]:
array([[-6425061.82215208, 4594257.92617961],
[-5808923.84969279, 5250795.00604155],
[-5206753.88613758, 5777772.51828996],
[-4554622.94040482, 6244967.03723341],
[-3887558.58343227, 6627927.97123701],
[-3200922.19194864, 6932398.19937816],
[-2480001.76507805, 7165675.95095855],
[-1702269.5101901 , 7332885.72276795],
[ -859899.12295981, 7431215.78426759],
[ 23837.23431173, 7453455.61302756],
[ 889905.10635756, 7397128.77301289],
[ 1695586.66856764, 7268519.87627204],
[ 2434052.81300274, 7073912.54130764],
[ 3122221.22299409, 6812894.40443648],
[ 3782033.80448001, 6478364.28561403],
[ 4425266.18173684, 6062312.15662039],
[ 5049148.25986903, 5563097.6328901 ],
[ 5616318.74912886, 5008293.21452795],
[ 6213232.98764984, 4307186.23400115],
[ 6720608.93929235, 3584542.06839575],
[ 7034261.06659143, 3059873.62740856]])

我们可以将其与 matplotlib 的动画功能结合起来,按照要求进行操作:

import cartopy.crs as ccrs
import matplotlib.animation as animation
import matplotlib.pyplot as plt

ax = plt.axes(projection=ccrs.Robinson())
ax.stock_img()

ny_lon, ny_lat = -75, 43
delhi_lon, delhi_lat = 77.23, 28.61

[line] = plt.plot([ny_lon, delhi_lon], [ny_lat, delhi_lat],
color='blue', linewidth=2, marker='o',
transform=ccrs.Geodetic(),
)

t_path = line._get_transformed_path()
path_in_data_coords, _ = t_path.get_transformed_path_and_affine()


# Draw the point that we want to animate.
[point] = plt.plot(ny_lon, ny_lat, marker='o', transform=ax.projection)

def animate_point(i):
verts = path_in_data_coords.vertices
i = i % verts.shape[0]
# Set the coordinates of the line to the coordinate of the path.
point.set_data(verts[i, 0], verts[i, 1])

ani = animation.FuncAnimation(
ax.figure, animate_point,
frames= path_in_data_coords.vertices.shape[0],
interval=125, repeat=True)

ani.save('point_ani.gif', writer='imagemagick')
plt.show()

The matplotlib way

cartopy 方法

在底层,cartopy 的 matplotlib 实现(如上面使用的)正在调用 project_geometry方法。我们也可以直接使用它,因为使用 Shapely 几何图形通常比使用 matplotlib 路径更方便。

通过这种方法,我们只需定义一个形状良好的几何图形,然后构建我们想要将几何图形转换为的源和目标坐标引用系统:

target_cs.project_geometry(geometry, source_cs)

我们唯一需要注意的是结果可以是 MultiLineString(或者更一般地说,任何 Multi-geometry 类型)。但是,在我们的简单情况下,我们不需要处理这个问题(顺便说一句,第一个示例中返回的简单 Path 也是如此)。

生成与上面类似的图的代码:

import cartopy.crs as ccrs
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
import shapely.geometry as sgeom


ax = plt.axes(projection=ccrs.Robinson())
ax.stock_img()

ny_lon, ny_lat = -75, 43
delhi_lon, delhi_lat = 77.23, 28.61


line = sgeom.LineString([[ny_lon, ny_lat], [delhi_lon, delhi_lat]])

projected_line = ccrs.PlateCarree().project_geometry(line, ccrs.Geodetic())

# We only animate along one of the projected lines.
if isinstance(projected_line, sgeom.MultiLineString):
projected_line = projected_line.geoms[0]

ax.add_geometries(
[projected_line], ccrs.PlateCarree(),
edgecolor='blue', facecolor='none')

[point] = plt.plot(ny_lon, ny_lat, marker='o', transform=ccrs.PlateCarree())


def animate_point(i):
verts = np.array(projected_line.coords)
i = i % verts.shape[0]
# Set the coordinates of the line to the coordinate of the path.
point.set_data(verts[i, 0], verts[i, 1])

ani = animation.FuncAnimation(
ax.figure, animate_point,
frames=len(projected_line.coords),
interval=125, repeat=True)

ani.save('projected_line_ani.gif', writer='imagemagick')
plt.show()

The cartopy way

最后的结果....

该方法自然地推广到对任何类型的 matplotlib Arrrrtist 进行动画处理......在本例中,我对大圆分辨率进行了更多控制,并沿大圆对图像进行了动画处理:

import cartopy.crs as ccrs
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
import shapely.geometry as sgeom


ax = plt.axes(projection=ccrs.Mercator())
ax.stock_img()

line = sgeom.LineString([[-5.9845, 37.3891], [-82.3666, 23.1136]])


# Higher resolution version of Mercator. Same workaround as found in
# https://github.com/SciTools/cartopy/issues/8#issuecomment-326987465.
class HighRes(ax.projection.__class__):
@property
def threshold(self):
return super(HighRes, self).threshold / 100


projected_line = HighRes().project_geometry(line, ccrs.Geodetic())

# We only animate along one of the projected lines.
if isinstance(projected_line, sgeom.MultiLineString):
projected_line = projected_line.geoms[0]

# Add the projected line to the map.
ax.add_geometries(
[projected_line], ax.projection,
edgecolor='blue', facecolor='none')


def ll_to_extent(x, y, ax_size=(4000000, 4000000)):
"""
Return an image extent in centered on the given
point with the given width and height.

"""
return [x - ax_size[0] / 2, x + ax_size[0] / 2,
y - ax_size[1] / 2, y + ax_size[1] / 2]


# Image from https://pixabay.com/en/sailing-ship-boat-sail-pirate-28930/.
pirate = plt.imread('pirates.png')
img = ax.imshow(pirate, extent=ll_to_extent(0, 0), transform=ax.projection, origin='upper')

ax.set_global()


def animate_ship(i):
verts = np.array(projected_line.coords)
i = i % verts.shape[0]

# Set the extent of the image to the coordinate of the path.
img.set_extent(ll_to_extent(verts[i, 0], verts[i, 1]))


ani = animation.FuncAnimation(
ax.figure, animate_ship,
frames=len(projected_line.coords),
interval=125, repeat=False)

ani.save('arrrr.gif', writer='imagemagick')
plt.show()

Arrrr, here be pirates!

此答案的所有代码和图像都可以在 https://gist.github.com/pelson/618a5f4ca003e56f06d43815b21848f6 找到.

关于cartopy - 对沿着两点之间的路径移动的点进行动画处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51482082/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com