Increase extent of vector layer with OGR or GDAL? - python

When using the OGR library or GDAL library with Python script, is it possible to increase the extent of a vector layer without actually adding new data points? In my specific case, I would like to increase the extent of vector layers associated with gpx files so that when I convert them to rasters they all have the same pixel matrix.
EDIT: An attempt of mine to use gdal.Rasterize does not produce a "tiff" file, nor does it cause an error to be reported:
import os
import gdal
import ogr
import math
os.chdir(r'C:\Users\pipi\Documents\Rogaine\Tarlo\gpx') #folder containing gpx files
vector_fn = '6_hour_Autumngaine_w_Tom_Elle.gpx' #filename of input gpxfile
pixel_size = 20 #units are in m if gpx file is left in wgs84
raster_fn = '0011a.tif' # Filename of the raster Tiff that will be created
driver = ogr.GetDriverByName('GPX')
source_ds = driver.Open(vector_fn, 0)
source_layer = source_ds.GetLayer('track_points') #returns the 'track points' layer of the data source
SR = source_layer.GetSpatialRef().ExportToWkt()
#_______USING VALUES FROM THE FILE___________
x_min1, x_max1, y_min1, y_max1 = source_layer.GetExtent()
pixel_sizey = pixel_size/(111.2*math.pow(10,3)) #determines an approximate x and y size because of geographic coordinates.
pixel_sizex = pixel_size/(math.cos(((y_max1 + y_min1)/2)*(math.pi/180))*111.2*math.pow(10,3))
print (pixel_sizey, pixel_sizex)
x_res = int((x_max1 - x_min1) / pixel_sizex)
y_res = int((y_max1 - y_min1) / pixel_sizey)
print (x_res, y_res)
layer_list = ['track_points']
gdal.Rasterize(raster_fn, vector_fn, format='GTiff', outputBounds=[x_min1, y_min1, x_max1, y_max1], outputSRS=SR, xRes=x_res, yRes=y_res, burnValues=[1], layers=layer_list)
target_ds = None
vector_fn = None
source_layer = None
source_ds = None

You need to pass options=gdal.RasterizeOptions(format='GTiff', outputBounds=[x_min1, y_min1, x_max1, y_max1], outputSRS=SR, xRes=x_res, yRes=y_res, burnValues=[1], layers=layer_list) instead of passing the individual kwargs directly. Otherwise, they will be ignored, and the command won't do what you intend. See Link and Link for details and links to the source code (often useful given the terse documentation).

I was unable to find a method to change the extent of the vector layer. However, I was able to write a python Function that uses gdal.RasterizeLayer() to produce a raster with an extent much larger than the original vector layer. The code for this function is:
import os
import gdal
import ogr
def RasterizeLarge(name, layer, extent, pixel_size):
"""Used to rasterize a layer where the raster extent is much larger than the layer extent
Arguments:
name -- (string) filename without extension of raster to be produced
layer -- (vector layer object) vector layer containing the data to be rasterized (tested with point data)
extent -- (list: x_min, x_max, y_min, y_max) extent of raster to be produced
pixel_size -- (list: x_pixel_size, y_pixel_size) 1 or 2 pixel different pixel sizes may be sent
"""
if isinstance(pixel_size, (list, tuple)):
x_pixel_size = pixel_size[0]
y_pixel_size = pixel_size[1]
else:
x_pixel_size = y_pixel_size = pixel_size
x_min, x_max, y_min, y_max = extent
# determines the x and y resolution of the file (lg = large)
x_res_lg = int((x_max - x_min) / x_pixel_size)+2
y_res_lg = int((y_max - y_min) / y_pixel_size)+2
if x_res_lg > 1 and y_res_lg > 1:
pass
else:
print ('Your pixel size is larger than the extent in one dimension or more')
return
x_min_sm, x_max_sm, y_min_sm, y_max_sm = layer.GetExtent()
if x_min_sm > x_min and x_max_sm < x_max and y_min_sm > y_min and y_max_sm < y_max:
pass
else:
print ('The extent of the layer is in one or more parts outside of the extent provided')
return
nx = int((x_min_sm - x_min)/x_pixel_size) #(number of pixels between main raster origin and minor raster)
ny = int((y_max - y_max_sm)/y_pixel_size)
x_res_sm = int((x_max_sm - x_min_sm) / x_pixel_size)+2
y_res_sm = int((y_max_sm - y_min_sm) / y_pixel_size)+2
#determines upper left corner of small layer raster
x_min_sm = x_min + nx * x_pixel_size
y_max_sm = y_max - ny * y_pixel_size
#______Creates a temporary raster file for the small raster__________
try:
# create the target raster file with 1 band
sm_ds = gdal.GetDriverByName('GTiff').Create('tempsmall.tif', x_res_sm, y_res_sm, 1, gdal.GDT_Byte)
sm_ds.SetGeoTransform((x_min_sm, x_pixel_size, 0, y_max_sm, 0, -y_pixel_size))
sm_ds.SetProjection(layer.GetSpatialRef().ExportToWkt())
gdal.RasterizeLayer(sm_ds, [1], layer, burn_values=[1])
sm_ds.FlushCache()
#______Gets data from the new raster in the form of an array________
in_band = sm_ds.GetRasterBand(1)
in_band.SetNoDataValue(0)
sm_data = in_band.ReadAsArray()
finally:
sm_ds = None #flushes data from memory. Without this you often get an empty raster.
#_____Creates an output file with the provided name and extent that contains the small raster.
name = name + '.tif'
try:
lg_ds = gdal.GetDriverByName('GTiff').Create(name, x_res_lg, y_res_lg, 1, gdal.GDT_Byte)
if lg_ds is None:
print 'Could not create tif'
return
else:
pass
lg_ds.SetProjection(layer.GetSpatialRef().ExportToWkt())
lg_ds.SetGeoTransform((x_min, x_pixel_size, 0.0, y_max, 0.0, -y_pixel_size))
lg_band = lg_ds.GetRasterBand(1)
lg_data = in_band.ReadAsArray()
lg_band.WriteArray(sm_data, xoff = nx, yoff = ny)
lg_band.SetNoDataValue(0)
lg_band.FlushCache()
lg_band.ComputeStatistics(False)
lg_band = None
finally:
del lg_ds, lg_band, in_band
os.remove('tempsmall.tif')
return

Related

Use gdal.RasterizeLayer without exporting image to drive

I have successfully used pretty generic code to rasterise a polygon layer (see below). However, I would like to convert the rasterised layer to a numpy array so that I can conduct further image processing steps rather than directly exporting the layer to drive. Is it possible to do this?
I have spent a long time on the GDAL docs pages, but I can't find a documented way to get to the array object. Any help much appreciated.
import gdal
import geopandas
import ogr
#open raster with target resolution/ coordinate reference system etc
data = gdal.Open('input_image.tif')
dataArray=data.ReadAsArray()
#define output shapefile name
output='output_fileName.tif'
#Get coordinate information for input raster
geo_transform = data.GetGeoTransform()
print(geo_transform)
#Get boundary coordinates and resolution of raster layer
x_min = geo_transform[0]
y_max = geo_transform[3]
x_max = x_min + geo_transform[1] * data.RasterXSize
y_min = y_max + geo_transform[5] * data.RasterYSize# (-40)
x_res = data.RasterXSize
y_res = data.RasterYSize
pixel_width = geo_transform[1]
#Open shapefile in geopandas
dataShp = geopandas.read_file('input_shapefile.shp')
# change CRS from polygon to raster file
dataShp = dataShp.to_crs(epsg=3031)
#convert geopandas into ogr Datasource
shp_temp = ogr.Open(dataShp.to_json())
#extract layer from ogr Datasource
mb_l = shp_temp.GetLayer()
target_ds = gdal.GetDriverByName('GTiff').Create(output, x_res, y_res, 1, gdal.GDT_Byte)
target_ds.SetGeoTransform((x_min, pixel_width, 0, y_min, 0, pixel_width))
band = target_ds.GetRasterBand(1)
NoData_value = -999999
band.SetNoDataValue(NoData_value)
band.FlushCache()
gdal.RasterizeLayer(target_ds, [1], mb_l, options=["ATTRIBUTE=type"])
target_ds = None

Aligning a shapefile to raster and assign values to overlay, then return as array?

My goal is to align a shapefile to a raster basemap, and assign 1 to the cells that overlap and 0 to the ones that don't, eventually returning an array that contains lat, lon, time, and the binary variable (1/0).
Here's the plan: 1) create raster of region from array, 2) rasterize polygon shapefiles, 3) align rasterized shapefiles with base raster, 4) pixels that overlap will be assigned 1 and those that don't will be 0, 5) convert rasters to array.
I've been able to do steps 1 & 2 (see code below), but I've been stuck on step 3 for a long time. How do I align the two rasters?
You can find the files here:
https://www.dropbox.com/sh/pecptfepac18s2y/AADbxFkKWlLqMdiHh-ICt4UYa?dl=0
Here's the code I used to create a flat grid of BC as basemap:
import gdal, osr
import numpy as np
#define parameters
#units = km
grid_size = 5
BC_width = 700
BC_length = 1800
def array2raster(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array):
cols = array.shape[1]
rows = array.shape[0]
originX = rasterOrigin[0]
originY = rasterOrigin[1]
driver = gdal.GetDriverByName('GTiff')
outRaster = driver.Create(newRasterfn, cols, rows, 1, gdal.GDT_Byte)
outRaster.SetGeoTransform((originX, pixelWidth, 0, originY, 0, pixelHeight))
outband = outRaster.GetRasterBand(1)
outband.WriteArray(array)
outRasterSRS = osr.SpatialReference()
outRasterSRS.ImportFromEPSG(4326)
outRaster.SetProjection(outRasterSRS.ExportToWkt())
outband.FlushCache()
def main(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array):
reversed_arr = array[::-1] # reverse array so the tif looks like the array
array2raster(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,reversed_arr) # convert array to raster
if __name__ == "__main__":
array = np.zeros([int(BC_length/grid_size),int(BC_width/grid_size)]) #140x360
for i in range(1,100):
array[i] = 100
rasterOrigin = (-139.72938, 47.655534) #lower left corner of raster
newRasterfn = '/temp/test.tif'
cols = array.shape[1] #shape of an array (aka # of elements in each dimension)
rows = array.shape[0]
originX = rasterOrigin[0]
originY = rasterOrigin[1]
pixelWidth = 5
pixelHeight = 5
Here's the code I used to rasterize polygon shapefiles
import ogr, gdal, osr
output_raster = '/testdata/poly.tif'
shapefile = "/testdata/20180808.shp"
def main(shapefile):
#making the shapefile as an object.
input_shp = ogr.Open(shapefile)
#getting layer information of shapefile.
shp_layer = input_shp.GetLayer()
#pixel_size determines the size of the new raster.
#pixel_size is proportional to size of shapefile.
pixel_size = 0.1
#get extent values to set size of output raster.
x_min, x_max, y_min, y_max = shp_layer.GetExtent()
#calculate size/resolution of the raster.
x_res = int((x_max - x_min) / pixel_size)
y_res = int((y_max - y_min) / pixel_size)
#get GeoTiff driver by
image_type = 'GTiff'
driver = gdal.GetDriverByName(image_type)
#passing the filename, x and y direction resolution, no. of bands, new raster.
new_raster = driver.Create(output_raster, x_res, y_res, 1, gdal.GDT_Byte)
#transforms between pixel raster space to projection coordinate space.
new_raster.SetGeoTransform((x_min, pixel_size, 0, y_min, 0, pixel_size))
#get required raster band.
band = new_raster.GetRasterBand(1)
#assign no data value to empty cells.
no_data_value = -9999
band.SetNoDataValue(no_data_value)
band.FlushCache()
#main conversion method
gdal.RasterizeLayer(new_raster, [1], shp_layer, burn_values=[255])
#adding a spatial reference
new_rasterSRS = osr.SpatialReference()
new_rasterSRS.ImportFromEPSG(4326)
new_raster.SetProjection(new_rasterSRS.ExportToWkt())
return output_raster
I'm doing everything in Python as I don't have access or funding to paid GIS software. I'm totally new to geospatial data processing... not sure if I'm taking the right approach. Any help would be amazing.
Checkout 'rasterio.mask.mask' from the rasterio library. I think it will help.

Programmatically subtract rasters of different dimensions

Question:
How can I programmatically return a raster that is the difference of two (differently sized) red bands?
i.e.
gdal_calc.py -A 'WARPED.tif' -B 'DSC_1636.tif' --outfile = 'dif.tif' --calc = "A-B"
QGIS raster calculator performs this function just fine. However, the previous code returns the following error.
Exception: Error! Dimensions of file DSC_1636.tif (7380, 4928) are different from other files (7743, 5507). Cannot proceed
I am currently under the impression I should read in the rasters using a defined extent, created by finding the overlap as shown below, but I am still not able to make this work.
# Subtract two rasters of different dimensions
# Pixel coordinates define overlap
import os, sys
from PIL import Image
from osgeo import gdal, ogr, osr
gdal.UseExceptions()
# Use PIL to get information from images
im1 = Image.open('DSC_0934-warped.tif')
print('warped image size is %s ' % str(im1.size))
im2 = Image.open('DSC_1636.png')
print('initial image (image 2) size is %s' % str(im2.size))
warped image size is (7743, 5507)
initial image (image 2) size is (7380, 4928)
# Use GDAL to get information about images
def get_extent(fn):
'''Returns min_x, max_y, max_x, min_y'''
ds = gdal.Open(fn)
gt = ds.GetGeoTransform()
return (gt[0], gt[3], gt[0] + gt[1] * ds.RasterXSize,
gt[3] + gt[5] * ds.RasterYSize)
print('extent of warped.tif is %s' % str(get_extent('DSC_0934-warped.tif')))
print('extent of 1636.png is %s' % str(get_extent('DSC_1636.png')))
extent of warped.tif is (-375.3831214210602, 692.5167764068751, 7991.3588371542955, -5258.102875649754)
extent of 1636.png is (0.0, 0.0, 7380.0, 4928.0)
r1 = get_extent('DSC_0934-warped.tif')
r2 = get_extent('DSC_1636.png')
# Get left, top, right, bottom of dataset's bounds in pixel coordinates
intersection = [max(r1[0], r2[0]),
min(r1[1], r2[1]),
min(r1[2], r2[2]),
max(r1[3], r2[3])]
print('checking for overlap')
if (intersection[2] < intersection[0]) or (intersection[1] > intersection[3]):
intersection = None
print('no overlap')
else:
print('intersection overlaps at: %s' % intersection)
checking for overlap
intersection overlaps at: [0.0, 0.0, 7380.0, 4928.0]
The most straight forward answer is to read in the images as an array of defined dimensions.
Without reposting the code above used to check where the overlap is, the solution can be had with the following additions. (Thank you #Val)
# Get the data
ds1_src = gdal.Open( "DSC_1636.png" )
ds2_src = gdal.Open( "DSC_0934-warped.tif")
ds1_bnd = ds1_src.GetRasterBand(1).ReadAsArray(xoff=0, yoff=0, win_xsize=7380, win_ysize=4928)
ds2_bnd = ds2_src.GetRasterBand(1).ReadAsArray(xoff=0, yoff=0, win_xsize=7380, win_ysize=4928)
# Do the maths...
data_out = ds2_bnd - ds1_bnd
#Write the out file
driver = gdal.GetDriverByName("GTiff")
dsOut = driver.Create("out.tiff", 7380, 4928, 1, GDT_Byte)
CopyDatasetInfo(ds1_src,dsOut)
bandOut=dsOut.GetRasterBand(1)
BandWriteArray(bandOut, data_out)
#Close the datasets
ds1_src = None
ds2_src = None
ds1_bnd = None
ds2_bnd = None
bandOut = None
dsOut = None

How to remove rings from convolve healpix map?

I'm applying convolution techniques to convolve 2 datasets, a healpix map with nside = 256 and a primary beam of shape (256, 256) in order to measure the total intensity from the convolved healpix map. My problem is that after convolving my map with the primary beam i get rings in my convolved map. I've tried normalizing it with either lanczos or Gaussian kernel to take care of the rings but all these approaches have failed.
In my code below, i used the query function in scipy to search for the nearest pixels in my healpix map within a given radius and take the sum of the product of the corresponding pixels in the primary beam using map coordinate. The final image i get has rings in it. Please can anyone help me solve this problem? Thanks in advance.
def query_npix(nside, npix, radius):
print 'searching for nearest pixels:......'
t1, t2 = hp.pix2ang(nside, np.arange(npix))
tree = spatial.cKDTree(zip(t1, t2))
dist, ipix_indx = tree.query(zip(t1, t2), k = 150, distance_upper_bound = radius)
r1, r2 = hp.pix2ang(nside, ipix_indx)
ra = r1.T - t1
dec = r2.T - t2
print 'Done searching'
return np.array(dist), np.array(ipix_indx), np.array(ra.T), np.array(dec.T)
def fullSky_convolve(healpix_map, primary_beam_fits, ipix_indx, dist, radius, r1, r2):
measured_map = []
hdulist = openFitsFile(primary_beam_fits)
beam_data = hdulist[0].data
header = hdulist[0].header
nside = hp.get_nside(healpix_map[0, ...])
npix = hp.get_map_size(healpix_map[0, ...]) # total number of pixels in the map must be 12 * nside^2
crpix1, crval1, cdelt1 = [ header.get(x) for x in "CRPIX1", "CRVAL1", "CDELT1" ]
crpix2, crval2, cdelt2 = [ header.get(x) for x in "CRPIX2", "CRVAL2", "CDELT2" ]
# beam centres in pixel coordinates
xc = crpix1-1 + (np.rad2deg(r1.ravel()) - crval1)/(256*cdelt1)
yc = crpix2-1 + (np.rad2deg(r2.ravel()) - crval2)/(256*cdelt2)
#xc = (np.rad2deg(r1.ravel()) )/cdelt1
for j in xrange(4):
print 'started Stokes: %d' %j
for iter in xrange(0 + j, 16, 4):
outpt = np.zeros(shape = npix, dtype=np.float64)
#by = outpt.copy()
# mask beam
bm_data = beam_data[iter]
#masked_beam= beam_data[iter]
shape = bm_data.shape
rad = np.linspace(-shape[0]/2,shape[-1]/2,shape[0])
rad2d = np.sqrt(rad[np.newaxis,:]**2+rad[:,np.newaxis]**2)
mask = rad2d <= radius/abs(cdelt2)
masked_beam = bm_data*mask
s1 = ndimage.map_coordinates(masked_beam, [xc, yc], mode = 'constant')
bm_map = s1.reshape(dist.shape[0], dist.shape[-1])
for itr in xrange(npix):
g_xy = (1.0/(np.sqrt(2*np.pi)*np.std(dist[itr])))*np.exp(-(dist[itr])**2/(2*np.var(dist[itr])))
#weighted_healpix_map = np.convolve(healpix_map[j, ...][ipix_indx[itr]], g_xy/g_xy.sum(), mode='same')
weighted_healpix_map = ndimage.filters.convolve(healpix_map[j, ...][ipix_indx[itr]], g_xy/g_xy.sum(), mode='reflect')
#outpt[itr] = np.sum(weighted_healpix_map*(bm_map[itr]/bm_map[itr].sum()))
outpt[itr] = np.sum(weighted_healpix_map*(bm_map[itr]))
#print 'itr', itr
alpha = file('pap%d.save'%iter, 'wb')
#h_map = ndimage.filters.gaussian_filter(outpt, sigma = 3.)
cPickle.dump(outpt, alpha, protocol = cPickle.HIGHEST_PROTOCOL)
alpha.close()
print 'Just dumped stripp%d.save:-------'%iter
print 'Loading dumped files:-------'
loaded_objects = []
for itr4 in xrange(16):
alpha = file('stripp%d.save'%itr4, 'rb')
loaded_objects.append(cPickle.load(alpha))
alpha.close()
measured_map.append(copy.deepcopy(loaded_objects))
return measured_map
Remember that HEALPix maps can be in either "Ring" or "Nested" format. It sounds like you may need to add the keyword nest=True to your healpy functions like hp.pix2ang. If your input maps are in nested format, this keyword is needed.
For example:
I recently tried using the healpy.smoothing() function, and found my resulting image to have rings (perhaps like you described), upon viewing the output map with healpix.mollview(). The rings disappeared and the image was presented as I expected, after running mollview with the nested=True keyword. Check what ordering schemes your input files use
Reference:
http://healpy.readthedocs.org/en/latest/tutorial.html#creating-and-manipulating-maps
Healpix supports two different ordering schemes, RING or NESTED. By
default, healpy maps are in RING ordering. In order to work with
NESTED ordering, all map related functions support the nest keyword,
for example: hp.mollview(m, nest=True, title="Mollview image NESTED")

SciPy RectSphereBivariateSpline interpolation over sphere returning ValueError

I have 3D measurement data on a sphere that is very coarse and I want to interpolate.
I found that RectSphereBivariateSpline from scipy.interpolate should be most suitable.
I used the example in the RectSphereBivariateSpline documentation as a starting point and now have the following code:
""" read csv input file, post process and plot 3D data """
import csv
import numpy as np
from mayavi import mlab
from scipy.interpolate import RectSphereBivariateSpline
# user input
nElevationPoints = 17 # needs to correspond with csv file
nAzimuthPoints = 40 # needs to correspond with csv file
threshold = - 40 # needs to correspond with how measurement data was captured
turnTableStepSize = 72 # needs to correspond with measurement settings
resolution = 0.125 # needs to correspond with measurement settings
# read data from file
patternData = np.empty([nElevationPoints, nAzimuthPoints]) # empty buffer
ifile = open('ttest.csv') # need the 'b' suffix to prevent blank rows being inserted
reader = csv.reader(ifile,delimiter=',')
reader.next() # skip first line in csv file as this is only text
for nElevation in range (0,nElevationPoints):
# azimuth
for nAzimuth in range(0,nAzimuthPoints):
patternData[nElevation,nAzimuth] = reader.next()[2]
ifile.close()
# post process
def r(thetaIndex,phiIndex):
"""r(thetaIndex,phiIndex): function in 3D plotting to return positive vector length from patternData[theta,phi]"""
radius = -threshold + patternData[thetaIndex,phiIndex]
return radius
#phi,theta = np.mgrid[0:nAzimuthPoints,0:nElevationPoints]
theta = np.arange(0,nElevationPoints)
phi = np.arange(0,nAzimuthPoints)
thetaMesh, phiMesh = np.meshgrid(theta,phi)
stepSizeRad = turnTableStepSize * resolution * np.pi / 180
theta = theta * stepSizeRad
phi = phi * stepSizeRad
# create new grid to interpolate on
phiIndex = np.linspace(1,360,360)
phiNew = phiIndex*np.pi/180
thetaIndex = np.linspace(1,180,180)
thetaNew = thetaIndex*np.pi/180
thetaNew,phiNew = np.meshgrid(thetaNew,phiNew)
# create interpolator object and interpolate
data = r(thetaMesh,phiMesh)
lut = RectSphereBivariateSpline(theta,phi,data.T)
data_interp = lut.ev(thetaNew.ravel(),phiNew.ravel()).reshape((360,180)).T
x = (data_interp(thetaIndex,phiIndex)*np.cos(phiNew)*np.sin(thetaNew))
y = (-data_interp(thetaIndex,phiIndex)*np.sin(phiNew)*np.sin(thetaNew))
z = (data_interp(thetaIndex,phiIndex)*np.cos(thetaNew))
# plot 3D data
obj = mlab.mesh(x, y, z, colormap='jet')
obj.enable_contours = True
obj.contour.filled_contours = True
obj.contour.number_of_contours = 20
mlab.show()
The example from the documentation works, but when I try to run the above code with the following test data: testdata I get a ValueError at the code position where the RectSphereBivariateSpline interpolator object is declared:
ValueError:
ERROR: on entry, the input data are controlled on validity
the following restrictions must be satisfied.
-1<=iopt(1)<=1, 0<=iopt(2)<=1, 0<=iopt(3)<=1,
-1<=ider(1)<=1, 0<=ider(2)<=1, ider(2)=0 if iopt(2)=0.
-1<=ider(3)<=1, 0<=ider(4)<=1, ider(4)=0 if iopt(3)=0.
mu >= mumin (see above), mv >= 4, nuest >=8, nvest >= 8,
kwrk>=5+mu+mv+nuest+nvest,
lwrk >= 12+nuest*(mv+nvest+3)+nvest*24+4*mu+8*mv+max(nuest,mv+nvest)
0< u(i-1)=0: s>=0
if s=0: nuest>=mu+6+iopt(2)+iopt(3), nvest>=mv+7
if one of these conditions is found to be violated,control is
immediately repassed to the calling program. in that case there is no
approximation returned.
I have tried and tried, but I am absolutely clueless what I should change in order to satisfy the RectSphereBivariateSpline object.
Does anyone have any hint as to what I may be doing wrong?
-- EDIT --
With the suggestions from #HYRY, I now have the following code that runs without runtime errors:
""" read csv input file, post process and plot 3D data """
import csv
import numpy as np
from mayavi import mlab
from scipy.interpolate import RectSphereBivariateSpline
# user input
nElevationPoints = 17 # needs to correspond with csv file
nAzimuthPoints = 40 # needs to correspond with csv file
threshold = - 40 # needs to correspond with how measurement data was captured
turnTableStepSize = 72 # needs to correspond with measurement settings
resolution = 0.125 # needs to correspond with measurement settings
# read data from file
patternData = np.empty([nElevationPoints, nAzimuthPoints]) # empty buffer
ifile = open('ttest.csv') # need the 'b' suffix to prevent blank rows being inserted
reader = csv.reader(ifile,delimiter=',')
reader.next() # skip first line in csv file as this is only text
for nElevation in range (0,nElevationPoints):
# azimuth
for nAzimuth in range(0,nAzimuthPoints):
patternData[nElevation,nAzimuth] = reader.next()[2]
ifile.close()
# post process
def r(thetaIndex,phiIndex):
"""r(thetaIndex,phiIndex): function in 3D plotting to return positive vector length from patternData[theta,phi]"""
radius = -threshold + patternData[thetaIndex,phiIndex]
return radius
#phi,theta = np.mgrid[0:nAzimuthPoints,0:nElevationPoints]
theta = np.arange(0,nElevationPoints)
phi = np.arange(0,nAzimuthPoints)
thetaMesh, phiMesh = np.meshgrid(theta,phi)
stepSizeRad = turnTableStepSize * resolution * np.pi / 180
theta = theta * stepSizeRad
phi = phi * stepSizeRad
# create new grid to interpolate on
phiIndex = np.arange(1,361)
phiNew = phiIndex*np.pi/180
thetaIndex = np.arange(1,181)
thetaNew = thetaIndex*np.pi/180
thetaNew,phiNew = np.meshgrid(thetaNew,phiNew)
# create interpolator object and interpolate
data = r(thetaMesh,phiMesh)
theta[0] += 1e-6 # zero values for theta cause program to halt; phi makes no sense at theta=0
lut = RectSphereBivariateSpline(theta,phi,data.T)
data_interp = lut.ev(thetaNew.ravel(),phiNew.ravel()).reshape((360,180)).T
def rInterp(theta,phi):
"""rInterp(theta,phi): function in 3D plotting to return positive vector length from interpolated patternData[theta,phi]"""
thetaIndex = theta/(np.pi/180)
thetaIndex = thetaIndex.astype(int)
phiIndex = phi/(np.pi/180)
phiIndex = phiIndex.astype(int)
radius = data_interp[thetaIndex,phiIndex]
return radius
# recreate mesh minus one, needed otherwise the below gives index error, but why??
phiIndex = np.arange(0,360)
phiNew = phiIndex*np.pi/180
thetaIndex = np.arange(0,180)
thetaNew = thetaIndex*np.pi/180
thetaNew,phiNew = np.meshgrid(thetaNew,phiNew)
x = (rInterp(thetaNew,phiNew)*np.cos(phiNew)*np.sin(thetaNew))
y = (-rInterp(thetaNew,phiNew)*np.sin(phiNew)*np.sin(thetaNew))
z = (rInterp(thetaNew,phiNew)*np.cos(thetaNew))
# plot 3D data
obj = mlab.mesh(x, y, z, colormap='jet')
obj.enable_contours = True
obj.contour.filled_contours = True
obj.contour.number_of_contours = 20
mlab.show()
However, the plot is much different than the non-interpolated data, see picture here as reference.
Also, when running the interactive session, data_interp is much larger in value (>3e5) than the original data (this is around 20 max).
Any further tips?
It looks like that theta[0] can't be 0, if you change it a litte before call RectSphereBivariateSpline:
theta[0] += 1e-6

Categories

Resources