#GraphEditor
What's the point of spending months writing a spline editor if you can't draw interesting graphs?

The blog post related to the latest release of the #grapheditor

#python #softwaredevelopment #qt #pyside6

https://isijingi.co.za/wp/2026/01/04/qtpygraphedit-v0-1-0-now-with-multipoint-lines/
January 4, 2026 at 12:23 PM
Unfortunately, Godot doesn't expose the text to screen readers too. :( But it looks there's some wip! github.com/godotengine/...
Implement screen reader support using AccessKit library. by bruvzg · Pull Request #76829 · godotengine/godot
Initial implementation of the AccessKit integration use C-API: All base (non-editor) controls except GraphEditor should work now. UI behavior without active screen reader should be unchanged. When ...
github.com
December 12, 2024 at 12:43 AM
The Graph theory.
Linear movement is boring. Life doesn't move at a constant speed, and your animations shouldn't either. Master your value graphs.
#vantiqstudio
#editor
#videoeeditor
#grapheditor
April 23, 2026 at 4:53 AM
"Attempt to disconnect a nonexistent connection" while deleting GraphNode from GraphEditor
### Godot Version v4.4.1.stable.official [49a5bc7b6] ### Question Similar to this question: GraphEdit nodes deletion error When trying to delete GraphNode added using `add_child`, an error was given: Attempt to disconnect a nonexistent connection from 'MusicGraphNode'. Signal: 'item_rect_changed', callable: 'CanvasItem::queue_redraw'. I was using this code to delete node. However, I tested and I found, with only `A`, only `B`, and both `A` and `B`, that error was given. Changing `free` to `queue_free` does not solve the problem. func clearUI(): self.clear_connections() for c in self.get_children(): if c is GraphElement: self.remove_child(c) # A c.free() # B If this `clearUI` called in `_init`, no error will be given. Also, I have checked that `clearUI` is only called once by the`loadGraphFromAMUG` method. Also, as described in the link above, if using deferred call of `add_child`, no error will be given. I am wondering why this is happening. This is my code: @tool class_name MusicGraphEditor extends GraphEdit ## This class is responsible to maintain the UI and inner data (`graph_store`). ## For each defined method, it should operate on GraphEdit's internal structure to show the UI, ## and `graph_store: MusicGraph` for saving data. # End of class document. ## The operation mode of MusicGraphEditor. enum OperationMode { select, move, connect, single_node_focusing } ## Current graph showed on the editor UI. var graph_store: MusicGraph ## Index of the graph_store in the file tab.[br] var graph_index: int ## Counter used for new node creation. var node_id_counter: int ## Counter used for new edge creation. var edge_id_counter: int ## Current operation mode of UI. var operation_mode: OperationMode: set = __setOperationMode func __setOperationMode(m: OperationMode): print_debug(str("Set MusicGraphEditor's operation_mode to \"", OperationMode.find_key(m), "\".")) operation_mode = m # TODO func _init() -> void: self.add_child( MusicGraphNode.new( MusicNode.new(1,"Test1", null, null, Vector2(10,10), [ GraphNodeSlotInfo.new(0, GraphNodeSlotInfo.SlotLocation.right), GraphNodeSlotInfo.new(1, GraphNodeSlotInfo.SlotLocation.right), GraphNodeSlotInfo.new(2, GraphNodeSlotInfo.SlotLocation.right), GraphNodeSlotInfo.new(3, GraphNodeSlotInfo.SlotLocation.left), ]) ) ) self.add_child( MusicGraphNode.new( MusicNode.new(2,"Test2", null, null, Vector2(300,300), [ GraphNodeSlotInfo.new(0, GraphNodeSlotInfo.SlotLocation.left), GraphNodeSlotInfo.new(1, GraphNodeSlotInfo.SlotLocation.left), GraphNodeSlotInfo.new(2, GraphNodeSlotInfo.SlotLocation.right), ]) ) ) var connect_result = self.connect_node("Test1",1,"Test2",1) # self.clearUI() # If called from here, no error. func _gui_input(event: InputEvent) -> void: self.__handleGUIInput__(event) func __handleGUIInput__(event: InputEvent): # TODO # Written in this way to get type hint. if event is InputEventMouse: if event.is_pressed(): var nearest_conn := self.get_closest_connection_at_point(event.position) # If found a connection. if nearest_conn.size() > 0: pass func loadGraphFromAMUG(index: int, file: AMUGResource): self.graph_index = index self.graph_store = file.music_graph self.loadGraphFromStore() ## Load the UI and paramters from `self.graph_store`. func loadGraphFromStore(): # TODO self.clearUI() var node_array := self.graph_store.node_array for node in self.graph_store.node_array: self.add_child(MusicGraphNode.new(node)) self.node_id_counter = node_array[-1].id + 1 func clearUI(): self.clear_connections() for c in self.get_children(): if c is GraphElement: self.remove_child(c) c.free()
forum.godotengine.org
May 30, 2025 at 7:24 AM
Which part exactly? haha
The editor overall is using Godot's GraphEditor and Nodes. The sorting is done by keeping track of what have already spawned(like a var for rows and columns) and offsetting the next one
June 26, 2025 at 11:21 PM