Example #1
0
def measurementUpdate(meas, sm, s, curs, goals):

    origLen = len(s)

    s = np.array(s)
    curs = np.array(curs)
    goals = np.array(goals)
    sm = Softmax()
    # sm.buildRectangleModel([[1,5],[3,7]],steepness=7);
    sm.buildOrientedRecModel([2000, -2000], 0, 1, 1, steepness=7)

    weights = [sm.pointEvalND(meas, s[i]) for i in range(0, len(s))]

    weights /= np.sum(weights)

    csum = np.cumsum(weights)
    csum[-1] = 1

    indexes = np.searchsorted(csum, np.random.random(len(s)))
    s[:] = s[indexes]
    curs[:] = curs[indexes]
    goals[:] = goals[indexes]

    return s, curs, goals
Example #2
0
class Sketch:

    def __init__(self, params, seed=None):
        if(seed is not None):
            np.random.seed(seed)

        self.name = params['name']
        self.centroid = params['centroid']
        if(params['points'] is not None):
            self.points = params['points']; 
        else:
            self.points = self.generateSketch(params)
        self.inflated = self.inflatePoints(params)
        self.labels = ['East', 'NorthEast', 'North', 'NorthWest',
                       'West', 'SouthWest', 'South', 'SouthEast']
        self.sm = Softmax()
        self.sm.buildPointsModel(self.points, steepness=params['steepness'])
        self.sm_inf = Softmax()
        self.sm_inf.buildPointsModel(
            self.inflated, steepness=params['steepness'])
        [self.joint, self.con_class, self.con_label] = self.labelClasses()

    def displayClasses(self, show=True):
        fig = plt.figure()
        [x, y, c] = self.sm.plot2D(low=[0, 0], high=[10, 10], vis=False)
        [x_inf, y_inf, c_inf] = self.sm_inf.plot2D(
            low=[0, 0], high=[10, 10], vis=False)

        c_inf = np.array(c_inf)
        c_inf[c_inf == 0] = 10
        c_inf[c_inf < 10] = 0

        plt.contourf(x_inf, y_inf, c_inf, cmap="Reds", alpha=1)
        plt.contourf(x, y, c, cmap="Blues", alpha=0.5)

        cid = fig.canvas.mpl_connect(
            'button_press_event', self.onclick_classes)

        if(show):
            plt.show()

    def onclick_classes(self, event):
        # print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
        #       ('double' if event.dblclick else 'single', event.button,
        #        event.x, event.y, event.xdata, event.ydata))
        print("Point Selected: [{:.2f},{:.2f}]".format(
            event.xdata, event.ydata))
        point = [event.xdata, event.ydata]
        if(event.dblclick):
            class_test = np.zeros(shape=(self.sm.size))
            for i in range(0, len(class_test)):
                class_test[i] = self.sm.pointEvalND(i, point)

            # print(class_test)

            ans = {}
            for l in self.labels:
                ans[l] = 0
                for i in range(0, len(class_test)):
                    te = self.con_label[i]
                    ans[l] += self.con_label[i][l]*class_test[i]

            suma = sum(ans.values())
            for k in ans.keys():
                ans[k] /= suma

            print("Outputing all label probabilities:")
            for k, v in ans.items():
                if(v > 0.009):
                    print("P: {:0.2f}, L: {}".format(v, k))

        else:
            # Find just most likely class
            # Check all softmax classes

            # Check if it's near
            near = ""
            near_test = np.zeros(shape=(self.sm_inf.size))
            for i in range(0, len(near_test)):
                near_test[i] = self.sm_inf.pointEvalND(i, point)
            if(np.argmax(near_test) == 0):
                near = 'Near'

            # Check other classes
            class_test = np.zeros(shape=(self.sm.size))
            for i in range(0, len(class_test)):
                class_test[i] = self.sm.pointEvalND(i, point)

            best = np.argmax(class_test)
            if(best == 0):
                near = ""
                best_lab = "Inside"
            else:
                te = self.con_label[best]
                best_lab = max(te, key=te.get)

            print("Most Likely Class: {}".format(near + " " + best_lab))
            print("")

    def giveMostLikelyClass(self,point):
        near = ""
        near_test = np.zeros(shape=(self.sm_inf.size))
        for i in range(0, len(near_test)):
            near_test[i] = self.sm_inf.pointEvalND(i, point)
        if(np.argmax(near_test) == 0):
            near = 'Near'

        # Check other classes
        class_test = np.zeros(shape=(self.sm.size))
        for i in range(0, len(class_test)):
            class_test[i] = self.sm.pointEvalND(i, point)

        best = np.argmax(class_test)
        if(best == 0):
            near = ""
            best_lab = "Inside"
        else:
            te = self.con_label[best]
            best_lab = max(te, key=te.get)
        res = near + " " + best_lab; 
        return res

    def giveProbabilities(self,point):
        class_test = np.zeros(shape=(self.sm.size))
        for i in range(1, len(class_test)):
            class_test[i] = self.sm.pointEvalND(i, point)

        # print(class_test)

        ans = {}
        for l in self.labels:
            ans[l] = 0
            for i in range(1, len(class_test)):
                te = self.con_label[i]
                ans[l] += self.con_label[i][l]*class_test[i]
        ans['Inside'] = self.sm.pointEvalND(0,point); 

        suma = sum(ans.values())
        for k in ans.keys():
            ans[k] /= suma

        return ans; 

    def giveNearProb(self,point):
        near_test = np.zeros(shape=(self.sm_inf.size))
        for i in range(0, len(near_test)):
            near_test[i] = self.sm_inf.pointEvalND(i, point)
        return near_test; 


    def answerQuestion(self,point,label,thresh = .8):
        # res = self.giveMostLikelyClass(point)
        # if(res == label):

        ##################################################
        #TODO: Integrate Camera Positions
        ##################################################

        probs = self.giveProbabilities(point); 
        maxi = max(probs.values()); 
        for k in probs.keys():
            probs[k] /= maxi; 

        if(label == "Near"):
            nearProb = self.giveNearProb(point); 
            if(np.argmax(nearProb) == 0):
                return 'Yes'
            else:
                return 'No'
        elif("Near" in label):
            spl = label.split(); 
            nearProb = self.giveNearProb(point); 
            if(probs[spl[1]] > thresh and np.argmax(nearProb) == 0):
                return 'Yes'
            else:
                return 'No'
        elif(probs[label] > thresh):
            
            return 'Yes'; 
        else: 
            return 'No'; 


    def displayProbTables(self, show=True):
        plt.figure()

        matProb = np.zeros(shape=(self.sm.size, len(self.labels)+1))

        # For every class
        for i in range(0, len(self.con_label)):
            # normalize across self.con_label
            c = self.con_label[i]
            for j in range(0, len(self.labels)):
                matProb[i, j+1] = c[self.labels[j]]
        matProb[0, :] = 0
        matProb[0, 0] = 1

        plt.imshow(matProb, cmap='inferno')
        plt.xticks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], ['Inside', 'East', 'NorthEast',
                                                    'North', 'NorthWest', 'West', 'SouthWest', 'South', 'SouthEast'], rotation=90)
        plt.title("Conditional p(label | class)")
        plt.ylabel("Softmax Class")
        plt.colorbar()

        plt.figure()
        matProb = np.zeros(shape=(self.sm.size, len(self.labels)+1))

        # For every class
        for i in range(0, len(self.con_class)):
            # normalize across self.con_class
            c = self.con_class[i]
            for j in range(0, len(self.labels)):
                matProb[i, j+1] = c[self.labels[j]]
        matProb[0, :] = 0
        matProb[0, 0] = 1

        plt.imshow(matProb, cmap='inferno')
        plt.xticks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], ['Inside', 'East', 'NorthEast',
                                                    'North', 'NorthWest', 'West', 'SouthWest', 'South', 'SouthEast'], rotation=90)
        plt.title("Conditional p(class | label)")
        plt.ylabel("Softmax Class")
        plt.colorbar()

        if(show):
            plt.show()

    def displayPoints(self, show=True):
        plt.figure()
        plt.scatter(self.points[:, 0], self.points[:, 1])

        if(show):
            plt.show()

    def generateSketch(self, params):

        # given a point, spread rays out in random directions with semi random distance, and a random number of points

        # Tuning Paramters
        ####################################
        centroid = params['centroid']
        dist_nom = params['dist_nom']
        dist_noise = params['dist_noise']
        angle_noise = params['angle_noise']
        pois_mean = params['pois_mean']
        ####################################

        # Fixed Parameters
        ####################################
        # Has to be at least a triangle
        pois_min = 3
        ####################################

        # Chose Number of Points from Poisson Distribution
        numVerts = np.random.poisson(pois_mean)+pois_min

        # Debugging
        # numVerts = min(numVerts, 5)

        points = []

        # Note: Angles must preserve order
        totalAngle = 0
        # Precompute angles
        allAngles = np.zeros(numVerts)
        for i in range(0, numVerts):
            totalAngle += 2*np.pi/numVerts + np.random.normal(0, angle_noise)
            allAngles[i] = totalAngle

        # Normalize and expand to 2pi
        allAngles /= totalAngle
        allAngles *= 1.999*np.pi

        for i in range(0, numVerts):
            h = dist_nom + np.random.normal(0, dist_noise)
            points.append([h*np.cos(allAngles[i])+centroid[0],
                           h*np.sin(allAngles[i])+centroid[1]])

        points = np.array(points)

        cHull = ConvexHull(points)
        points = points[cHull.vertices]

        return points

    def inflatePoints(self, params):

        # Tuning Paramters
        ####################################
        area_multiplier = params['area_multiplier']
        ####################################

        ske = Polygon(self.points)

        ske2 = affinity.scale(ske, xfact=np.sqrt(
            area_multiplier), yfact=np.sqrt(area_multiplier))

        inflation = np.array(ske2.exterior.coords.xy).T

        return inflation

    def findLabels(self, point, centroid):
        # point must first be normalized with respect to centroid
        pprime = [point[0] - centroid.x, point[1] - centroid.y]

        ang = np.arctan2(pprime[1], pprime[0])*180/np.pi

        if(ang < 0):
            ang += 360

        allLabels = []

        # Off-Axial
        if(ang < 90):
            allLabels.append("NorthEast")
        elif(ang < 180):
            allLabels.append("NorthWest")
        elif(ang < 270):
            allLabels.append("SouthWest")
        elif(ang <= 360):
            allLabels.append("SouthEast")

        # On-Axial
        if(ang < 45):
            allLabels.append("East")
        elif(ang < 135):
            allLabels.append("North")
        elif(ang < 225):
            allLabels.append("West")
        elif(ang < 315):
            allLabels.append("South")
        elif(ang < 360):
            allLabels.append("East")
        return allLabels

    def labelClasses(self):

        # Take a ring of points, around centroid of object
        # For each point, identify it's cardinal direction, can be multiple levels
        # For each class, add together eval at points into direction labels
        # Normalize direction labels, and you have a soft classification of each class
        # Maybe threshold during normalization

        # Returns:
        # Joint probability dirLabs
        # Conditional p(class|labs)
        # Conditional p(labs|class)

        ske = Polygon(self.points)
        # print(ske.centroid)
        cent = ske.centroid
        hfactor = 3
        ra = hfactor*np.sqrt(ske.area/np.pi)

        # Direction Percentages
        dirLabs = []
        for i in range(0, len(self.points)+1):
            dirLabs.append({"West": 0, "East": 0, "North": 0, "South": 0,
                            "SouthWest": 0, "NorthWest": 0, "NorthEast": 0, "SouthEast": 0})

        numDegrees = 360
        testPoints = []
        for i in range(0, numDegrees):
            testPoints.append([ra*np.cos((i/numDegrees)*360 * np.pi/180)+cent.x,
                               ra*np.sin((i/numDegrees)*360 * np.pi/180)+cent.y])
        # for i in range(0,10000):
        #     testPoints.append([np.random.random()*10,np.random.random()*10])

        testPoints = np.array(testPoints)

        suma = 0
        # For each point
        for t in testPoints:
            # Find its labels
            labs = self.findLabels(t, cent)
            # Now apply to each class
            for c in range(0, self.sm.size):
                # eval
                tmp = self.sm.pointEvalND(c, t)
                for l in labs:
                    # add to dirLabs[c][l]
                    dirLabs[c][l] += tmp
                    suma += tmp

        # Normalize dirlabs to obtain p(class,label)
        for c in dirLabs:
            for k in c.keys():
                c[k] /= suma
            # print(c)

        cond_classes = deepcopy(dirLabs)
        labs = self.labels

        # For every class
        for i in range(0, len(cond_classes)):
            # normalize across labels
            c = cond_classes[i]
            suma = 0
            for k, v in c.items():
                suma += v
            for key in c.keys():
                c[key] /= suma

        cond_labs = deepcopy(dirLabs)

        for l in labs:
            suma = 0
            for c in cond_labs:
                suma += c[l]
            for c in cond_labs:
                c[l] /= suma

        return dirLabs, cond_classes, cond_labs
Example #3
0
def make3DSoftmaxAnimation():
    dims = 3

    #Trapezoidal Pyramid Specs
    numClasses = 7
    boundries = [[1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0]]
    B = np.matrix([
        0, 0, -1, -2, -1, 0, .5, -2, 0, 1, .5, -2, 1, 0, .5, -2, 0, -1, .5, -2,
        0, 0, 1, -2
    ]).T / 4
    '''
	#Octohedron Specs
	numClasses = 9; 
	boundries = []; 
	for i in range(1,numClasses):
		boundries.append([i,0]); 
	B = np.matrix([-1,-1,0.5,-1,-1,1,0.5,-1,1,1,0.5,-1,1,-1,0.5,-1,-1,-1,-0.5,-1,-1,1,-0.5,-1,1,1,-0.5,-1,1,-1,-0.5,-1]).T; 
	'''

    M = np.zeros(shape=(len(boundries) * (dims + 1), numClasses * (dims + 1)))

    for j in range(0, len(boundries)):
        for i in range(0, dims + 1):
            M[(dims + 1) * j + i, (dims + 1) * boundries[j][1] + i] = -1
            M[(dims + 1) * j + i, (dims + 1) * boundries[j][0] + i] = 1

    A = np.hstack((M, B))

    Theta = linalg.lstsq(M, B)[0].tolist()

    weight = []
    bias = []
    for i in range(0, len(Theta) // (dims + 1)):
        weight.append([
            Theta[(dims + 1) * i][0], Theta[(dims + 1) * i + 1][0],
            Theta[(dims + 1) * i + 2][0]
        ])
        bias.append(Theta[(dims + 1) * i + dims][0])

    steep = 10
    weight = (np.array(weight) * steep).tolist()
    bias = (np.array(bias) * steep).tolist()
    pz = Softmax(weight, bias)

    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.set_xlabel('X Axis')
    ax.set_ylabel('Y Axis')
    ax.set_zlabel('Z Axis')
    ax.set_xlim([-5, 5])
    ax.set_ylim([-5, 5])
    ax.set_zlim([-5, 5])
    #ax.set_title("3D Scatter of Softmax Class Dominance Regions")

    dataClear = np.zeros(shape=(numClasses, 21, 21, 21))
    edgesClear = np.empty(shape=(numClasses, 3, 0)).tolist()
    for clas in range(0, numClasses):
        #-5 to 5 on all dims
        data = np.zeros(shape=(21, 21, 21))
        for i in range(0, 21):
            for j in range(0, 21):
                for k in range(0, 21):
                    dataClear[clas][i][j][k] = pz.pointEvalND(
                        clas, [(i - 10) / 2, (j - 10) / 2, (k - 10) / 2])
                    if (dataClear[clas][i][j][k] > 0.0001):
                        edgesClear[clas][0].append((i - 10) / 2)
                        edgesClear[clas][1].append((j - 10) / 2)
                        edgesClear[clas][2].append((k - 10) / 2)

    count = 0

    allCols = ['b', 'g', 'r', 'c', 'm', 'y', 'w', '#eeefff', '#ffa500']

    edgesZ = np.empty(shape=(numClasses, 20, 3, 0)).tolist()
    #Z Axis

    for slic in range(-10, 10):
        for clas in range(0, 1):
            #-5 to 5 on all dims
            data = np.zeros(shape=(101, 101))
            for i in range(0, 101):
                for j in range(0, 101):
                    data[i][j] = pz.pointEvalND(clas,
                                                [(i - 50) / 10,
                                                 (j - 50) / 10, slic / 5])
                    if (data[i][j] > 0.1):
                        edgesZ[clas][slic + 10][0].append((i - 50) / 10)
                        edgesZ[clas][slic + 10][1].append((j - 50) / 10)
                        edgesZ[clas][slic + 10][2].append(slic / 5)
            ax.cla()
            ax.set_xlabel('X Axis')
            ax.set_ylabel('Y Axis')
            ax.set_zlabel('Z Axis')
            ax.set_xlim([-5, 5])
            ax.set_ylim([-5, 5])
            ax.set_zlim([-5, 5])
            #ax.set_title("3D Scatter of Softmax Class Dominance Regions")
        for i in range(0, numClasses):
            #ax.scatter(edgesClear[i][0],edgesClear[i][1],edgesClear[i][2],alpha=0.15,color=allCols[i]);
            ax.scatter(edgesZ[i][slic + 10][0],
                       edgesZ[i][slic + 10][1],
                       edgesZ[i][slic + 10][2],
                       color=allCols[i])

        fig.savefig(os.path.dirname(__file__) + '/tmp/img' + str(count) +
                    ".png",
                    bbox_inches='tight',
                    pad_inches=0)
        count += 1
        plt.pause(0.1)
    '''
	#X axis
	for slic in range(-10,10):
		shapeEdgesX = []; 
		shapeEdgesY = [];
		shapeEdgesZ = [];
		#-5 to 5 on all dims
		data = np.zeros(shape=(101,101)); 
		for i in range(0,101):
			for j in range(0,101):
					data[i][j] = pz.pointEvalND(0,[slic/5,(i-50)/10,(j-50)/10]);
					if(data[i][j] > 0.0001):
						shapeEdgesY.append((i-50)/10); 
						shapeEdgesZ.append((j-50)/10); 
						shapeEdgesX.append(slic/5);   
		ax.cla(); 
		ax.set_xlabel('X Axis'); 
		ax.set_ylabel('Y Axis'); 
		ax.set_zlabel('Z Axis'); 
		ax.set_xlim([-5,5]); 
		ax.set_ylim([-5,5]); 
		ax.set_zlim([-5,5]); 
		#ax.set_title("3D Scatter of Softmax Class Dominance Regions")
		ax.scatter(shapeEdgesXClear,shapeEdgesYClear,shapeEdgesZClear,alpha=0.01,color='b')
		ax.scatter(shapeEdgesX,shapeEdgesY,shapeEdgesZ,color='k'); 
		fig.savefig(os.path.dirname(__file__) + '/tmp/img'+str(count)+".png",bbox_inches='tight',pad_inches=0);
		count+=1;  
		plt.pause(0.1); 

	#Y axis
	for slic in range(-10,10):
		shapeEdgesX = []; 
		shapeEdgesY = [];
		shapeEdgesZ = [];
		#-5 to 5 on all dims
		data = np.zeros(shape=(101,101)); 
		for i in range(0,101):
			for j in range(0,101):
					data[i][j] = pz.pointEvalND(0,[(i-50)/10,slic/5,(j-50)/10]);
					if(data[i][j] > 0.0001):
						shapeEdgesX.append((i-50)/10); 
						shapeEdgesZ.append((j-50)/10); 
						shapeEdgesY.append(slic/5);   
		ax.cla(); 
		ax.set_xlabel('X Axis'); 
		ax.set_ylabel('Y Axis'); 
		ax.set_zlabel('Z Axis'); 
		ax.set_xlim([-5,5]); 
		ax.set_ylim([-5,5]); 
		ax.set_zlim([-5,5]); 
		#ax.set_title("3D Scatter of Softmax Class Dominance Regions")
		ax.scatter(shapeEdgesXClear,shapeEdgesYClear,shapeEdgesZClear,alpha=0.01,color='b')
		ax.scatter(shapeEdgesX,shapeEdgesY,shapeEdgesZ,color='k'); 
		fig.savefig(os.path.dirname(__file__) + '/tmp/img'+str(count)+".png",bbox_inches='tight',pad_inches=0);
		count+=1;  
		plt.pause(0.1); 
	'''
    #Animate Results
    fig, ax = plt.subplots()
    images = []
    for k in range(0, count):
        fname = os.path.dirname(__file__) + '/tmp/img%d.png' % k
        img = mgimg.imread(fname)
        imgplot = plt.imshow(img)
        plt.axis('off')
        images.append([imgplot])
    ani = animation.ArtistAnimation(fig, images, interval=20)
    ani.save('trapezoidalAllClass3.gif', fps=3, writer='animation.writer')
Example #4
0
def slice3DModel():
    steep = 1

    dims = 3

    #Trapezoidal Pyramid Specs
    numClasses = 7
    boundries = [[1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0]]
    B = np.matrix([
        0, 0, -1, -2, -1, 0, .5, -2, 0, 1, .5, -2, 1, 0, .5, -2, 0, -1, .5, -2,
        0, 0, 1, -1
    ]).T
    '''
	#Octohedron Specs
	numClasses = 9; 
	boundries = []; 
	for i in range(1,numClasses):
		boundries.append([i,0]); 
	B = np.matrix([-1,-1,0.5,-1,-1,1,0.5,-1,1,1,0.5,-1,1,-1,0.5,-1,-1,-1,-0.5,-1,-1,1,-0.5,-1,1,1,-0.5,-1,1,-1,-0.5,-1]).T; 
	'''

    M = np.zeros(shape=(len(boundries) * (dims + 1), numClasses * (dims + 1)))

    for j in range(0, len(boundries)):
        for i in range(0, dims + 1):
            M[(dims + 1) * j + i, (dims + 1) * boundries[j][1] + i] = -1
            M[(dims + 1) * j + i, (dims + 1) * boundries[j][0] + i] = 1

    A = np.hstack((M, B))

    Theta = linalg.lstsq(M, B)[0].tolist()

    weight = []
    bias = []
    for i in range(0, len(Theta) // (dims + 1)):
        weight.append([
            Theta[(dims + 1) * i][0], Theta[(dims + 1) * i + 1][0],
            Theta[(dims + 1) * i + 2][0]
        ])
        bias.append(Theta[(dims + 1) * i + dims][0])

    steep = 10
    weight = (np.array(weight) * steep).tolist()
    bias = (np.array(bias) * steep).tolist()
    pz = Softmax(weight, bias)

    print('Plotting Observation Model')
    #pz.plot2D(low=[2.5,2.5],high=[3.5,3.5],delta = 0.1,vis=True);
    #pz.plot2D(low=[0,0],high=[10,5],delta = 0.1,vis=True);
    #pz.plot2D(low=[-5,-5],high=[5,5],delta = 0.1,vis=True);

    pz2 = Softmax(deepcopy(weight), deepcopy(bias))
    pz3 = Softmax(deepcopy(weight), deepcopy(bias))
    pz4 = Softmax(deepcopy(weight), deepcopy(bias))

    for i in range(0, len(pz2.weights)):
        pz2.weights[i] = [pz2.weights[i][0], pz2.weights[i][2]]

    for i in range(0, len(pz3.weights)):
        pz3.weights[i] = [pz3.weights[i][1], pz3.weights[i][2]]

    for i in range(0, len(pz4.weights)):
        pz4.weights[i] = [pz4.weights[i][0], pz4.weights[i][1]]

    fig = plt.figure()
    [x, y, c] = pz2.plot2D(low=[-5, -5], high=[5, 5], vis=False)
    plt.contourf(x, y, c)
    plt.xlabel('X Axis')
    plt.ylabel('Z Axis')
    plt.title('Slice Across Y Axis')

    fig = plt.figure()
    [x, y, c] = pz3.plot2D(low=[-5, -5], high=[5, 5], vis=False)
    plt.contourf(x, y, c)
    plt.xlabel('Y Axis')
    plt.ylabel('Z Axis')
    plt.title('Slice Across X axis')

    fig = plt.figure()
    [x, y, c] = pz4.plot2D(low=[-5, -5], high=[5, 5], vis=False)
    plt.contourf(x, y, c)
    plt.xlabel('X Axis')
    plt.ylabel('Y Axis')
    plt.title('Slice Across Z Axis')

    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.set_xlabel('X Axis')
    ax.set_ylabel('Y Axis')
    ax.set_zlabel('Z Axis')
    ax.set_xlim([-5, 5])
    ax.set_ylim([-5, 5])
    ax.set_zlim([-5, 5])
    ax.set_title("3D Scatter of Softmax Class Dominance Regions")

    for clas in range(1, numClasses):
        shapeEdgesX = []
        shapeEdgesY = []
        shapeEdgesZ = []
        #-5 to 5 on all dims
        data = np.zeros(shape=(21, 21, 21))
        for i in range(0, 21):
            for j in range(0, 21):
                for k in range(0, 21):
                    data[i][j][k] = pz.pointEvalND(clas,
                                                   [(i - 10) / 2, (j - 10) / 2,
                                                    (k - 10) / 2])
                    if (data[i][j][k] > 0.1):
                        shapeEdgesX.append((i - 10) / 2)
                        shapeEdgesY.append((j - 10) / 2)
                        shapeEdgesZ.append((k - 10) / 2)

        ax.scatter(shapeEdgesX, shapeEdgesY, shapeEdgesZ)

    plt.show()