Базовая карта от m (лат, lons) до svg cx и cy - PullRequest
0 голосов
/ 28 июня 2019

Я создаю SVG-изображение мира с базовой картой, на которой я изображаю город Берлин как «контрольную точку» (потому что я хотел бы поместить круг там вручную ... поэтому у меня есть ссылка).

from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt

# Berlin & New York & Sydney
lats = [52.516667] #[52.516667, 40.730610]
lons = [13.388889] # [13.388889, -73.935242]

plt.figure(figsize=(15,15/2))
m = Basemap(projection='robin', lon_0=0, resolution='c')
m.drawcountries(color='#ffffff', linewidth=0.75)
m.fillcontinents(color='#c0c0c0', lake_color='#e6f5ff')                
m.drawmapboundary(fill_color='#e6f5ff', linewidth=1, color='#000000') # Ocean          

x,y = m(lons,lats)

plt.plot(x, y, 'bo', color='r', markersize=5)

plt.savefig("basemap.svg", figsize=(24,12))
plt.show()

На следующем шаге я бы хотел поместить кружок на изображение SVG вручную, отредактировав код созданного файла SVG. Это можно сделать, введя следующий код перед </svg> в конце кода изображения SVG.

<circle fill="blue" cx="250" cy="470" r="2"/>

Как я могу определить правильное значение для cx и cy с моим кодом Python для размещения синей точки там, где находится Берлин?

Я полагал, что у меня есть mapWidth = 1080 и mapHeigth = 540 и xMax = 33973600 и yMax = 17231000.

Таким образом, я мог бы вычислить cx = mapWidth - x/xMax*mapWidth и аналогично cy = mapHeigth - y/yMax*mapHeigth. Тем не менее, это не помещает синюю точку в правильное положение также, если я считаю нижний и левый поля 72 и 152 пункта соответственно. Есть идеи?

1 Ответ

1 голос
/ 03 июля 2019

Поскольку, похоже, вам действительно нужно решение, я дам вам один способ сделать это.

ПРИМЕЧАНИЕ : я не призываю вас манипулировать файлом .svg вручную.Однако, если выбора нет, давайте сделаем это!

Решение предполагает , что процесс, не являющийся питоном, не изменяет файл в форме.

Чтобы преодолетьСоздав файл .svg (по крайней мере, для меня черный ящик), вы можете просто создать другое изображение с графиком ожидаемых координат, сохранить изображение как временный файл .svg, найти точки координат (в файле .svg) и, наконец,добавьте их в исходный файл карты.

Я определяю 3 метода: - createMap, чтобы нарисовать карту и сохранить вывод как .png файл - get_svg_coordinates: создать временную карту (.svg файл), прочитать координаты точки, удалить временный файл, вернуть координаты точки.- add_circle: нарисовать кружок на существующем .svg файле карты.

Здесь код: (рабочий пример)

# Import modules
import os
import re
# os.environ['PROJ_LIB'] = r'C:\Users\...\Library\share'
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt


def createMap(lats, lons, color='r', figure_name="basemap.svg", show=False):
    """ Create a map from points coordinates + export to .csv file
    Arguments
        :param lats: latitudes
        :param lons: longitudes
        :param color='r': color points
        :param figure_name="basemap.svg": name output file
        :param show=False: show the map
    """
    # Same code as yours
    plt.figure(figsize=(15, 15/2))
    m = Basemap(projection='robin', lon_0=0, resolution='c')
    m.drawcountries(color='#ffffff', linewidth=0.75)
    m.fillcontinents(color='#c0c0c0', lake_color='#e6f5ff')
    m.drawmapboundary(fill_color='#e6f5ff', linewidth=1, color='#000000')  # Ocean

    x, y = m(lons, lats)

    plt.plot(x, y, 'bo', color=color, markersize=5)
    plt.savefig(figure_name, figsize=(24, 12))

    if show: plt.show()


def get_svg_coordinates(lat, lon, color='#ff0000', figure_temp_name="tmp_figure.svg"):
    """ Create a temporary file using the createMap function
        Find the point coordinates inside (using regex check)
        Remove temporary csv file
    Arguments
        :param lat: new point latitude
        :param lon: new point  longitude
        :param color='#ff0000': point color
        :param figure_temp_name="tmp_figure.svg": temp file name
    """
    createMap(lat, lon, color=color, figure_name=figure_temp_name)

    with open(figure_temp_name, "r") as f:
        # read file
        content = f.read()  
        # Find x - y values (pattern ' x=' is unique is you are using 1 point)
        x = re.findall(r'<use.*x=\"(\d*\.*\d*)\"', content)
        y = re.findall(r'<use.*y=\"(\d*\.*\d*)\"', content)

    # remove file
    os.remove(figure_temp_name)
    return x, y


def add_circle(map_file_name, x, y):
    """ Draw circle at the end of file
    Arguments:
        :param map_file_name: filename (adding circle)
        :param x: x coordinates (results of get_svg_coordinates method)
        :param y: y coordinates (results of get_svg_coordinates method)
    """
    with open(map_file_name, "r+") as f:
        content = f.readlines()
        # get number of lines in file
        for i, l in enumerate(content):
            pass
        # Add content
        content.insert(i, '<circle fill="blue" cx="{0}" cy="{1}" r="2"/>'.format(x[0], y[0]))
        f.seek(0)                   # file pointer locates at the beginning to write the whole file again
        f.writelines(content)       # rewrite file


# Berlin & New York & Sydney
lats = [52.516667]  # [52.516667, 40.730610]
lons = [13.388889]  # [13.388889, -73.935242]

# create your initial svg map
map_file_name = "basemap.svg"
createMap(lats, lons, figure_name=map_file_name)

# Find new position point on svg file
# Define coordinates points
NewYork_lat = 40.730610
NewYork_long = -73.935242
x, y = get_svg_coordinates(NewYork_lat, NewYork_long)
add_circle(map_file_name, x, y)

Примечание:

  • Я не знаком с файлом .svg.Чтобы ответить на вопрос, я добавляю <circle fill="blue" cx="???" cy="???" r="2"/> в конце файла, как и ожидалось.Однако, может быть, лучше определить весь DOM <g id="line2d_1"> и скопировать его.

  • Фрагмент работает для одного изображения, я позволю вам обобщить для набора точек.

...