Engee 文档
Notebook

矢量世界地图

在这个例子中,我们将展示如何使用世界矢量地图:绘制一条海岸线并在大地坐标系中绘制几个点。

加载和输出矢量图

用于存储矢量大地测量信息的最显着的行业标准之一是Shapefile标准。 包含国家轮廓,道路和河流,机场和港口标记的SHP文件很容易在互联网上找到并下载,包括使用脚本。 在这个例子中,我们将使用从[自然地球]网站获得的地图(https://www.naturalearthdata.com/downloads/110m-physical-vectors /)。

我们需要包裹 ShapefileDownloads (已在Engee供应中提供):

In [ ]:
Pkg.add("Shapefile")

在此示例中,该文件将可用。 如果您需要自动下载任何其他文件,可以使用以下一组命令。

In [ ]:
using Shapefile
using Downloads

# Скачиваем и загружаем данные границ стран (Natural Earth)
function download_world_shapefile()
    shapefile_url = "https://naciscdn.org/naturalearth/110m/physical/ne_110m_coastline.zip"
    zip_path = joinpath(@__DIR__, "countries.zip")
    Downloads.download(shapefile_url, zip_path)
    run(`unzip -o $zip_path -d $(@__DIR__)/countries`)
    shp_path = joinpath(@__DIR__, "countries", "ne_110m_coastline.shp")
    return shp_path
end
Out[0]:
download_world_shapefile (generic function with 1 method)

此代码将带有地图的解压缩存档放在当前项目文件夹中(但不是宏 @__DIR__ 使用临时文件夹也很方便,例如temp_path = mktempdir()).

In [ ]:
# Скачиваем и распаковываем карту
#shp_path = download_world_shapefile()

由于我们并不总是需要再次下载地图,因此我们将编写一个代码,以SHP格式呈现预先下载的地图。

In [ ]:
shp_path = "$(@__DIR__)/countries/ne_110m_coastline.shp"
table = Shapefile.Table(shp_path)
Out[0]:
Shapefile.Table{Union{Missing, Shapefile.Polyline}} with 134 rows and the following 4 columns:
	
geometry, scalerank, featurecla, min_zoom

从整个文件 Shapefile 我们将对一组领域感兴趣 geometry. 命令行或命令有助于探索复杂结构的内容。 dump(объект).

我们上传了一张低分辨率的世界地图,只有海岸。 我们画吧:

In [ ]:
# Создаем карту
plot([-180,180], [-90,-90], fillrange=[90,90], color=:lightblue)

# Нарисуем контур побережья
for shape in table
    x = [point.x for point in shape.geometry.points]
    y = [point.y for point in shape.geometry.points]
    plot!(x, y, color=:white, linewidth=0.5)
end

plot!(legend=false, grid=false, axis=false, framestyle=:none, 
        size=(1200, 600), xlim=(-180, 180), ylim=(-90, 90), aspect_ratio=:equal)
Out[0]:

并添加几个点和一条路线。:

In [ ]:
# Добавляем точки (пример: Лондон, Нью-Йорк, Москва)
cities_lon = [-0.1276, -74.0060, 37.6176]
cities_lat = [51.5072, 40.7128, 55.7558]
city_names = ["Лондон", "Нью Йорк", "Москва"]

scatter!( cities_lon, cities_lat, color=:red, markersize=5, label="Cities")

# Добавляем линию (пример: маршрут)
route_lon = [-0.1276, 37.6176]  # Лондон -> Москва
route_lat = [51.5072, 55.7558]
plot!(route_lon, route_lat, color=:blue, linewidth=2, label="Route")

# Подписываем названия городов
for c in zip(cities_lon, cities_lat, city_names)
    annotate!(c[1], c[2], text(c[3], 8, :bottom))
end

plot!()
Out[0]:

其他投影中的地图输出

为了在另一个投影中显示矢量信息,创建一个将变换坐标并将其应用于每对坐标的对象就足够了。 我们将使用库执行此操作。 Proj 我们将在几个投影中构建地图,还绘制赤道线并在地图上显示兴趣点的位置。

In [ ]:
Pkg.add("Proj")
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
In [ ]:
using Proj

# Определяем проекции
projections = [
    ("Mercator", "+proj=merc +lon_0=0 +lat_ts=0 +x_0=0 +y_0=0"),
    ("Robinson", "+proj=robin +lon_0=0 +x_0=0 +y_0=0"),
    ("Mollweide", "+proj=moll +lon_0=0 +x_0=0 +y_0=0"),
    ("Orthographic (сферическая)", "+proj=ortho +lat_0=30 +lon_0=0"),
    ("Eckert IV (псевдоцилиндрическая)", "+proj=eck4 +lon_0=0"),
    ("Winkel Tripel (компромиссная)", "+proj=wintri +lon_0=0"),
    ("Sinusoidal (равновеликая)", "+proj=sinu +lon_0=0"),
    ("Azimuthal Equidistant (азимутальная)", "+proj=aeqd +lat_0=0 +lon_0=0")
]

# Создаем массив подграфиков
plt = plot(layout=(ceil(Int32, length(projections) / 2),2), size=(800, 1200))

for (i, (name, proj)) in enumerate(projections)
    trans = Proj.Transformation("+proj=longlat", proj)
    
    # Указываем текущий подграфик
    subplot = plt[i]
    
    for shape in table
        x = [point.x for point in shape.geometry.points]
        y = [point.y for point in shape.geometry.points]
        xy_transf = trans.(x, y)
        xx,yy = getindex.(xy_transf, 1), getindex.(xy_transf, 2)
        plot!(subplot, xx, yy, c=1, lw=0.5, fill=:lightblue, title=name, legend=false, grid=false, framestyle=:none)
    end
    
    # Добавляем экватор
    lons = range(-180, 180, length=100)
    lats = zeros(100)
    line_transf = trans.(lons, lats)
    x_line, y_line = getindex.(line_transf, 1), getindex.(line_transf, 2)
    plot!(subplot, x_line, y_line, c=:red, lw=2, label="Equator")

    # Добавляем отметки
    cities_transf = trans.(cities_lon, cities_lat)
    cities_x = getindex.(cities_transf, 1)
    cities_y = getindex.(cities_transf, 2)
    scatter!(subplot, cities_x, cities_y, color=:red, markersize=5, label="Cities")
    for c in zip( cities_x, cities_y, city_names)
        annotate!(subplot, c[1], c[2], text(c[3], 8, :bottom))
    end
    
end

display(plt)

结论

在许多项目(例如,那些专用于导航的项目)中,以这样简单的方式执行的信息输出可能是有用的。 并且掌握了Proj库的语言,可以灵活地变换点的坐标并使用通常的库工具进行输出。 Plots.