matplotlib图上的白色区域,pygrib数据在359.5和360度之间

时间:2015-04-25 13:19:21

标签: python matplotlib matplotlib-basemap grib gfs

我尝试使用pygrib使用matplotlib绘制gfs天气模型的输出以保存数据,该数据保存在grib文件中。几乎一切正常,输出看起来像这样:

enter image description here

通过使用0 degress的数据,该程序似乎没有缩小359.5和360度之间的差距。如果数据将在常规列表中,或者我将使用0°的数据,并通过附加列表将其保存为360°。我见过人们对非pygrib数据有同样的问题。 如果您知道如何更改pygrib数据(不幸的是常规操作不适用于pygrib数据)或者如何使matplotlib缩小差距,那么您真的可以帮我解决这个问题。也许函数“addcyclic”可以帮助,但我不知道如何。

编辑:我解决了问题,看到了答案。

所以这是产生问题的代码:

#!/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)

2 个答案:

答案 0 :(得分:1)

我在2个月后自己解决了这个问题:

如果您的经度范围是0到359.75,则Matplotlib不会填充该区域,因为它从matplotlibs的角度结束。我通过分割数据然后堆叠数据来解决它。

select .. where 'V' = 1

不再有0°的白色区域。

如果您想绘制整个半球(0到359.75度),我不知道是否有修复。

答案 1 :(得分:0)

我已经自己运行了几次,底图模块的addcyclic功能实际上运行得很好。 The basemap docs列出语法并使用得很好。

就代码中的变量而言,您可以在GribDataLayer类中乘以self.factor之前或之后添加循环点:

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)

希望这有帮助!