User Tools

Site Tools


graphpca_class

Visual Analytics Course

PCA (Principal Components Analysis)

This python code is meant to be used with the ''PCA'' class. You provide it a graph and a list of properties form which a data matrix is computed. The matrix can then be passed on to the PCA class to compute a 2D embedding for the graph. You would typically use it as:

gPCA = GraphPCA(graph, ['propertyName1', ...]
 
pca = PCA(gPCA.dataMatrix)
gPCA.layout(pca)
 
# the drawAxis method is used to double-check the final result
gPCA.drawAxis()

GraphPCA.py
from tulip import *
from numpy import *
from PCA import *
 
class GraphPCA(object):
    '''
    This is a utilitary class to the PCA class.
    It builds a matrix data from several graph (double) properties.
    The matrix can then be handled to the PCA class to perform PCA analysis.
 
    Note: all properties used by the class must have been pre-computed.
    '''
 
 
    def __init__(self, graph, propertyNameList, compute = False):
        '''
        Constructor
        '''
        self.graph = graph
        self.viewLayout = self.graph.getLayoutProperty('viewLayout')
        m = []
        self.propertyNameList = propertyNameList
        self.propertyList = []
        for i in range(len(self.propertyNameList)):
            self.propertyList.append(self.graph.getDoubleProperty(self.propertyNameList[i]))
            if compute:
                '''
                will only compute if property has not been computed already
                this might be the case when using user defined properties
                '''
                self.graph.computeDoubleProperty(self.propertyNameList[i], self.propertyList[i])
        for n in self.graph.getNodes():
            nVect = []
            for p in self.propertyList:
                nVect.append(p.getNodeValue(n))
            m.append(nVect)
        self.dataMatrix = array(m)
 
 
    def layout(self, pca):
        pca.computePrincipalComponents()
        coords = pca.computeDataProjection()
        xCoords = coords[0]
        yCoords = coords[1]
	i = 0
	for node in self.graph.getNodes():
		cNode = self.viewLayout[node]
		cNode.setX(xCoords[i])
		cNode.setY(yCoords[i])
		self.viewLayout[node] = cNode
		i += 1
 
    def drawAxis(self, pca):
        '''
        Need to call layout first so the self.pca variable is initialized
        '''
        n1 = self.graph.addNode()
        n2 = self.graph.addNode()
        n3 = self.graph.addNode()
        n4 = self.graph.addNode()
        self.viewLayout[n1] = tlp.Coord(1,0,0)
        self.viewLayout[n2] = tlp.Coord(-1,0,0)
        self.viewLayout[n3] = tlp.Coord(0,1,0)
        self.viewLayout[n4] = tlp.Coord(0,-1,0)
        color = self.graph.getColorProperty('viewColor')
        color[n1] = tlp.Color(0,255,0)
        color[n2] = tlp.Color(0,255,0)
        color[n3] = tlp.Color(0,255,0)
        color[n4] = tlp.Color(0,255,0)
        size = self.graph.getSizeProperty('viewSize')
        size[n1] = tlp.Size(0.01,0.01,0.01)
        size[n2] = tlp.Size(0.01,0.01,0.01)
        size[n3] = tlp.Size(0.01,0.01,0.01)
        size[n4] = tlp.Size(0.01,0.01,0.01)
        self.graph.addEdge(n1, n2)
        self.graph.addEdge(n3, n4)
        return True
 
    def layoutFromProperties(self, propId1, propId2):
        '''
        Handy. This method will lay out nodes of a graph using
        two properites as x, y coordinates
        '''
        for n in self.graph.getNodes():
            c = viewLayout.getNodeValue(n)
            c.setX(self.propertyList[propId1].getNodeValue(n))
            c.setY(self.propertyList[propId2].getNodeValue(n))
            self.viewLayout.setNodeValue(n, c)
 
 
    def totalSquaredDistances(self):
        '''
        computes the sum of squared distances of points to a given line
        the line is implicitly defined by two selected nodes
        although they are part of the view, those nodes are not part
        of the point cloud and should be treated as outer items
 
        first compute the unit vector along the given line
        then compute the sum of squared dot products of other points (vectors)
        with the unit vector
        also, we assume the viewLayout is in 2D, with a null 3rd coordinates
        (makes it possible to rely on tlp.Coord dot product)
        '''
        viewSelection = self.graph.getBooleanProperty('viewSelection')
        selectedNodes = []
        for n in self.graph.getNodes():
            if viewSelection.getNodeValue(n):
                selectedNodes.append(n)
        node1 = selectedNodes[0]
        node2 = selectedNodes[1]
 
        c1 = self.viewLayout.getNodeValue(node1)
        c2 = self.viewLayout.getNodeValue(node2)
        m = (c2.getY() - c1.getY()) / (c2.getX() - c1.getX())
        length = sqrt(1 + m * m)
        u = tlp.Coord(1.0 / length, m / length, 0.0)
 
        sqDist = 0.0
        for n in self.graph.getNodes():
            if not n.id == node1.id and not n.id == node2.id:
                c = self.viewLayout.getNodeValue(n)
                sqDist += u.dotProduct(c) * u.dotProduct(c)
        return sqDist 
/net/html/perso/melancon/Visual_Analytics_Course/data/pages/graphpca_class.txt · Last modified: 2012/10/25 14:57 by melancon