Here is example code which 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()
_______________________________________________
graph-tool mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to