Issue image link (i do not know why its not being centered to allign with the line, can someone please help me?): https://drive.google.com/file/d/1DvUJwkR_lXLfEPHiz161_xpOoxtAtGen/view?usp=sharing code start from here: import re import matplotlib.pyplot as plt import networkx as nx from matplotlib.widgets import Slider from matplotlib.patches import FancyArrowPatch # Parse data from the file def parse_events(file_path): events = [] with open(file_path, "r") as file: content = file.read() matches = re.finditer( r"Label: (v|l|m|ve|r|s)((.*?))nObject: ((.*?))nt=(d+.d+),(d+.d+)nDescription: (.*?)nObjects in Description: ((.*?))", content, ) for match in matches: events.append({ "type": match.group(1).strip(), "label": match.group(2).strip(), "object": match.group(3).strip(), "start_time": float(match.group(4)), "end_time": float(match.group(5)), "description": match.group(6).strip(), "related_objects": [obj.strip() for obj in match.group(7).split(", ")] }) return events # Strip text after '(' in the description def clean_description(description): return description.split('(')[0].strip() # Create a dynamic graph visualization def create_dynamic_graph(events, time_range): G = nx.DiGraph() for event in events: if event["start_time"] <= time_range <= event["end_time"]: main_object = event["object"] related_objects = event["related_objects"] cleaned_description = clean_description(event["description"]) # Handle edges for related objects if len(related_objects) > 1: for obj in related_objects[1:]: G.add_edge(main_object, obj, label=f"{event['type']}: {cleaned_description}", type=event["type"]) else: # Add node if not already present if main_object not in G.nodes: G.add_node(main_object, descriptions={}) # Ensure the 'descriptions' attribute is initialized if "descriptions" not in G.nodes[main_object]: G.nodes[main_object]["descriptions"] = {} # Add the event's description G.nodes[main_object]['descriptions'][event["type"]] = cleaned_description return G # Draw arrows based on event type def draw_arrows(ax, G, pos): # Clear existing arrows for patch in list(ax.patches): patch.remove() for edge in G.edges(data=True): src, tgt, data = edge x_src, y_src = pos[src] x_tgt, y_tgt = pos[tgt] # Determine arrow style and color based on type if data.get("type") == "l": connectionstyle = "arc3,rad=0.2" color = "black" elif data.get("type") == "m": connectionstyle = "arc3,rad=-0.2" color = "orange" elif data.get("type") == "r": connectionstyle = "arc3,rad=0.3" color = "red" elif data.get("type") == "s": connectionstyle = "arc3,rad=-0.3" color = "pink" else: connectionstyle = "arc3,rad=0" color = "blue" arrow = FancyArrowPatch( (x_src, y_src), (x_tgt, y_tgt), connectionstyle=connectionstyle, arrowstyle="->", # Arrow tip color=color, linewidth=1.5 ) ax.add_patch(arrow) # Label the arrow label = data.get('label', '') mid_x = (x_src + x_tgt) / 2 mid_y = (y_src + y_tgt) / 2 ax.text(mid_x, mid_y, label, fontsize=9, color=color, ha="center", va="center") # Draw the graph def draw_graph(G, ax, pos): ax.clear() ax.set_xlim(-1, 1) # Set fixed bounds for x-axis ax.set_ylim(-1, 1) # Set fixed bounds for y-axis ax.axvline(-1, color="black", linewidth=2) # Left boundary ax.axvline(1, color="black", linewidth=2) # Right boundary ax.axhline(-1, color="black", linewidth=2) # Bottom boundary ax.axhline(1, color="black", linewidth=2) # Top boundary nx.draw(G, pos, ax=ax, with_labels=False, node_size=1500, font_size=10) draw_arrows(ax, G, pos) for node, data in G.nodes(data=True): x, y = pos[node] # Node Name ax.text(x, y, node, fontsize=10, ha="center", va="center") # Render all descriptions below the node text_y_offset = -0.15 # Start below the node if "descriptions" in data: for term_type, description in data["descriptions"].items(): if term_type == "v": color = "red" elif term_type == "l": color = "black" elif term_type == "m": color = "orange" elif term_type == "ve": color = "blue" elif term_type == "r": color = "red" else: continue ax.text(x, y + text_y_offset, f"{term_type}: {description}", fontsize=10, color=color, ha="center", va="center") text_y_offset -= 0.1 # Adjust offset for the next text # Node dragging handler class NodeDragger: def __init__(self, graph, pos, ax, draw_func, bounds): self.graph = graph self.pos = pos = ax self.draw_func = draw_func self.bounds = bounds self.dragging_node = None self.dragging = False self.cid_press = ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.cid_release = ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.cid_motion = ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): if event.inaxes != self.ax: return for node, (x, y) in self.pos.items(): if abs(event.xdata - x) < 0.05 and abs(event.ydata - y) < 0.05: self.dragging_node = node self.dragging = True break def on_release(self, event): if self.dragging: self.dragging = False self.dragging_node = None self.ax.figure.canvas.draw_idle() def on_motion(self, event): if not self.dragging or self.dragging_node is None or event.inaxes != self.ax: return # Apply boundary constraints x = min(max(event.xdata, self.bounds[0]), self.bounds[1]) y = min(max(event.ydata, self.bounds[2]), self.bounds[3]) self.pos[self.dragging_node] = (x, y) self.draw_func(self.graph, , self.pos) self.ax.figure.canvas.draw_idle() # Interactive plot def interactive_plot(events): fig, ax = plt.subplots(figsize=(10, 8)) plt.subplots_adjust(bottom=0.2) ax_time = plt.axes([0.2, 0.05, 0.65, 0.03]) slider = Slider(ax_time, 'Time', 0, max(event["end_time"] for event in events), valinit=0, valstep=0.1) # Initial graph current_time = 0 G = create_dynamic_graph(events, current_time) pos = nx.spring_layout(G) bounds = [-1, 1, -1, 1] draw_graph(G, ax, pos) # Add node dragger with bounds dragger = NodeDragger(G, pos, ax, draw_graph, bounds) def update(val): if dragger.dragging: # Do not update while dragging return time = slider.val # Create a new graph for the updated time range updated_graph = create_dynamic_graph(events, time) G.clear() G.add_edges_from(updated_graph.edges(data=True)) G.add_nodes_from(updated_graph.nodes(data=True)) for node in G.nodes: if node not in pos: pos[node] = (0.5, 0.5) # Default position for new nodes draw_graph(G, ax, pos) slider.on_changed(update) plt.show() # Main if __name__ == "__main__": file_path = "ter.txt" events = parse_events(file_path) interactive_plot(events) self.axself.ax
submitted by /u/Kind-Run-6955
[link] [comments]
r/learnpython Issue image link (i do not know why its not being centered to allign with the line, can someone please help me?): https://drive.google.com/file/d/1DvUJwkR_lXLfEPHiz161_xpOoxtAtGen/view?usp=sharing code start from here: import re import matplotlib.pyplot as plt import networkx as nx from matplotlib.widgets import Slider from matplotlib.patches import FancyArrowPatch # Parse data from the file def parse_events(file_path): events = [] with open(file_path, “r”) as file: content = file.read() matches = re.finditer( r”Label: (v|l|m|ve|r|s)((.*?))nObject: ((.*?))nt=(d+.d+),(d+.d+)nDescription: (.*?)nObjects in Description: ((.*?))”, content, ) for match in matches: events.append({ “type”: match.group(1).strip(), “label”: match.group(2).strip(), “object”: match.group(3).strip(), “start_time”: float(match.group(4)), “end_time”: float(match.group(5)), “description”: match.group(6).strip(), “related_objects”: [obj.strip() for obj in match.group(7).split(“, “)] }) return events # Strip text after ‘(‘ in the description def clean_description(description): return description.split(‘(‘)[0].strip() # Create a dynamic graph visualization def create_dynamic_graph(events, time_range): G = nx.DiGraph() for event in events: if event[“start_time”] <= time_range <= event[“end_time”]: main_object = event[“object”] related_objects = event[“related_objects”] cleaned_description = clean_description(event[“description”]) # Handle edges for related objects if len(related_objects) > 1: for obj in related_objects[1:]: G.add_edge(main_object, obj, label=f”{event[‘type’]}: {cleaned_description}”, type=event[“type”]) else: # Add node if not already present if main_object not in G.nodes: G.add_node(main_object, descriptions={}) # Ensure the ‘descriptions’ attribute is initialized if “descriptions” not in G.nodes[main_object]: G.nodes[main_object][“descriptions”] = {} # Add the event’s description G.nodes[main_object][‘descriptions’][event[“type”]] = cleaned_description return G # Draw arrows based on event type def draw_arrows(ax, G, pos): # Clear existing arrows for patch in list(ax.patches): patch.remove() for edge in G.edges(data=True): src, tgt, data = edge x_src, y_src = pos[src] x_tgt, y_tgt = pos[tgt] # Determine arrow style and color based on type if data.get(“type”) == “l”: connectionstyle = “arc3,rad=0.2” color = “black” elif data.get(“type”) == “m”: connectionstyle = “arc3,rad=-0.2” color = “orange” elif data.get(“type”) == “r”: connectionstyle = “arc3,rad=0.3” color = “red” elif data.get(“type”) == “s”: connectionstyle = “arc3,rad=-0.3” color = “pink” else: connectionstyle = “arc3,rad=0” color = “blue” arrow = FancyArrowPatch( (x_src, y_src), (x_tgt, y_tgt), connectionstyle=connectionstyle, arrowstyle=”->”, # Arrow tip color=color, linewidth=1.5 ) ax.add_patch(arrow) # Label the arrow label = data.get(‘label’, ”) mid_x = (x_src + x_tgt) / 2 mid_y = (y_src + y_tgt) / 2 ax.text(mid_x, mid_y, label, fontsize=9, color=color, ha=”center”, va=”center”) # Draw the graph def draw_graph(G, ax, pos): ax.clear() ax.set_xlim(-1, 1) # Set fixed bounds for x-axis ax.set_ylim(-1, 1) # Set fixed bounds for y-axis ax.axvline(-1, color=”black”, linewidth=2) # Left boundary ax.axvline(1, color=”black”, linewidth=2) # Right boundary ax.axhline(-1, color=”black”, linewidth=2) # Bottom boundary ax.axhline(1, color=”black”, linewidth=2) # Top boundary nx.draw(G, pos, ax=ax, with_labels=False, node_size=1500, font_size=10) draw_arrows(ax, G, pos) for node, data in G.nodes(data=True): x, y = pos[node] # Node Name ax.text(x, y, node, fontsize=10, ha=”center”, va=”center”) # Render all descriptions below the node text_y_offset = -0.15 # Start below the node if “descriptions” in data: for term_type, description in data[“descriptions”].items(): if term_type == “v”: color = “red” elif term_type == “l”: color = “black” elif term_type == “m”: color = “orange” elif term_type == “ve”: color = “blue” elif term_type == “r”: color = “red” else: continue ax.text(x, y + text_y_offset, f”{term_type}: {description}”, fontsize=10, color=color, ha=”center”, va=”center”) text_y_offset -= 0.1 # Adjust offset for the next text # Node dragging handler class NodeDragger: def __init__(self, graph, pos, ax, draw_func, bounds): self.graph = graph self.pos = pos = ax self.draw_func = draw_func self.bounds = bounds self.dragging_node = None self.dragging = False self.cid_press = ax.figure.canvas.mpl_connect(‘button_press_event’, self.on_press) self.cid_release = ax.figure.canvas.mpl_connect(‘button_release_event’, self.on_release) self.cid_motion = ax.figure.canvas.mpl_connect(‘motion_notify_event’, self.on_motion) def on_press(self, event): if event.inaxes != self.ax: return for node, (x, y) in self.pos.items(): if abs(event.xdata – x) < 0.05 and abs(event.ydata – y) < 0.05: self.dragging_node = node self.dragging = True break def on_release(self, event): if self.dragging: self.dragging = False self.dragging_node = None self.ax.figure.canvas.draw_idle() def on_motion(self, event): if not self.dragging or self.dragging_node is None or event.inaxes != self.ax: return # Apply boundary constraints x = min(max(event.xdata, self.bounds[0]), self.bounds[1]) y = min(max(event.ydata, self.bounds[2]), self.bounds[3]) self.pos[self.dragging_node] = (x, y) self.draw_func(self.graph, , self.pos) self.ax.figure.canvas.draw_idle() # Interactive plot def interactive_plot(events): fig, ax = plt.subplots(figsize=(10, 8)) plt.subplots_adjust(bottom=0.2) ax_time = plt.axes([0.2, 0.05, 0.65, 0.03]) slider = Slider(ax_time, ‘Time’, 0, max(event[“end_time”] for event in events), valinit=0, valstep=0.1) # Initial graph current_time = 0 G = create_dynamic_graph(events, current_time) pos = nx.spring_layout(G) bounds = [-1, 1, -1, 1] draw_graph(G, ax, pos) # Add node dragger with bounds dragger = NodeDragger(G, pos, ax, draw_graph, bounds) def update(val): if dragger.dragging: # Do not update while dragging return time = slider.val # Create a new graph for the updated time range updated_graph = create_dynamic_graph(events, time) G.clear() G.add_edges_from(updated_graph.edges(data=True)) G.add_nodes_from(updated_graph.nodes(data=True)) for node in G.nodes: if node not in pos: pos[node] = (0.5, 0.5) # Default position for new nodes draw_graph(G, ax, pos) slider.on_changed(update) plt.show() # Main if __name__ == “__main__”: file_path = “ter.txt” events = parse_events(file_path) interactive_plot(events) self.axself.ax submitted by /u/Kind-Run-6955 [link] [comments]
Issue image link (i do not know why its not being centered to allign with the line, can someone please help me?): https://drive.google.com/file/d/1DvUJwkR_lXLfEPHiz161_xpOoxtAtGen/view?usp=sharing code start from here: import re import matplotlib.pyplot as plt import networkx as nx from matplotlib.widgets import Slider from matplotlib.patches import FancyArrowPatch # Parse data from the file def parse_events(file_path): events = [] with open(file_path, "r") as file: content = file.read() matches = re.finditer( r"Label: (v|l|m|ve|r|s)((.*?))nObject: ((.*?))nt=(d+.d+),(d+.d+)nDescription: (.*?)nObjects in Description: ((.*?))", content, ) for match in matches: events.append({ "type": match.group(1).strip(), "label": match.group(2).strip(), "object": match.group(3).strip(), "start_time": float(match.group(4)), "end_time": float(match.group(5)), "description": match.group(6).strip(), "related_objects": [obj.strip() for obj in match.group(7).split(", ")] }) return events # Strip text after '(' in the description def clean_description(description): return description.split('(')[0].strip() # Create a dynamic graph visualization def create_dynamic_graph(events, time_range): G = nx.DiGraph() for event in events: if event["start_time"] <= time_range <= event["end_time"]: main_object = event["object"] related_objects = event["related_objects"] cleaned_description = clean_description(event["description"]) # Handle edges for related objects if len(related_objects) > 1: for obj in related_objects[1:]: G.add_edge(main_object, obj, label=f"{event['type']}: {cleaned_description}", type=event["type"]) else: # Add node if not already present if main_object not in G.nodes: G.add_node(main_object, descriptions={}) # Ensure the 'descriptions' attribute is initialized if "descriptions" not in G.nodes[main_object]: G.nodes[main_object]["descriptions"] = {} # Add the event's description G.nodes[main_object]['descriptions'][event["type"]] = cleaned_description return G # Draw arrows based on event type def draw_arrows(ax, G, pos): # Clear existing arrows for patch in list(ax.patches): patch.remove() for edge in G.edges(data=True): src, tgt, data = edge x_src, y_src = pos[src] x_tgt, y_tgt = pos[tgt] # Determine arrow style and color based on type if data.get("type") == "l": connectionstyle = "arc3,rad=0.2" color = "black" elif data.get("type") == "m": connectionstyle = "arc3,rad=-0.2" color = "orange" elif data.get("type") == "r": connectionstyle = "arc3,rad=0.3" color = "red" elif data.get("type") == "s": connectionstyle = "arc3,rad=-0.3" color = "pink" else: connectionstyle = "arc3,rad=0" color = "blue" arrow = FancyArrowPatch( (x_src, y_src), (x_tgt, y_tgt), connectionstyle=connectionstyle, arrowstyle="->", # Arrow tip color=color, linewidth=1.5 ) ax.add_patch(arrow) # Label the arrow label = data.get('label', '') mid_x = (x_src + x_tgt) / 2 mid_y = (y_src + y_tgt) / 2 ax.text(mid_x, mid_y, label, fontsize=9, color=color, ha="center", va="center") # Draw the graph def draw_graph(G, ax, pos): ax.clear() ax.set_xlim(-1, 1) # Set fixed bounds for x-axis ax.set_ylim(-1, 1) # Set fixed bounds for y-axis ax.axvline(-1, color="black", linewidth=2) # Left boundary ax.axvline(1, color="black", linewidth=2) # Right boundary ax.axhline(-1, color="black", linewidth=2) # Bottom boundary ax.axhline(1, color="black", linewidth=2) # Top boundary nx.draw(G, pos, ax=ax, with_labels=False, node_size=1500, font_size=10) draw_arrows(ax, G, pos) for node, data in G.nodes(data=True): x, y = pos[node] # Node Name ax.text(x, y, node, fontsize=10, ha="center", va="center") # Render all descriptions below the node text_y_offset = -0.15 # Start below the node if "descriptions" in data: for term_type, description in data["descriptions"].items(): if term_type == "v": color = "red" elif term_type == "l": color = "black" elif term_type == "m": color = "orange" elif term_type == "ve": color = "blue" elif term_type == "r": color = "red" else: continue ax.text(x, y + text_y_offset, f"{term_type}: {description}", fontsize=10, color=color, ha="center", va="center") text_y_offset -= 0.1 # Adjust offset for the next text # Node dragging handler class NodeDragger: def __init__(self, graph, pos, ax, draw_func, bounds): self.graph = graph self.pos = pos = ax self.draw_func = draw_func self.bounds = bounds self.dragging_node = None self.dragging = False self.cid_press = ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.cid_release = ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.cid_motion = ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): if event.inaxes != self.ax: return for node, (x, y) in self.pos.items(): if abs(event.xdata - x) < 0.05 and abs(event.ydata - y) < 0.05: self.dragging_node = node self.dragging = True break def on_release(self, event): if self.dragging: self.dragging = False self.dragging_node = None self.ax.figure.canvas.draw_idle() def on_motion(self, event): if not self.dragging or self.dragging_node is None or event.inaxes != self.ax: return # Apply boundary constraints x = min(max(event.xdata, self.bounds[0]), self.bounds[1]) y = min(max(event.ydata, self.bounds[2]), self.bounds[3]) self.pos[self.dragging_node] = (x, y) self.draw_func(self.graph, , self.pos) self.ax.figure.canvas.draw_idle() # Interactive plot def interactive_plot(events): fig, ax = plt.subplots(figsize=(10, 8)) plt.subplots_adjust(bottom=0.2) ax_time = plt.axes([0.2, 0.05, 0.65, 0.03]) slider = Slider(ax_time, 'Time', 0, max(event["end_time"] for event in events), valinit=0, valstep=0.1) # Initial graph current_time = 0 G = create_dynamic_graph(events, current_time) pos = nx.spring_layout(G) bounds = [-1, 1, -1, 1] draw_graph(G, ax, pos) # Add node dragger with bounds dragger = NodeDragger(G, pos, ax, draw_graph, bounds) def update(val): if dragger.dragging: # Do not update while dragging return time = slider.val # Create a new graph for the updated time range updated_graph = create_dynamic_graph(events, time) G.clear() G.add_edges_from(updated_graph.edges(data=True)) G.add_nodes_from(updated_graph.nodes(data=True)) for node in G.nodes: if node not in pos: pos[node] = (0.5, 0.5) # Default position for new nodes draw_graph(G, ax, pos) slider.on_changed(update) plt.show() # Main if __name__ == "__main__": file_path = "ter.txt" events = parse_events(file_path) interactive_plot(events) self.axself.ax
submitted by /u/Kind-Run-6955
[link] [comments]