Hi Tiago,
sometimes, when delete the graph and create a new one, then plot it, the plotted graph is shown upside down (in terms of the node text). So how could we control the orientation of the graph? Or which parameter we should use to always make node text shown in a correct orientation. Thanks a lot.
-- View this message in context: http://main-discussion-list-for-the-graph-tool-project.982480.n3.nabble.com/... Sent from the Main discussion list for the graph-tool project mailing list archive at Nabble.com.
On 05.06.2015 15:28, Xun Xiao wrote:
Hi Tiago,
sometimes, when delete the graph and create a new one, then plot it, the plotted graph is shown upside down (in terms of the node text). So how could we control the orientation of the graph? Or which parameter we should use to always make node text shown in a correct orientation. Thanks a lot.
I'm not sure I understand. Can you provide an example?
Best, Tiago
I can explain a bit. Using your graph_draw() has no problem, however, when I include the GraphWidget in the window of myself, after plotting a graph with specifying node text, the whole graph is upside down, I have to turn 180 degree of the graph.
-- View this message in context: http://main-discussion-list-for-the-graph-tool-project.982480.n3.nabble.com/... Sent from the Main discussion list for the graph-tool project mailing list archive at Nabble.com.
On 05.06.2015 16:11, Xun Xiao wrote:
I can explain a bit. Using your graph_draw() has no problem, however, when I include the GraphWidget in the window of myself, after plotting a graph with specifying node text, the whole graph is upside down, I have to turn 180 degree of the graph.
Well, I've never encountered this problem before, and I don't know what may be causing it. Without a concrete example, I cannot investigate.
Best, Tiago
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()
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()