This code shows the problem under Ubuntu 20.04 running under WSL2.
-caleb
###################################################3
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()