#StackBounty: #python #matplotlib #scipy #interpolation Return z-value of contour from separate xy coordinate

Bounty: 100

I have a set of xy cooridnates that generate a contour. For the code below, these cooridnates are from groups A and B. I have also created a separate xy cooridnate that is called from C1_X and C1_Y. However this isn’t used creating the contour itself. It is a separate xy coordinate.

Question: Is it possible to return the z-value at the C1_X C1_Y cooridnate?

It is similar to another question: enter link description here. This figure displays what I’m hoping to return.enter image description here

The contour below is normalised so values fall between -1 and 1. I’m hoping to return the z-value for C1_X and C1_Y, which is the white scatter point seen in the figure beneath the code.

I have attempted to return the z-value for this point using:

# Attempt at returning the z-value for C1 
f = RectBivariateSpline(X, Y, normPDF)
z = f(d['C1_X'], d['C1_Y']) 
print(z)

But I’m returning an error: raise TypeError('x must be strictly increasing')
TypeError: x must be strictly increasing

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as sts
import matplotlib.animation as animation
import matplotlib.transforms as transforms
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.interpolate import RectBivariateSpline

DATA_LIMITS = [0, 15]

def datalimits(*data):
    return DATA_LIMITS 

def mvpdf(x, y, xlim, ylim, radius=1, velocity=0, scale=0, theta=0):
    X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
    XY = np.stack([X, Y], 2)
    PDF = sts.multivariate_normal([x, y]).pdf(XY)
    return X, Y, PDF

def mvpdfs(xs, ys, xlim, ylim, radius=None, velocity=None, scale=None, theta=None):
    PDFs = []
    for i,(x,y) in enumerate(zip(xs,ys)):
        X, Y, PDF = mvpdf(x, y, xlim, ylim)
        PDFs.append(PDF)

    return X, Y, np.sum(PDFs, axis=0)


''' Animate Plot '''

fig, ax = plt.subplots(figsize = (10,6))
ax.set_xlim(DATA_LIMITS)
ax.set_ylim(DATA_LIMITS)

line_a, = ax.plot([], [], 'o', c='red', alpha = 0.5, markersize=5,zorder=3)
line_b, = ax.plot([], [], 'o', c='blue', alpha = 0.5, markersize=5,zorder=3)
lines=[line_a,line_b] 

offset = lambda p: transforms.ScaledTranslation(p/82.,0, plt.gcf().dpi_scale_trans)
trans = plt.gca().transData

scat = ax.scatter([], [], s=5**2,marker='o', c='white', alpha = 1,zorder=3,transform=trans+offset(+2) )
scats=[scat] 

cfs = None

def plotmvs(tdf, xlim=None, ylim=None, fig=fig, ax=ax):    
    global cfs  
    if cfs:
        for tp in cfs.collections:
            tp.remove()

    df = tdf[1]

    if xlim is None: xlim = datalimits(df['X'])
    if ylim is None: ylim = datalimits(df['Y'])

    PDFs = []

    for (group, gdf), group_line in zip(df.groupby('group'), (line_a, line_b)):
        group_line.set_data(*gdf[['X','Y']].values.T)
        X, Y, PDF = mvpdfs(gdf['X'].values, gdf['Y'].values, xlim, ylim)
        PDFs.append(PDF)

    for (group, gdf), group_line in zip(df.groupby('group'), lines+scats):
            if group in ['A','B']:
                group_line.set_data(*gdf[['X','Y']].values.T)
                kwargs = {
                'radius': gdf['Radius'].values if 'Radius' in gdf else None,
                'velocity': gdf['Velocity'].values if 'Velocity' in gdf else None,
                'scale': gdf['Scaling'].values if 'Scaling' in gdf else None,
                'theta': gdf['Rotation'].values if 'Rotation' in gdf else None,
                'xlim': xlim,
                'ylim': ylim
                }
                X, Y, PDF = mvpdfs(gdf['X'].values, gdf['Y'].values, **kwargs)
                PDFs.append(PDF)

            #plot white scatter point    
            elif group in ['C']:
                gdf['X'].values, gdf['Y'].values
                scat.set_offsets(gdf[['X','Y']].values)

    normPDF = (PDFs[0]-PDFs[1])/max(PDFs[0].max(),PDFs[1].max())

    # Attempt at returning the z-value for C1 
    f = RectBivariateSpline(X, Y, normPDF)
    z = f(d['C1_X'], d['C1_Y']) 
    print(z)

    cfs = ax.contourf(X, Y, normPDF, cmap='jet', alpha = 1, levels=np.linspace(-1,1,10),zorder=1)

    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="5%", pad=0.1)
    cbar = fig.colorbar(cfs, ax=ax, cax=cax)
    cbar.set_ticks([-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1])

    return  cfs.collections + [scat] + [line_a,line_b] 

n = 1
time = range(n)  

d = ({
    'A1_X' :    [3],
    'A1_Y' :    [6],
    'A2_X' :    [6],
    'A2_Y' :    [10],
    'B1_X' :    [12],
    'B1_Y' :    [2],
    'B2_X' :    [14],
    'B2_Y' :    [4],
    'C1_X' :    [4],
    'C1_Y' :    [6],
    'A1_Radius' :  [107],
    'A2_Radius' :  [95],  
    'B1_Radius' :  [250],
    'B2_Radius' :  [213],
    'A1_Scaling' : [7],
    'A2_Scaling' : [5],      
    'B1_Scaling' : [2],
    'B2_Scaling' : [4],                   
    'A1_Rotation' :    [0],
    'A2_Rotation' :    [0], 
    'B1_Rotation' :    [0],
    'B2_Rotation' :    [0],                       
    })

tuples = [((t, k.split('_')[0][0], int(k.split('_')[0][1:]), k.split('_')[1]), v[i])
    for k,v in d.items() for i,t in enumerate(time) ]

df = pd.Series(dict(tuples)).unstack(-1)
df.index.names = ['time', 'group', 'id']

interval_ms = 1000
delay_ms = 2000
ani = animation.FuncAnimation(fig, plotmvs,  frames=df.groupby('time'), interval=interval_ms, repeat_delay=delay_ms,)

plt.show()

enter image description here

I am hoping to return the contour value for this point. Intended Output will be either a list or df that displays the normalised z value (-1,1) for C.

Upon visual inspection this would be approx 0.6 or 0.7


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.