Как я могу наложить свой контурный график на базовую карту

Это вопрос, который я задал несколько месяцев назад, и до сих пор не могу найти решение. Мой код дает мне базовую карту и контурный график рядом (но печать в файл дает только контурный график), но я хочу, чтобы они были наложены друг на друга. Лучшим решением было бы здесь https://gist.github.com/oblakeobjet/7546272, но это не показывает, как вводить данные, и это сложно, когда вы учитесь с нуля в Интернете. Не утомляя очень добрых людей, я надеюсь, что решение будет простым, как изменение строки кода, и что кто-то может помочь. Мой код

#!/usr/bin/python
# vim: set fileencoding=UTF8

import numpy as np
import pandas as pd
from matplotlib.mlab import griddata
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt

#fig = plt.figure(figsize=(10,8))  #when uncommented draws map with colorbar but no contours

#prepare a basemap

m = Basemap(projection = 'merc',llcrnrlon = 21, llcrnrlat = -18, urcrnrlon = 34, urcrnrlat = -8, resolution='h')

# draw country outlines.

m.drawcountries(linewidth=0.5, linestyle='solid', color='k', antialiased=1, ax=None, zorder=None)
m.drawmapboundary(fill_color = 'white')
m.fillcontinents(color='coral',lake_color='blue')
parallels = np.arange(-18, -8, 2.)
m.drawparallels(np.arange(-18, -8, 2.), color = 'black', linewidth = 0.5)
m.drawparallels(parallels,labels=[True,False,False,False])
meridians = np.arange(22,34, 2.)
m.drawmeridians(np.arange(21,36, 2.), color = '0.25', linewidth = 0.5)
m.drawmeridians(meridians,labels=[False,False,False,True])

fig = plt.figure(figsize=(10,8))       # At this position or commented draws teo figures side by side

#-- Read the data.

data = pd.read_csv('../../data/meansr.txt', delim_whitespace=True)

#-- Now gridding data.  First making a regular grid to interpolate onto

numcols, numrows = 300, 300
xi = np.linspace(data.Lon.min(), data.Lon.max(), numcols)
yi = np.linspace(data.Lat.min(), data.Lat.max(), numrows)
xi, yi = np.meshgrid(xi, yi)

#-- Interpolating at the points in xi, yi

x, y, z = data.Lon.values, data.Lat.values, data.Z.values
zi = griddata(x, y, z, xi, yi)

#-- Display and write the results

m = plt.contourf(xi, yi, zi)
plt.scatter(data.Lon, data.Lat, c=data.Z, s=100,
       vmin=zi.min(), vmax=zi.max())
fig.colorbar(m)
plt.savefig("rainfall.jpg", format="jpg")

Графики, которые я получаю, выглядят так: contour plotи базовая карта

и мои данные

32.6  -13.6   41
27.1  -16.9   43
32.7  -10.2   46
24.2  -13.6   33
28.5  -14.4   43
28.1  -12.6   33
27.9  -15.8   46
24.8  -14.8   44
31.1  -10.2   35
25.9  -13.5   24
29.1   -9.8   10
25.8  -17.8   39
33.2  -12.3   44
28.3  -15.4   46
27.6  -16.1   47
28.9  -11.1   31
31.3   -8.9   39
31.9  -13.3   45
23.1  -15.3   31
31.4  -11.9   39
27.1  -15.0   42
24.4  -11.8   15
28.6  -13.0   39
31.3  -14.3   44
23.3  -16.1   39
30.2  -13.2   38
24.3  -17.5   32
26.4  -12.2   23
23.1  -13.5   27

person Zilore Mumba    schedule 11.11.2014    source источник
comment
По-видимому, вы получаете две фигуры, потому что m - это контекст, из которого вы вызываете каждую команду рисования карты, и после этого вы рисуете текущую активную фигуру, используя команды построения на основе plt.   -  person heltonbiker    schedule 11.11.2014
comment
Почему тег R? Вы, кажется, довольно хорошо разбираетесь в Python.   -  person Gregor Thomas    schedule 11.11.2014
comment
Можете ли вы поделиться файлом meanr.txt для запуска вашего кода?   -  person Andre Araujo    schedule 05.01.2019


Ответы (2)


Вы почти закончили, но Basemap может быть темпераментным, и вам нужно управлять z-порядком графиков/деталей карты. Кроме того, вы должны преобразовать координаты долготы и широты в координаты картографической проекции, прежде чем строить их с помощью базовой карты.

Вот полное решение, которое дает следующий результат. Я изменил некоторые цвета и толщину линий, чтобы сделать текст более разборчивым, YMMV. Я также масштабировал размер точек разброса по нормализованному «среднему» значению (data['Z']) — вы можете просто удалить его и заменить, например. 50, если вы предпочитаете постоянный размер (он будет выглядеть как самый большой маркер).

Пожалуйста, укажите также единицы количества осадков и продолжительность измерения, в результате которого были получены средние значения, если это возможно:

Интерполированные данные об осадках, точки разброса масштабированы по значению

import numpy as np
import pandas as pd
from matplotlib.mlab import griddata
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
%matplotlib inline

# set up plot
plt.clf()
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, axisbg='w', frame_on=False)

# grab data
data = pd.read_csv('../../data/meansr.txt', delim_whitespace=True)
norm = Normalize()

# define map extent
lllon = 21
lllat = -18
urlon = 34
urlat = -8

# Set up Basemap instance
m = Basemap(
    projection = 'merc',
    llcrnrlon = lllon, llcrnrlat = lllat, urcrnrlon = urlon, urcrnrlat = urlat,
    resolution='h')

# transform lon / lat coordinates to map projection
data['projected_lon'], data['projected_lat'] = m(*(data.Lon.values, data.Lat.values))

# grid data
numcols, numrows = 1000, 1000
xi = np.linspace(data['projected_lon'].min(), data['projected_lon'].max(), numcols)
yi = np.linspace(data['projected_lat'].min(), data['projected_lat'].max(), numrows)
xi, yi = np.meshgrid(xi, yi)

# interpolate
x, y, z = data['projected_lon'].values, data['projected_lat'].values, data.Z.values
zi = griddata(x, y, z, xi, yi)

# draw map details
m.drawmapboundary(fill_color = 'white')
m.fillcontinents(color='#C0C0C0', lake_color='#7093DB')
m.drawcountries(
    linewidth=.75, linestyle='solid', color='#000073',
    antialiased=True,
    ax=ax, zorder=3)

m.drawparallels(
    np.arange(lllat, urlat, 2.),
    color = 'black', linewidth = 0.5,
    labels=[True, False, False, False])
m.drawmeridians(
    np.arange(lllon, urlon, 2.),
    color = '0.25', linewidth = 0.5,
    labels=[False, False, False, True])

# contour plot
con = m.contourf(xi, yi, zi, zorder=4, alpha=0.6, cmap='RdPu')
# scatter plot
m.scatter(
    data['projected_lon'],
    data['projected_lat'],
    color='#545454',
    edgecolor='#ffffff',
    alpha=.75,
    s=50 * norm(data['Z']),
    cmap='RdPu',
    ax=ax,
    vmin=zi.min(), vmax=zi.max(), zorder=4)

# add colour bar and title
# add colour bar, title, and scale
cbar = plt.colorbar(conf, orientation='horizontal', fraction=.057, pad=0.05)
cbar.set_label("Mean Rainfall - mm")

m.drawmapscale(
    24., -9., 28., -13,
    100,
    units='km', fontsize=10,
    yoffset=None,
    barstyle='fancy', labelstyle='simple',
    fillcolor1='w', fillcolor2='#000000',
    fontcolor='#000000',
    zorder=5)

plt.title("Mean Rainfall")
plt.savefig("rainfall.png", format="png", dpi=300, transparent=True)
plt.show()

Использование метода griddata из matplotlib удобно, но также может быть медленным. В качестве альтернативы вы можете использовать griddata scipy. методы, которые быстрее и гибче:

from scipy.interpolate import griddata as gd

zi = gd(
    (data[['projected_lon', 'projected_lat']]),
    data.Z.values,
    (xi, yi),
    method='linear')

Если вы используете метод griddata scipy, вам также нужно будет определить, какой из методов (nearest, linear, cubic) дает наилучший результирующий график.

Я должен добавить, что методы интерполяции, продемонстрированные и обсужденные выше, являются самыми простыми из возможных и не обязательно применимы для интерполяции данных об осадках. Эта статья дает хороший обзор допустимых подходов и соображений для использования в гидрологии и гидрологическом моделировании. Реализация их (вероятно, с использованием Scipy) остается в качестве упражнения и т. д.

person urschrei    schedule 12.11.2014
comment
Большое спасибо за ваше драгоценное время @urschrei. Это также послужит мне хорошим учебным материалом. Я работаю над этим почти год. Я принял к сведению все ваши предложения. Кстати, что означает YMMV? Я начал с R. Я смог получить контуры на карте в r, но я понял, что нельзя экстраполировать (заполнить домен) в r. Хотя я все еще не экстраполирую, я думаю, что могу быть счастлив, живя с python. Большое спасибо всем добрым и отзывчивым людям. - person Zilore Mumba; 13.11.2014
comment
@ZiloreMumba YMMV означает, что «ваш пробег может отличаться» — что вы можете по-разному относиться к цветовой карте и выбору ширины линии, которые я сделал, и что вы можете свободно экспериментировать с ними. Удачи! - person urschrei; 13.11.2014
comment
@AndreAraujo Это просто исходные данные, сохраненные в виде текстового файла, со строкой заголовка: Lon Lat Values. Файл разделен пробелами. - person urschrei; 05.01.2019

У меня не все установлено здесь для запуска вашего кода, но вы должны попробовать построить базовую карту m, которую вы создали, например:

# fig = plt.figure(figsize=(10,8)) # omit this at line 28

(...)

m.contourf(xi, yi, zi)
m.scatter(data.Lon, data.Lat, c=data.Z, s=100,
   vmin=zi.min(), vmax=zi.max())

(пожалуйста, сообщите, если это не работает)

person heltonbiker    schedule 11.11.2014
comment
заменив мои функции построения графиков фрагментом, который вы прислали, рисует карту без контуров и точечной диаграммы. - person Zilore Mumba; 11.11.2014
comment
Спасибо всем тем, кто потратил свое время на чтение моего кода (выше), и тем, кто помог мне заставить этот код работать (шесть месяцев назад), особенно @urschrei. С тех пор мне было интересно, есть ли какая-либо экстраполяция в python. Я знаю, что экстраполяция может дать странные результаты, но я ничего не видел в документации. Можно ли экстраполировать, чтобы хотя бы заполнить карту? - person Zilore Mumba; 28.05.2015
comment
Я удивлен, что нет ответа на этот простой вопрос: есть ли команда для экстраполяции в python? - person Zilore Mumba; 29.05.2015
comment
@ZiloreMumba вы можете использовать, например, модуль scypy.rbf для создания интерполятора RBF для набора данных. Затем вы можете интерполировать дальше от исходного набора данных (то есть экстраполировать), но проверять результаты, потому что чем дальше, тем больше ошибок вы получите. И еще, проверьте другие интерполяторы, не только RBF (кригинг тоже есть, но не нативно в scipy я думаю. - person heltonbiker; 01.06.2015
comment
Спасибо @heltonbiker, я попробую. - person Zilore Mumba; 01.06.2015