1

The code below is a bivariate gaussian distribution. The distribution is produced by adjusting the COV matrix to account for specific variables. Specifically, every XY coordinate is applied with a radius ([_Rad]). The COV matrix is then adjusted by scaling factor ([_Scaling]) to expand the radius in x-direction and contract in y-direction. The direction of this is measured by the rotation angle ([_Rotation]). The output is expressed as a probability function.

Question. The radius should only cover a set area. When I try to translate the script to a group of coordinates (link at the bottom) the probability extends over the entire frame. You can see the flickering of colours, which indicates alternating probability. But the radius of the coordinates ranges from 8-25. This area should be fixed or pegged. It shouldn't extend the entire frame

I have tried to fix the areas as 0.5 but that isn't the issue. I'm hoping to alter the code so that the probability is only influenced by the radius provided.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as sts
from matplotlib.animation import FuncAnimation

#Create data limits used for the animation frame. Bit rough
DATA_LIMITS = [-100, 100]

def datalimits(*data):
    return DATA_LIMITS  # dmin - spad, dmax + spad

#This is the function used for the rotation matrix
def rot(theta):
    theta = np.deg2rad(theta)
    return np.array([
        [np.cos(theta), -np.sin(theta)],
        [np.sin(theta), np.cos(theta)]
    ])

#Used for the covariance matrix
def getcov(radius=1, scale=1, theta=0):
    cov = np.array([
        [radius*(scale + 1), 0],
        [0, radius/(scale + 1)]
    ])

    r = rot(theta)
    return r @ cov @ r.T

#This is the multivariate probability distribution function
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)

    x,y = rot(theta) @ (velocity/2, 0) + (x, y)

    cov = getcov(radius=radius, scale=scale, theta=theta)

    PDF = sts.multivariate_normal([x, y], cov).pdf(XY)

    return X, Y, PDF

#Used for the animation function
def mvpdfs(xs, ys, xlim, ylim, radius=None, velocity=None, scale=None, theta=None):
    PDFs = []
    for i,(x,y) in enumerate(zip(xs,ys)):
        kwargs = {
            'radius': radius[i] if radius is not None else 1,
            'velocity': velocity[i] if velocity is not None else 0,
            'scale': scale[i] if scale is not None else 0,
            'theta': theta[i] if theta is not None else 0,
            'xlim': xlim,
            'ylim': ylim
        }
        X, Y, PDF = mvpdf(x, y,**kwargs)
        PDFs.append(PDF)

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

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

#animate the scatter points
line_a, = ax.plot([], [], '.', c='red', alpha = 0.5, markersize=5, animated=True)
line_b, = ax.plot([], [], '.', c='blue', alpha = 0.5, markersize=5, animated=True)
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)):

        # Update the scatter line data
        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)

    #I've played around with these functions a bit. This is 
    #where I think the probability subtraction from both teams results
    #in the uneven or _flickering_ background probability
    PDF = PDFs[0] - PDFs[1]
    normPDF = PDF - PDF.min()
    normPDF = normPDF / normPDF.max()

    #This function attempted to _fix_ the background
    #to 0.5 or neutral but you can still see the areas
    #not covered by scatter points is still a different
    #probability 
    #normPDF = PDF * .5/max(PDF.max(), -PDF.min()) + .5

    #create the contour
    cfs = ax.contourf(X, Y, normPDF, cmap='viridis', alpha = 0.8,
    levels=10)

    return cfs.collections + [line_a, line_b]

#This big data frame houses the XY coordinates, Radius, Scaling factor
#Rotation for each respective frame
n = 10
time = range(n) 
d = ({
     'A1_X' :    [13.3,13.16,12.99,12.9,12.79,12.56,12.32,12.15,11.93,11.72],
     'A1_Y' :    [26.12,26.44,26.81,27.18,27.48,27.82,28.13,28.37,28.63,28.93],
     'A2_X' :    [6.97,6.96,7.03,6.98,6.86,6.76,6.55,6.26,6.09,5.9],
     'A2_Y' :    [10.92,10.83,10.71,10.52,10.22,10.02,9.86,9.7,9.54,9.37],
     'A3_X' :    [-31.72,-31.93,-32.18,-32.43,-32.7,-32.89,-33.15,-33.51,-33.84,-34.17],
     'A3_Y' :    [21.25,21.52,21.7,21.98,22.25,22.47,22.7,22.95,23.2,23.4],
     'A4_X' :    [37.54,37.42,37.3,37.14,36.97,36.77,36.56,36.37,36.13,35.89],
     'A4_Y' :    [7.31,7.35,7.38,7.43,7.5,7.58,7.65,7.68,7.69,7.69],
     'A5_X' :    [-5.37,-5.31,-5.28,-5.34,-5.41,-5.42,-5.68,-5.84,-6.1,-6.31],
     'A5_Y' :    [-5.42,-5.7,-6,-6.15,-6.41,-6.67,-6.88,-7.11,-7.33,-7.49],
     'A6_X' :    [-3.33,-3.15,-2.97,-2.94,-2.88,-2.79,-2.69,-2.66,-2.54,-2.67],
     'A6_Y' :    [13.69,13.86,14.09,14.34,14.73,15.01,15.38,15.83,16.15,16.73],
     'A7_X' :    [-4.4,-4.56,-4.83,-5.02,-5.18,-5.51,-5.81,-6.03,-6.31,-6.7],
     'A7_Y' :    [21.34,21.53,21.69,21.89,22.03,22.35,22.63,22.91,23.14,23.34],
     'A8_X' :    [-14.89,-15.12,-15.26,-15.52,-15.96,-16.37,-16.7,-17.08,-17.55,-17.95],
     'A8_Y' :    [3.7,3.41,3.14,2.84,2.58,2.26,2.07,1.78,1.45,1.23],
     'A9_X' :    [-51.92,-52.04,-52.15,-52.26,-52.36,-52.54,-52.76,-52.98,-53.17,-53.4],
     'A9_Y' :    [16.45,16.44,16.5,16.61,16.59,16.52,16.52,16.43,16.45,16.49],
     'A10_X' :   [-15.18,-15.18,-15.18,-15.18,-15.18,-15.18,-15.18,-15.18,-15.18,-15.18],
     'A10_Y' :   [26.02,26.02,26.02,26.02,26.02,26.02,26.02,26.02,26.02,26.02],
     'A11_X' :   [15.5,15.22,14.9,14.59,14.36,14.08,13.74,13.43,13.13,12.82],
     'A11_Y' :   [7.25,7.36,7.51,7.61,7.72,7.88,8.05,8.18,8.5,8.8],
     'A12_X' :   [-5.36,-5.35,-5.33,-5.28,-5.18,-5.12,-4.99,-4.83,-4.8,-4.71],
     'A12_Y' :   [19.02,18.77,18.56,18.41,18.22,18.03,17.9,17.72,17.69,17.58],
     'A13_X' :   [-45.76,-45.91,-46.13,-46.41,-46.62,-46.82,-47.07,-47.35,-47.61,-47.87],
     'A13_Y' :   [18.9,18.96,19.03,19.12,19.12,19.18,19.31,19.42,19.45,19.53],
     'A14_X' :   [-10.28,-10.3,-10.23,-10.36,-10.53,-10.69,-10.84,-10.95,-11.17,-11.37],
     'A14_Y' :   [18.25,18.42,18.56,18.73,18.86,18.98,19.02,19.19,19.3,19.46],
     'A15_X' :   [29.77,29.6,29.45,29.24,28.9,28.68,28.42,28.06,27.75,27.49],
     'A15_Y' :   [11.59,11.38,11.19,11.02,10.85,10.71,10.58,10.39,10.18,9.98],
     'B1_X' :    [38.35,38.1,37.78,37.55,37.36,37.02,36.78,36.46,36.21,35.79],
     'B1_Y' :    [12.55,12.58,12.58,12.55,12.5,12.47,12.43,12.48,12.44,12.44],
     'B2_X' :    [14.6,14.38,14.16,13.8,13.45,13.11,12.71,12.3,12.06,11.61],
     'B2_Y' :    [4.66,4.44,4.24,4.1,4.01,3.84,3.67,3.56,3.44,3.47],
     'B3_X' :    [-12.16,-12.35,-12.53,-12.73,-12.91,-13.01,-13.24,-13.44,-13.68,-13.93],
     'B3_Y' :    [20.07,20.26,20.34,20.5,20.62,20.69,20.72,20.73,20.63,20.58],
     'B4_X' :    [-3.27,-3.1,-2.83,-2.49,-2.34,-2.13,-1.97,-1.8,-1.67,-1.59],
     'B4_Y' :    [-6.25,-6.37,-6.52,-6.61,-6.76,-6.89,-7.01,-7.1,-7.13,-7.33],
     'B5_X' :    [-21.47,-21.63,-21.84,-22.03,-22.28,-22.53,-22.77,-22.99,-23.27,-23.52],
     'B5_Y' :    [8.94,8.87,8.79,8.68,8.61,8.56,8.48,8.35,8.22,8.12],
     'B6_X' :    [-13.81,-13.83,-13.91,-14.02,-14.15,-14.31,-14.54,-14.77,-14.96,-15.24],
     'B6_Y' :    [25.45,25.81,25.94,26.26,26.56,26.75,26.92,27.07,27.22,27.25],
     'B7_X' :    [-6.28,-6.33,-6.43,-6.44,-6.61,-6.8,-7.02,-7.22,-7.46,-7.7],
     'B7_Y' :    [13.82,13.6,13.43,13.26,13.12,13.09,13.07,13.14,13.19,13.32],
     'B8_X' :    [28.39,28.09,27.91,27.76,27.4,27.14,26.91,26.69,26.34,26.1],
     'B8_Y' :    [8.36,8.2,8.13,8.1,8.01,7.94,7.84,7.76,7.8,7.84],
     'B9_X' :    [-7.55,-7.54,-7.57,-7.65,-7.77,-7.87,-8.01,-8.06,-8.06,-8.06],
     'B9_Y' :    [17.98,17.94,17.97,18.02,18.05,18.09,18.07,18.02,17.97,17.92],
     'B10_X' :   [-32.36,-32.63,-32.92,-33.25,-33.54,-33.78,-34.13,-34.37,-34.69,-35.01],
     'B10_Y' :   [13.27,13.48,13.67,13.9,14.14,14.48,14.76,15.05,15.31,15.62],
     'B11_X' :   [-44.08,-44.19,-44.33,-44.47,-44.64,-44.78,-44.92,-45.16,-45.36,-45.56],
     'B11_Y' :   [15.9,16.09,16.22,16.38,16.49,16.63,16.7,16.79,16.85,16.94],
     'B12_X' :   [-16.47,-16.67,-16.76,-16.86,-16.99,-17.24,-17.48,-17.76,-17.98,-18.29],
     'B12_Y' :   [29.76,29.96,30.07,30.3,30.45,30.59,30.61,30.67,30.62,30.66],
     'B13_X' :   [-50.27,-50.38,-50.55,-50.74,-50.92,-51.02,-51.13,-51.3,-51.46,-51.65],
     'B13_Y' :   [16.31,16.3,16.31,16.33,16.36,16.28,16.25,16.22,16.21,16.27],
     'B14_X' :   [-15.55,-15.81,-16.05,-16.35,-16.67,-16.96,-17.35,-17.76,-18.09,-18.6],
     'B14_Y' :   [8.56,8.53,8.54,8.57,8.62,8.6,8.58,8.49,8.44,8.55],
     'B15_X' :   [9.79,9.47,9.2,8.77,8.41,8.07,7.65,7.19,6.76,6.42],
     'B15_Y' :   [27.61,27.79,27.99,28.16,28.37,28.53,28.68,28.82,28.9,29.06],
     'A1_Radius' :  [10.33,10.34,10.34,10.37,10.38,10.37,10.36,10.36,10.35,10.35],
     'A2_Radius' :  [9.05,9.06,9.07,9.08,9.09,9.09,9.08,9.06,9.05,9.04],
     'A3_Radius' :  [13.04,13.15,13.29,13.44,13.6,13.72,13.88,14.1,14.31,14.52],
     'A4_Radius' :  [25,25,25,25,25,25,25,25,25,24.81],
     'A5_Radius' :  [11.24,11.33,11.44,11.49,11.59,11.68,11.77,11.86,11.95,12.02],
     'A6_Radius' :  [8.19,8.19,8.18,8.17,8.15,8.14,8.13,8.11,8.11,8.09],
     'A7_Radius' :  [8.18,8.19,8.2,8.21,8.22,8.25,8.27,8.29,8.31,8.33],
     'A8_Radius' :  [9.71,9.79,9.85,9.94,10.05,10.17,10.26,10.38,10.53,10.65],
     'A9_Radius' :  [25,25,25,25,25,25,25,25,25,25],
     'A10_Radius' : [9.08,9.08,9.08,9.08,9.08,9.08,9.08,9.08,9.08,9.08],
     'A11_Radius' : [11.12,11.03,10.91,10.81,10.74,10.64,10.54,10.45,10.34,10.23],
     'A12_Radius' : [8.07,8.06,8.05,8.05,8.04,8.03,8.02,8.01,8.01,8.01],
     'A13_Radius' : [24.16,24.36,24.62,24.98,25,25,25,25,25,25],
     'A14_Radius' : [8.3,8.3,8.3,8.31,8.32,8.33,8.34,8.35,8.37,8.39],
     'A15_Radius' : [17.86,17.75,17.66,17.52,17.28,17.14,16.96,16.73,16.53,16.38],
     'B1_Radius' :  [25,25,25,25,25,25,24.84,24.45,24.15,23.65],
     'B2_Radius' :  [11.3,11.28,11.26,11.19,11.11,11.06,10.99,10.91,10.88,10.77],
     'B3_Radius' :  [8.46,8.48,8.5,8.52,8.54,8.55,8.57,8.59,8.61,8.63],
     'B4_Radius' :  [11.54,11.59,11.65,11.69,11.75,11.81,11.86,11.9,11.92,12],
     'B5_Radius' :  [10.08,10.13,10.18,10.24,10.3,10.37,10.43,10.5,10.59,10.66],
     'B6_Radius' :  [8.89,8.92,8.94,8.98,9.02,9.06,9.1,9.14,9.18,9.21],
     'B7_Radius' :  [8.19,8.2,8.22,8.23,8.24,8.24,8.25,8.25,8.26,8.26],
     'B8_Radius' :  [17.34,17.15,17.03,16.93,16.69,16.52,16.38,16.25,16.01,15.84],
     'B9_Radius' :  [8.13,8.13,8.14,8.14,8.15,8.15,8.16,8.16,8.16,8.16],
     'B10_Radius' : [13.38,13.5,13.64,13.8,13.94,14.05,14.23,14.35,14.53,14.7],
     'B11_Radius' : [22.24,22.35,22.5,22.65,22.84,23,23.16,23.44,23.67,23.9],
     'B12_Radius' : [9.68,9.74,9.77,9.82,9.86,9.92,9.96,10.02,10.05,10.1],
     'B13_Radius' : [25,25,25,25,25,25,25,25,25,25],
     'B14_Radius' : [9.17,9.2,9.23,9.26,9.3,9.34,9.4,9.47,9.52,9.59],
     'B15_Radius' : [9.8,9.76,9.74,9.7,9.67,9.63,9.59,9.55,9.5,9.48],
     'A1_Scaling' : [0,0.07,0.1,0.09,0.06,0.1,0.09,0.05,0.07,0.08],
     'A2_Scaling' : [0,0.01,0.01,0.02,0.06,0.03,0.04,0.07,0.03,0.04],
     'A3_Scaling' : [0,0.07,0.06,0.08,0.09,0.05,0.07,0.11,0.1,0.09],
     'A4_Scaling' : [0,0.01,0.01,0.02,0.02,0.03,0.03,0.02,0.03,0.04],
     'A5_Scaling' : [0,0.05,0.05,0.02,0.04,0.04,0.07,0.05,0.07,0.04],
     'A6_Scaling' : [0,0.04,0.05,0.04,0.09,0.05,0.09,0.12,0.07,0.21],
     'A7_Scaling' : [0,0.04,0.06,0.05,0.03,0.13,0.1,0.07,0.08,0.11],
     'A8_Scaling' : [0,0.08,0.06,0.09,0.16,0.16,0.08,0.14,0.19,0.12],
     'A9_Scaling' : [0,0.01,0.01,0.02,0.01,0.02,0.03,0.03,0.02,0.03],
     'A10_Scaling' :    [0,0,0,0,0,0,0,0,0,0],
     'A11_Scaling' :    [0,0.05,0.07,0.06,0.04,0.06,0.09,0.06,0.11,0.11],
     'A12_Scaling' :    [0,0.04,0.03,0.02,0.02,0.02,0.02,0.03,0,0.01],
     'A13_Scaling' :    [0,0.02,0.03,0.05,0.03,0.03,0.05,0.05,0.04,0.04],
     'A14_Scaling' :    [0,0.02,0.02,0.03,0.03,0.02,0.01,0.03,0.03,0.04],
     'A15_Scaling' :    [0,0.04,0.03,0.04,0.08,0.04,0.05,0.1,0.08,0.06],
     'B1_Scaling' : [0,0.04,0.06,0.03,0.02,0.07,0.04,0.06,0.04,0.11],
     'B2_Scaling' : [0,0.06,0.05,0.09,0.08,0.08,0.11,0.1,0.04,0.12],
     'B3_Scaling' : [0,0.04,0.02,0.04,0.03,0.01,0.03,0.02,0.04,0.04],
     'B4_Scaling' : [0,0.03,0.06,0.07,0.03,0.03,0.02,0.02,0.01,0.03],
     'B5_Scaling' : [0,0.02,0.03,0.03,0.04,0.04,0.04,0.04,0.06,0.04],
     'B6_Scaling' : [0,0.08,0.01,0.07,0.06,0.04,0.05,0.05,0.04,0.05],
     'B7_Scaling' : [0,0.03,0.02,0.02,0.03,0.02,0.03,0.02,0.04,0.04],
     'B8_Scaling' : [0,0.07,0.02,0.01,0.08,0.04,0.04,0.03,0.07,0.04],
     'B9_Scaling' : [0,0,0,0.01,0.01,0.01,0.01,0,0,0],
     'B10_Scaling' :    [0,0.07,0.07,0.09,0.08,0.11,0.12,0.09,0.1,0.11],
     'B11_Scaling' :    [0,0.03,0.02,0.03,0.03,0.02,0.02,0.04,0.03,0.03],
     'B12_Scaling' :    [0,0.05,0.01,0.04,0.02,0.05,0.04,0.05,0.03,0.05],
     'B13_Scaling' :    [0,0.01,0.02,0.02,0.02,0.01,0.01,0.02,0.01,0.02],
     'B14_Scaling' :    [0,0.04,0.04,0.05,0.06,0.05,0.09,0.1,0.07,0.16],
     'B15_Scaling' :    [0,0.08,0.06,0.13,0.1,0.08,0.11,0.14,0.12,0.08],           
     'A1_Rotation' :    [0,112.81,114.01,110.56,110.6,113.37,116.02,116.99,118.62,119.38],
     'A2_Rotation' :    [0,-94.27,-73.02,-87.73,-98.57,-102.94,-111.2,-119.95,-122.41,-124.66],
     'A3_Rotation' :    [0,128.47,135.84,134.06,134.75,133.94,134.69,136.59,137.5,138.85],
     'A4_Rotation' :    [0,164.64,165.45,163.48,161.42,160.63,161.31,162.54,164.99,167.17],
     'A5_Rotation' :    [0,-78.78,-81.19,-87.73,-92.23,-92.33,-101.96,-105.48,-111.09,-114.38],
     'A6_Rotation' :    [0,43.84,48.03,59.34,66.72,67.83,69.48,72.62,72.2,77.81],
     'A7_Rotation' :    [0,131.01,141.7,138.59,138.53,137.8,137.64,136.12,136.75,139.03],
     'A8_Rotation' :    [0,-127.32,-123.16,-125.78,-133.66,-135.66,-137.83,-138.76,-139.64,-141.01],
     'A9_Rotation' :    [0,-173.6,166.75,154.39,162.16,173.26,175.63,-178.69,-179.76,178.52],
     'A10_Rotation' :   [0,0,0,0,0,0,0,0,0,0],
     'A11_Rotation' :   [0,159.85,156.67,158.48,157.77,156.11,155.54,155.77,152.28,149.97],
    'A12_Rotation' :    [0,-87.73,-86.34,-82.59,-77.52,-76.38,-71.91,-67.87,-66.98,-65.81],
     'A13_Rotation' :   [0,157.86,160.03,161.3,165.63,165.1,162.84,162.02,163.42,163.4],
     'A14_Rotation' :   [0,96.06,80.08,98.93,112.07,119.3,125.62,125.42,130.18,131.8],
     'A15_Rotation' :   [0,-128.97,-128.41,-133.2,-139.65,-141,-143.05,-144.79,-145.08,-144.84],
     'B1_Rotation' :    [0,172.04,176.94,179.74,-177.22,-176.59,-175.81,-178,-177.26,-177.53],
     'B2_Rotation' :    [0,-135.52,-136.05,-144.97,-150.41,-151.25,-152.35,-154.52,-154.34,-158.27],
     'B3_Rotation' :    [0,136.51,144.7,143.29,144.27,144.21,149.19,152.95,159.91,164.19],
     'B4_Rotation' :    [0,-34.26,-30.8,-24.57,-28.69,-29.15,-30.36,-29.83,-28.55,-32.58],
     'B5_Rotation' :    [0,-157.4,-157.25,-155.34,-157.7,-160.03,-160.33,-158.82,-158.14,-158.21],
     'B6_Rotation' :    [0,92.27,101.22,104.5,106.63,110.85,116.25,120.35,122.84,128.35],
     'B7_Rotation' :    [0,-105.22,-111.46,-106.51,-115.8,-125.96,-134.82,-144.07,-152.07,-160.76],
     'B8_Rotation' :    [0,-151.19,-154.33,-157.13,-160.12,-161.43,-160.74,-160.39,-164.53,-167.14],
     'B9_Rotation' :    [0,-73.61,-155.92,158.51,161.67,160.64,169.2,175.38,-178.71,-172.8],                         
     'B10_Rotation' :   [0,142.69,144.41,144.93,143.57,139.61,139.91,138.54,138.86,138.47],
     'B11_Rotation' :   [0,119.54,127.13,128.87,133.1,133.59,136.35,140.45,143.34,144.72],
     'B12_Rotation' :   [0,134.03,132.68,125.29,126.67,132.59,139.67,144.84,150.2,153.44],
     'B13_Rotation' :   [0,-177.72,178.64,176.87,175.25,-177.73,-175.96,-175.29,-175.61,-178.46],
     'B14_Rotation' :   [0,-173.78,-177.74,179.11,176.83,178.31,179.19,-178.19,-177.33,-179.89],
     'B15_Rotation' :   [0,152.39,147.79,151.7,151.38,151.96,153.65,155.22,157.01,156.86],
     })

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 = 200
delay_ms = 1000
ani = FuncAnimation(fig, plotmvs, frames=df.groupby('time'),
                blit=True, interval=interval_ms, repeat_delay=delay_ms)

plt.show()
14
  • 7
    The question has been viewed 60 times. I don't think the reason you did not get an answer is that it has not received enough attention. Rather, it's really hard to understand what you are trying to achieve and where the problem lies. Commented Mar 26, 2019 at 21:13
  • @ImportanceOfBeingErnest, I've tried to add a greater description. Can you see the video in the animation provided. If so, you can see the probability (referenced as the changing colormap) dynamically change throughout. The probability should only change based off the radius. Does this make sense Commented Mar 27, 2019 at 9:05
  • 1
    Try making a more minimal example showing: a) what you have and b) what you are trying to achieve. People will pay more attention if they can quickly evaluate what you want. Make a very small example dataset we can copy, show a small example of what you are trying to do. Then show (hopefully with a picture) why it doesn't work. Commented Mar 27, 2019 at 10:01
  • Thanks @FChm. I have cut the code that is superfluous but everything else is essential to the functionality. If I cut some functions it wouldn't operate as I need it to. I'll add descriptions of each function to make the process easier to follow. Commented Mar 27, 2019 at 11:24
  • The link to the animation is broken. Commented Mar 29, 2019 at 7:36

1 Answer 1

1
+50

Your problem is not actually with the spatial extent of your probability distribution functions, but rather with the normalisation you use to display your composition functions. In particular, as a value of zero should mean zero probability and it is of course favourable if that value is tied to the same colour in each frame. The normalisation you use in your code, namely

normPDF = PDF - PDF.min()
normPDF = normPDF / normPDF.max()

does not guarantee this property. As an example, consider the min and max values of PDF to be -0.8 and 0.9, respectively. After the transformation, the min and max values of normPDF will 0 and 1, i.e. you transformation would do -0.8 --> 0 and 0.9 --> 1. At the same time the original zero probability is also being transformed: 0 --> 0.8/(0.9+0.8) = 0.47058823529411764. Because your distribution functions change in every frame, also their maximum values change and hence your zero probability will be transformed to a different value in each frame.

To avoid this, it is better to use a normalisation that conserves your zero probability. The easiest transformation that comes to mind is the one that normalises the probability to the interval [-1,1] (-1 because you subtract to probability distributions from each other), which can be achieved my dividing the distribution by the maximum probability:

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

With this normalisation, no value in normPDF is ever smaller than -1 or greater than 1. Note, however, that normPDF does not necessarily span all values from -1 to 1, but it is rather confined to these values. Additionally, zero probability stays always zero by definition. Now that the distribution is normalised, we still need to take care that the zero probability is always assigned the same colour. This can be done by telling contourf what the levels of the contour plot should be. This can be done using the keyword levels, which can either be an integer (then only the amount of contours is fixed; not enough here) or an iterable that contains all desired levels. The easiest would be equally spaced levels and np.linspace(-1,1,n), with n being the amount of levels you want, will draw levels only between the normalisation limits:

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

A word of caution: If you do perform normalisation separately for each frame, as it is done in your code now, the values (except 0) that are assigned to certain colours will most likely change from frame to frame. This is because the min and max values of your PDFs change. If you mean to also show a colorbar next to the plot, you will have to update the colorbar for each frame as well. However, this would make the animation rather hard to follow. Instead I would suggest to first calculate the PDFs for all frames, compute the max values for all frames and then normalise all frames at once with this 'global' maximum value. This way you need to draw your colorbar only once.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks @ThomasKuhn. This is fantastic. Your word of caution is especially pertinent. This was going to be my next question. Is it possible to fix the max value for all frames so the same probability is assigned?
@jonboy I'm not quite sure I understand. By definition the bivariate distribution should be normalised such that the 2d integral over the distribution is equal to one. If you sum up several bivariate distributions, the 2d integral over that sum should then be equal to the number of distributions you summed over. If you normalise your distribution differently, this is, of course, not true anymore. I guess my question here is, what are you actually after?
This may need to be a separate question but I want the normalisation to be consistent across all frames. As you mentioned the colours assigned to certain values change. Is it possible to calculate the PDFs for all frames and return the max value?
@jonboy sorry for being slow: it should be possible to do what you are after if you break up your code into two loops. The first one would calculate the pdf's for all your frames and store them in an array and the second loop would take care of the normalisation and visualisation. Let me know if you need some explicit example.
Thanks @Thomas Kuhn. I can reopen a separate question if necessary. I better understand your comment. So I would alter my plotmvs function to return the max contour value and then use that in a separate function to normalise the PDF's?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.