datu-puti
datu-puti

Reputation: 1363

Interpolate polar/circular data with Pandas

I have a sparse data set, f44, made up of bearings in degrees and ssi (dbm) values:

       ssi
deg       
4.0    -69
59.0   -73
162.0  -73
267.0  -61
319.0  -75

I reindexed f44 to include all the missing indices from 0-359:

f44i = f44.reindex(np.arange(0,360))

When I interpolate (using quadratic) and plot the figure, it's apparent that the result doesn't interpolate between the first/lowest bearing and the highest:

f44i = f44i.interpolate(method='quadratic')
f44i.plot()

naive interpolation

How can I interpolate this data in a way that will fill in between 0 and 360 degrees? The pandas Series.interpolate documentation does not appear to have anything built-in, nor does the scipy documentation.

Upvotes: 0

Views: 1664

Answers (2)

datu-puti
datu-puti

Reputation: 1363

I'm not convinced this is the best way to do this, but it seems to work. Please add something if there is a better way.

Since I'm only interested in 0-360 degrees, I can duplicate the dataset from -360-0, and 360-720, expanding my original data set to the left and right, like so:

import numpy as  np    

# Create left side
f44il = f44i.copy()
f44il.index = np.arange(-360,0)

# Create right side
f44ir = f44i.copy()
f44ir.index = np.arange(360,720)

Interpolating and plotting the result looks promising (the third command shows 0-360 in a different color):

f44expanded = pd.concat([f44il, f44i, f44ir]).interpolate(method='quadratic')
f44expanded.plot()
f44expanded[np.arange(0,360)].plot()

repeating data

Then I can just create a new series from the interpolated data with an index from 0-360, which looks like it gives me exactly what I want:

f44final = f44expanded[np.arange(0,360)]
f44final.plot()

final plot

I suspect there is a better way to do this, so feel free to add an answer if you know of one.

Upvotes: 0

user8936101
user8936101

Reputation:

I have an alternative approach to this problem using scipy to interpolate onto a closed curve. First, I converted your data from (deg, ssi) to psuedo cartesian coordinates (x,y) assuming deg is the polar angle and ssi is the (negative) of the radial distance. Then you can use the method defined here to interpolate a closed curve onto a set of (x,y) points.

import numpy as np
import pandas
import matplotlib.pyplot as plt
from scipy import interpolate

dic = {'deg': [4.0, 59.0, 162.0, 267.0, 319.0],
       'ssi': [-69, -73, -73, -61, -75]}

f44  = pandas.DataFrame(data=dic)

'''
Now, lets do the following. Convert your data from (deg, ssi) to (x,y)
where x = ssi* cosd(deg), y=ssi*sind(deg). Now we need to interpolate a closed
curve onto these set of cartesian points.  
'''

f44['x'] = -f44['ssi']*np.cos( np.deg2rad(f44['deg']))
f44['y'] = -f44['ssi']*np.sin( np.deg2rad(f44['deg']))

x = f44.as_matrix(columns=[f44.columns[2]])[:,0]
y = f44.as_matrix(columns=[f44.columns[3]])[:,0]
x = np.r_[x, x[0]]
y = np.r_[y, y[0]]

tck, u = interpolate.splprep([x, y], s=0, per=True)
xi, yi = interpolate.splev(np.linspace(0, 1, 1000), tck)

# Save interpolated data to new dataframe. 
f44i = pandas.DataFrame(data = {'x':xi, 'y':yi})

f44i['deg'] = np.rad2deg( np.arctan2(f44i['y'],f44i['x']))
f44i['ssi'] =-np.sqrt( f44i['x']**2 + f44i['y']**2)

for i,l in enumerate(f44i['deg']):
    if l < 0:
        f44i['deg'][i] = 360 + f44i['deg'][i]

fig, ax = plt.subplots(1, 1)
ax.plot(f44i['deg'], f44i['ssi'], '.', markersize=0.5)
ax.plot(f44['deg'], f44['ssi'], '.', color='red')
plt.show()

Now we get a curve that looks like the one below. (re-converted from the psuedo cartesian coordinates to your preferred (deg, ssi) coordinates). Also, I have created a new dataframe to replace the f44i you created. You can make this code more suitable for your specific application.

Interpolation using a closed curve.

Upvotes: 1

Related Questions