2015-04-25 8 views
3

Что я пытаюсь сделать для вывода вывода модели погоды gfs с помощью matplotlib с помощью pygrib для сохранения данных, которые сохраняются в grib-файлах. Почти все работает отлично, результат выглядит следующим образом:Белая область на графике matplotlib с данными pygrib между 359,5 и 360 градусами

enter image description here

Оказывается, что программа не закрывает зазор между 359,5 и 360 град, используя данные 0 град. Если данные будут в обычном списке или что-то, я буду использовать данные 0 ° и сохранить его на 360 °, добавив список. Я видел людей, имеющих ту же проблему с данными, не относящимися к pygrib. Если вы знаете, как изменить данные pygrib (обычные операции не работают с данными pygrib, к сожалению) или как заставить matplotlib закрыть пробел, вы действительно поможете мне в решении этой проблемы. Может быть, функция «addcyclic» может помочь, но я не знаю, как это сделать.

EDIT: Я решил проблему, см. Мой ответ.

Так вот код производит проблему:

#!/usr/bin/python3 

import os, sys, datetime, string 
from abc import ABCMeta, abstractmethod 

import numpy as np 
import numpy.ma as ma 
from scipy.ndimage.filters import minimum_filter, maximum_filter 
import pygrib 
from netCDF4 import Dataset 
from pylab import * 
import matplotlib.pyplot as plt 
from mpl_toolkits.basemap import Basemap, addcyclic, shiftgrid 

import laplaceFilter 
import mpl_util 


class Plot(Basemap): 
    def __init__(self, basemapParams): 
     super().__init__(**basemapParams) 
     self.layers = [] 

    def addLayer(self, layer): 
     self.layers.append(layer) 

    def plot(self, data): 
     for layer in self.layers: 
      layer.plot(self, data) 

     plt.title('Plot') 
     plt.show() 


class Layer(metaclass=ABCMeta): 
    def __init__(self): 
     pass 

    @abstractmethod 
    def plot(self, plot, data): 
     return NotImplemented 


class BackgroundLayer(Layer): 
    def __init__(self, bgtype, coords): 
     #possible bgtype values: borders, topo, both 
     self.bgtype = bgtype 
     self.lonStart = coords[0] 
     self.lonEnd = coords[1] 
     self.latStart = coords[2] 
     self.latEnd = coords[3] 

    def plot(self, plot, data): 
     [...] 


    def findSubsetIndices(self,min_lat,max_lat,min_lon,max_lon,lats,lons): 
     [...] 


class LegendLayer(Layer): 
    def __init__(self): 
     pass 


class GribDataLayer(Layer, metaclass=ABCMeta): 
    def __init__(self, varname, level, clevs, cmap, factor): 
     self.varname = varname 
     self.level = level 
     self.clevs = clevs 
     self.cmap = cmap 
     self.factor = factor 

    def plot(self, plot, data): 
     #depending on the height we want to use, we have to change the index 
     indexes = {1000:0, 2000:1, 3000:2, 5000:3, 7000:4, 10000:5, 15000:6, 20000:7, 25000:8, 30000:9, 
        35000:10, 40000:11, 45000:12, 50000:13, 55000:14, 60000:15, 65000:16, 70000:17, 
        75000:18, 80000:19, 85000:20, 90000:21, 92500:22, 95000:23, 97500:24, 100000:25, 0:0} 

     selecteddata = data.select(name = self.varname)[indexes[self.level]] 
     lats, lons = selecteddata.latlons() 



     layerdata = selecteddata.values*self.factor 

     x, y = plot(lons, lats) # compute map proj coordinates. 
     self.fillLayer(plot, x, y, layerdata, self.clevs, self.cmap) 

    @abstractmethod 
    def fillLayer(self, plot, x, y, layerdata, clevs, cmap): 
     return NotImplemented 


class ContourLayer(GribDataLayer): 
    def __init__(self, varname, level, clevs, cmap, factor, linewidth=1.5, fontsize=15, 
       fmt="%3.1f", inline=0,labelcolor = 'k'): 
     self.linewidth = linewidth 
     self.fontsize = fontsize 
     self.fmt = fmt 
     self.inline = inline 
     self.labelcolor = labelcolor 
     super().__init__(varname, level, clevs, cmap, factor) 

    def fillLayer(self, plot, x, y, layerdata, clevs, cmap): 
     # contour data over the map. 
     cs = plot.contour(x,y,layerdata,clevs,colors = cmap,linewidths = self.linewidth) 
     plt.clabel(cs, clevs, fontsize = self.fontsize, fmt = self.fmt, 
        inline = self.inline, colors = self.labelcolor) 
     if self.varname == "Pressure reduced to MSL": 
      self.plotHighsLows(plot,layerdata,x,y) 

    def plotHighsLows(self,plot,layerdata,x,y): 
     [...] 


class ContourFilledLayer(GribDataLayer): 
    def __init__(self, varname, level, clevs, cmap, factor, extend="both"): 
     self.extend = extend 
     super().__init__(varname, level, clevs, cmap, factor) 

    def fillLayer(self, plot, x, y, layerdata, clevs, cmap): 
     # contourfilled data over the map. 
     cs = plot.contourf(x,y,layerdata,levels=clevs,cmap=cmap,extend=self.extend) 
     #cbar = plot.colorbar.ColorbarBase(cs) 


[...] 


ger_coords = [4.,17.,46.,56.] 
eu_coords = [-25.,57.,22.,70.] 


### Choose Data 
data = pygrib.open('gfs.t12z.mastergrb2f03') 


### 500hPa Europe 
coords = eu_coords 
plot1 = Plot({"projection":"lcc","resolution":"h","rsphere":(6378137.00,6356752.3142), "area_thresh": 1000., 
      "llcrnrlon":coords[0],"llcrnrlat":coords[2],"urcrnrlon":coords[1],"urcrnrlat":coords[3], 
      "lon_0":(coords[0]+coords[1])/2.,"lat_0":(coords[2]+coords[3])/2.}) 


clevs = range(480,600,4) 
cmap = plt.cm.nipy_spectral 
factor = .1 
extend = "both" 
level = 50000 
layer1 = ContourFilledLayer('Geopotential Height', level, clevs, cmap, factor, extend) 


clevs = [480.,552.,600.] 
linewidth = 2. 
fontsize = 14 
fmt = "%d" 
inline = 0 
labelcolor = 'k' 
layer2 = ContourLayer('Geopotential Height', level, clevs, 'k', factor, linewidth, fontsize, fmt, inline, labelcolor) 

level = 0 
clevs = range(800,1100,5) 
factor = .01 
linewidth = 1.5 
inline = 0 
labelcolor = 'k' 
layer3 = ContourLayer('Pressure reduced to MSL', level, clevs, 'w', factor, linewidth, fontsize, fmt, inline, labelcolor) 


plot1.addLayer(BackgroundLayer('borders', coords)) 
plot1.addLayer(layer1) 
plot1.addLayer(layer2) 
plot1.addLayer(layer3) 
plot1.plot(data) 
+0

У этого человека была аналогичная проблема, но он не использовал файлы netcdf вместо grib-файлов, что делает его более сложным. [Исключить белые края в Matplotlib/Basemap pcolor plot] (https://stackoverflow.com/questions/13606304/eliminate-white-edges-in-matplotlib-basemap-pcolor-plot?rq=1) – Corrumpo

ответ

1

Я решил это сам через 2 месяца:

Matplotlib не заполнит область, если ваш диапазон долготы от 0 до 359.75 потому, что он заканчивается там с точки зрения matplotlibs. Я решил это, разделив данные и уложив их.

selecteddata_all = data.select(name = "Temperature")[0] 

selecteddata1, lats1, lons1 = selecteddata_all.data(lat1=20,lat2=60,lon1=335,lon2=360) 
selecteddata2, lats2, lons2 = selecteddata_all.data(lat1=20,lat2=60,lon1=0,lon2=30) 

lons   = np.hstack((lons1,lons2)) 
lats   = np.hstack((lats1,lats2)) 
selecteddata = np.hstack((selecteddata1,selecteddata2)) 

Никакой белой области, оставшейся от 0 ° больше.

Я не знаю, есть ли исправление, если вы хотите построить целое полушарие (от 0 до 359,75 град.).

0

Я несколько раз сталкивался с этим сам, и добавочная функция базового модуля фактически работает очень хорошо. The basemap docs выложите синтаксис и используйте довольно хорошо.

В терминах переменных в коде вы можете добавить циклическую точку либо до, либо после того, как вы умножьте self.factor в своем классе GribDataLayer:

layerdata, lons = addcyclic(layerdata, lons) 

Вы также можете использовать np.append и написать свой собственной функции для выполнения этой же задачи. Это будет выглядеть примерно так:

layerdata = np.append(layerdata,layerdata[...,0,None],axis=-1) 

Если входные данные 2D, то синтаксис выше эквивалентно выбору всех данных в первой долготе полосе (т.е. layerdata [:, 0])

layerdata = np.append(layerdata,layerdata[:,0,None],axis=-1) 

Надеюсь, это поможет!