Advertisement
Guest User

Untitled

a guest
Aug 2nd, 2015
203
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.25 KB | None | 0 0
  1. '''
  2. @author Michael J Bommarito II
  3. @contact michael.bommarito@gmail.com
  4. @date Feb 21, 2011
  5. @license Simplified BSD, (C) 2011.
  6.  
  7. Plot the network of the first 1000 #cn220 tweets with igraph and cairo.
  8. '''
  9.  
  10. import cairo
  11. import codecs
  12. import dateutil.parser
  13. import igraph
  14. import numpy
  15. import re
  16.  
  17. def readTweets(fileName):
  18. '''
  19. Read in tweet data from the tab-delimited tweet format.
  20. '''
  21. rows = [[field.strip() for field in line.split("\t")] for line in codecs.open(fileName, 'r', 'utf-8')]
  22. return [(int(row[0]), dateutil.parser.parse(row[1]), row[2], row[3]) for row in rows]
  23.  
  24. def getNetwork(tweets):
  25. '''
  26. Parse the list of tweets and find "edges" embedded in the tweets.
  27. Edges are just mentions in the tweet text, e.g., @mjbommar.
  28. Then process the network from the edges.
  29. '''
  30. reMention = re.compile('\@([\w]+)')
  31.  
  32. # Calculate the list of mentions
  33. mentions = []
  34. for tweet in tweets:
  35. mentions.extend([(tweet[1], tweet[2], name) for name in reMention.findall(tweet[3])])
  36.  
  37. # Sort by date
  38. mentions = sorted(mentions)
  39.  
  40. # Now convert the dates/mention to edges and weights
  41. dates, nodeA, nodeB = zip(*mentions)
  42. nodes = set(nodeA) | set(nodeB)
  43. nodes = sorted(list(nodes))
  44. nodeMap = dict([(v,i) for i,v in enumerate(nodes)])
  45. edges = [(nodeMap[e[1]], nodeMap[e[2]]) for e in mentions]
  46. edges, weights = map(list, zip(*[[e, edges.count(e)] for e in set(edges)]))
  47.  
  48. # Now create the graph
  49. graph = igraph.Graph(edges)
  50. graph.es['weight'] = weights
  51. graph.vs['label'] = nodes
  52.  
  53. return graph
  54.  
  55. def project2D(layout, alpha, beta):
  56. '''
  57. This method will project a set of points in 3D to 2D based on the given
  58. angles alpha and beta.
  59. '''
  60.  
  61. # Calculate the rotation matrices based on the given angles.
  62. c = numpy.matrix([[1, 0, 0], [0, numpy.cos(alpha), numpy.sin(alpha)], [0, -numpy.sin(alpha), numpy.cos(alpha)]])
  63. c = c * numpy.matrix([[numpy.cos(beta), 0, -numpy.sin(beta)], [0, 1, 0], [numpy.sin(beta), 0, numpy.cos(beta)]])
  64. b = numpy.matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
  65.  
  66. # Hit the layout, rotate, and kill a dimension
  67. layout = numpy.matrix(layout)
  68. X = (b * (c * layout.transpose())).transpose()
  69. return [[X[i,0],X[i,1],X[i,2]] for i in range(X.shape[0])]
  70.  
  71. def drawGraph3D(graph, layout, angle, fileName):
  72. '''
  73. Draw a graph in 3D with the given layout, angle, and filename.
  74. '''
  75.  
  76. # Setup some vertex attributes and calculate the projection
  77. graph.vs['degree'] = graph.degree()
  78. vertexRadius = 0.1 * (0.9 * 0.9) / numpy.sqrt(graph.vcount())
  79. graph.vs['x3'], graph.vs['y3'], graph.vs['z3'] = zip(*layout)
  80.  
  81.  
  82. layout2D = project2D(layout, angle[0], angle[1])
  83. graph.vs['x2'], graph.vs['y2'], graph.vs['z2'] = zip(*layout2D)
  84. minX, maxX = min(graph.vs['x2']), max(graph.vs['x2'])
  85. minY, maxY = min(graph.vs['y2']), max(graph.vs['y2'])
  86. minZ, maxZ = min(graph.vs['z2']), max(graph.vs['z2'])
  87.  
  88. # Calculate the draw order. This is important if we want this to look
  89. # realistically 3D.
  90. zVal, zOrder = zip(*sorted(zip(graph.vs['z3'], range(graph.vcount()))))
  91.  
  92. # Setup the cairo surface
  93. surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1280, 800)
  94. con = cairo.Context(surf)
  95. con.scale(1280.0, 800.0)
  96.  
  97. # Draw the background
  98. con.set_source_rgba(0.0, 0.0, 0.0, 1.0)
  99. con.rectangle(0.0, 0.0, 1.0, 1.0)
  100. con.fill()
  101.  
  102. # Draw the edges without respect to z-order but set their alpha along
  103. # a linear gradient to represent depth.
  104. for e in graph.get_edgelist():
  105. # Get the first vertex info
  106. v0 = graph.vs[e[0]]
  107. x0 = (v0['x2'] - minX) / (maxX - minX)
  108. y0 = (v0['y2'] - minY) / (maxY - minY)
  109. alpha0 = (v0['z2'] - minZ) / (maxZ - minZ)
  110. alpha0 = max(0.1, alpha0)
  111.  
  112. # Get the second vertex info
  113. v1 = graph.vs[e[1]]
  114. x1 = (v1['x2'] - minX) / (maxX - minX)
  115. y1 = (v1['y2'] - minY) / (maxY - minY)
  116. alpha1 = (v1['z2'] - minZ) / (maxZ - minZ)
  117. alpha1 = max(0.1, alpha1)
  118.  
  119. # Setup the pattern info
  120. pat = cairo.LinearGradient(x0, y0, x1, y1)
  121. pat.add_color_stop_rgba(0, 1, 1.0, 1.0, alpha0 / 6.0)
  122. pat.add_color_stop_rgba(1, 1, 1.0, 1.0, alpha1 / 6.0)
  123. con.set_source(pat)
  124.  
  125. # Draw the line
  126. con.set_line_width(vertexRadius / 4.0)
  127. con.move_to(x0, y0)
  128. con.line_to(x1, y1)
  129. con.stroke()
  130.  
  131. # Draw vertices in z-order
  132. for i in zOrder:
  133. v = graph.vs[i]
  134. alpha = (v['z2'] - minZ) / (maxZ - minZ)
  135. alpha = max(0.1, alpha)
  136. radius = vertexRadius
  137. x = (v['x2'] - minX) / (maxX - minX)
  138. y = (v['y2'] - minY) / (maxY - minY)
  139.  
  140. # Setup the radial pattern for 3D lighting effect
  141. pat = cairo.RadialGradient(x, y, radius / 4.0, x, y, radius)
  142. pat.add_color_stop_rgba(0, alpha, 0, 0, 1)
  143. pat.add_color_stop_rgba(1, 0, 0, 0, 1)
  144. con.set_source(pat)
  145.  
  146.  
  147. # Draw the vertex sphere
  148. con.move_to(x, y)
  149. con.arc(x, y, radius, 0, 2 * numpy.pi)
  150. con.fill()
  151.  
  152. # Output the surface
  153. surf.write_to_png(fileName)
  154.  
  155. if __name__ == "__main__":
  156. # Load the tweets
  157. tweets = readTweets("data/tweets_cn220.csv")
  158.  
  159. # Determine how many tweets we'll use to construct the network.
  160. numTweets = 1000
  161.  
  162. # Load the graph, isolate the giant component, and calculate the layout.
  163. graph = getNetwork(tweets[0:numTweets])
  164. graph = graph.components(mode=igraph.WEAK).giant()
  165. layout = graph.layout_kamada_kawai_3d()
  166.  
  167. # Now draw the frames while rotating.
  168. for frame in range(400):
  169. alpha = frame * numpy.pi / 200.
  170. beta = frame * numpy.pi / 150.
  171. print frame, alpha, beta
  172. drawGraph3D(graph, layout, (alpha, beta), "frames/%08d.png" % (frame))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement