This shows the issue:
############################################## import time import threading import queue import numpy as np import graph_tool as gt import graph_tool.draw as gtd from numpy.random import * from numpy.linalg import norm import sys, os, os.path from gi.repository import Gtk, Gdk, GdkPixbuf, GObject, GLib
class Producer (threading.Thread): def __init__(self, threadID, name, q, priority=None): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.q = q self.priority = priority
def run(self): print("Producer " + self.name + " has started") while True: time.sleep(.25) edge = (np.random.randint(0, 100), np.random.randint(0, 10)) if edge[0] != edge[1]: self.q.put(edge) print(f'Producer {self.name} has added {edge} to the queue')
# This function will be called repeatedly by the GTK+ main loop, and we use it # to update the vertex layout and perform the rewiring. def update_state(): print(f'update_state():')
# Perform one iteration of the layout step, starting from the previous positions print(f' update_state(): iterate force-directed graph') gt.draw.sfdp_layout(graph, pos=pos, K=rest_length, init_step=step, max_iter=1)
for i in range(100): if not node_queue.empty(): edge = node_queue.get() print(f' update_state() has consumed {edge}. Adding to the graph') v0_idx = edge[0] v1_idx = edge[1] v0_name = f'v_{v0_idx}' v1_name = f'v_{v1_idx}' vertex_names = list(graph.vp['name']) if vertex_names[0] == '__TEMP_VERT__': graph.remove_vertex(graph.vertex(0)) graph.remove_vertex(graph.vertex(0)) graph.remove_vertex(graph.vertex(0))
if v0_name in vertex_names: print(f' update_state() has found {v0_name} in the graph') v0_idx = list(vertex_names).index(v0_name) else: print(f' update_state() has not found {v0_name} in the graph') v0_idx = graph.add_vertex() graph.vertex_properties['name'][v0_idx] = v0_name graph.vertex_properties['size'][v0_idx] = 10.0 # np.random.randint(10,10)
if v1_name in vertex_names: print(f' update_state() has found {v1_name} in the graph') v1_idx = list(vertex_names).index(v1_name) else: print(f' update_state() has not found {v1_name} in the graph') v1_idx = graph.add_vertex() graph.vertex_properties['name'][v1_idx] = v1_name graph.vertex_properties['size'][v1_idx] = 10.0 # np.random.randint(10,10)
edge = graph.add_edge(v0_idx, v1_idx) print(f' update_state() has added ({v0_idx}: {v0_name}, {v1_idx}: {v1_name}) to the graph')
gt.draw.sfdp_layout(graph, pos=pos, K=rest_length, init_step=step, max_iter=1)
win.graph.fit_to_window(ink=True)
# The following will force the re-drawing of the graph, and issue a # re-drawing of the GTK window. print(f' update_state(): rebuild / redraw)') win.graph.regenerate_surface() win.graph.queue_draw()
# We need to return True so that the main loop will call this function more # than once. print(f'update_state() ends: {time.time()}') return True
if __name__ == "__main__": # Set up queue to pass edges to display (main) thread node_queue = queue.Queue()
# Set up a worker thread to put edges in the queue threads = [] producer = Producer(1, "prod1", node_queue, 6.) # create producer object with priority 6 producer.start() threads.append(producer)
# Set up some functional parameters seed(42) gt.seed_rng(42)
# Create a graph to initialize the window width. # TODO: Is there a way to initialize an empty graph? # Initializing the GraphWindow without ay least # vertices and some edges seems to cause the # vertices and edges to be drawn with unpredictable # radii and thicknesses graph = gt.Graph(directed=True) v0, v1, v2 = graph.add_vertex(3) graph.add_edge(0, 1) graph.add_edge(0, 2) graph.add_edge(1, 2) graph.set_directed(True)
prop_node_name = graph.new_vertex_property("string") graph.vertex_properties['name'] = prop_node_name prop_node_name[v0] = '__TEMP_VERT__' prop_node_name[v1] = '__TEMP_VERT__' prop_node_name[v2] = '__TEMP_VERT__'
prop_node_size = graph.new_vertex_property("float") graph.vertex_properties['size'] = prop_node_size prop_node_size[v0] = 100 prop_node_size[v1] = 100 prop_node_size[v2] = 100
# Parameters for the layout update step = 0.2 # move step rest_length = 15 # preferred edge length
pos = gtd.sfdp_layout(graph, K=rest_length) # initial layout positions win = gtd.GraphWindow( graph, pos, geometry = (1600, 900), vertex_size = graph.vertex_properties['size'], vertex_text = graph.vertex_properties['name'], vertex_font_size = 30, vertex_rotation = 3.14159266368979323846, edge_text = 'relationship', edge_font_size = 30, edge_pen_width = 5, edge_text_parallel = True, )
# Bind the function above as an 'idle' callback. cid = GLib.idle_add(update_state)
# We will give the user the ability to stop the program by closing the window. win.connect("delete_event", Gtk.main_quit)
# Actually show the window, and start the main loop. win.show_all() Gtk.main()