Open fsoupimenta opened 6 months ago
Could you describe the intended behaviour in excruciating detail for me? As in:
The user selects multiple nodes with the window selector or by clicking on multiple node artists while holding Ctrl-C.
The user presses ...
Etc.
so that we could select all the desired vertices by dragging the left mouse button, and then press the button to add a new node
Is this a different functionality you were working on, or did you mean to say "... to add a new edge".
I haven't heard from you in a while, so I am assuming that the issue got resolved on your end. Feel free to re-open if that is not the case.
Hi! Sorry for my absence, I've had some unexpected events.
The behavior I want is as follows :
The user selects the desired vertices (either by dragging the mouse cursor or by clicking on each one individually while holding down control).
The user clicks the insert a new vertex button (insert or +)
A new vertex is added which is already adjacent to all the other vertices selected previously.
I'll leave a gif below with a demonstration of something similar:
Would it be possible to add this functionality?
Welcome back!
Possible? Sure. But it seems you already got it covered (or how else did you make the gif?).
I made some changes to the dev branch to make the implementation of the desired feature more straightforward. Now the desired functionality boils down to the following class:
import matplotlib.pyplot as plt
from netgraph._interactive_graph_classes import MutableGraph
from netgraph._artists import NodeArtist
class GFGraph(MutableGraph):
"""Extends :py:class:`MutableGraph` to support the addition of edges to newly created nodes.
- Double clicking on two nodes successively will create an edge between them.
- Pressing 'insert' or '+' will add a new node to the graph.
- Pressing 'delete' or '-' will remove selected nodes and edges.
- Pressing '@' will reverse the direction of selected edges.
When adding a new node, the properties of the last selected node will be used to style the node artist.
Ditto for edges. If no node or edge has been previously selected the first created node or edge artist will be used.
When adding a new node while other nodes are currently selected,
edges from the selected nodes to the new node will be added as well.
"""
def _on_key_press(self, event):
if event.key in ('insert', '+'):
node = self._add_node(event)
# --------------------
# custom code
new_edges = []
for artist in self._selected_artists:
if isinstance(artist, NodeArtist):
source = self._reverse_node_artists[artist]
new_edges.append(self._add_edge(source, node))
if new_edges:
self.edge_layout.get()
self._update_edge_artists()
self.fig.canvas.draw_idle()
# --------------------
else:
super()._on_key_press(event)
if __name__ == "__main__":
fig, ax = plt.subplots()
instance = GFGraph([(0, 1)], node_labels=True, ax=ax)
plt.show()
I haven't made this behaviour the default for MutableGraph
(yet), as it potentially conflicts with the way that new nodes are styled: new nodes are given the same type and properties as the last node that the user clicked on. The new feature can conflict with this behaviour, if:
1) the source nodes are selected through Ctrl+click, and 2) the source nodes do not have the desired type or properties.
Currently, the only work-around is to 1) click on a node with the desired type and properties, and then 2) select the source nodes with a rectangle selector (which avoids clicking on them).
I will see if I can come up with a decent solution. In the meantime, please leave the issue open lest I forget about.
Welcome back!
Possible? Sure. But it seems you already got it covered (or how else did you make the gif?).
In our software we have a class that inherits from EditableGraph
, and to get the behavior that the gif demonstrates we have overridden the on_key_press
method as follows:
class ResizableGraph(EditableGraph):
...
def _on_key_press(self, event):
...
if event.key == '+' or event.key == '=':
self._add_node(event)
for selected_artist in self._selected_artists:
node = self.find_node(selected_artist)
if node:
self._add_edge((self.nodes[-1], node))
self._update_edges([(self.nodes[-1], node)])
super()._on_key_press(event)
...
However, I believe that the implementation was not done in the best way and we had the problem I reported in the first comment of this issue when the vertices are selected using the rectangle selector instead of ctrl + click.
In our software we have a class that inherits from
EditableGraph
I haven't tested If the approach above works seamlessly if you inherit from EditableGraph
instead of MutableGraph
.
Are you using any of the features of EditableGraph
(i.e. interactive node & edge labeling)?
In our software we have a class that inherits from
EditableGraph
I haven't tested If the approach above works seamlessly if you inherit from
EditableGraph
instead ofMutableGraph
. Are you using any of the features ofEditableGraph
(i.e. interactive node & edge labeling)?
Yes, we use the features of the EditableGraph
. You even helped us implement this class that inherits from EditableGraph
a while ago, in the issue https://github.com/paulbrodersen/netgraph/issues/46.
Thanks for the reminder! ;-)
Have you tested the solution above if all features still work when you inherit from ResizableGraph or EditableGraph? I don't know for sure which features you care about so I can't do it for you.
Sorry for my disappearance again 😅
We tested it and only had one problem:
When we select the nodes that we want by the rectangle
, some edges are also selected because they are in the middle of the path. And then, when inserting a new node, nothing happens and we get the following error in the console:
File “C:\Users\Fernando Pimenta\Documents\Github\GraphFilter\venv\lib\site-packages\matplotlib\cbook\__init__.py”, line 307, in process
func(*args, **kwargs)
File “C:\Users\Fernando Pimenta\Documents\Github\GraphFilter\source\view\project\docks\visualize_graph_dock.py”, line 116, in _on_key_press
self._add_node(event)
File “C:\Users\Fernando Pimenta\Documents\Github\GraphFilter\venv\lib\site-packages\netgraph\_interactive_variants.py”, line 227, in _add_node
node_properties = self._extract_node_properties(self._selected_artists[-1])
File “C:\Users\Fernando Pimenta\Documents\Github\GraphFilter\venv\lib\site-packages\netgraph\_interactive_variants.py”, line 178, in _extract_node_properties
radius = node_artist.radius,
AttributeError: 'EdgeArtist' object has no attribute 'radius'
Debugging a bit, we found that the problem is in this part of the code:
def _add_node(self, event):
# --------------------
if self._selected_artists:
node_properties = self._extract_node_properties(self._selected_artists[-1])
else:
node_properties = self._last_selected_node_properties
Our theory is that it tries to take the properties of the last node that was selected as you mentioned earlier, but since in this case the last artist selected was an edge, it tries to assign edge properties to a node.
But otherwise, everything worked as it should.
Sorry, I just noticed that I forgot to answer. I can't reproduce the problem.
Hello,
I tested the code you posted on May 7th in the development branch and it worked correctly. However, when adapting it to our code, I found the behavior mentioned above.
The adaptation has kept the same code, with the only difference being that the class inherits from EditableGraph
and is using version 4.13.2 made available by the python interpreter.
I bit the bullet and read what looked like the relevant commits in your repo.
The first issue I noticed is that you added a _add_node
method to your ResizableGraph
. As a result, you are not inheriting the (presumably) working _add_node
method from EditableGraph
/MutableGraph
, but are using your own, apparently broken version.
The second issue I noticed is that you changed the indentation of super()._on_key_press(event)
in _on_key_press
, effectively disabling most key press event triggered changes to the class instance.
Should you still encounter problems after reverting these changes, please make sure to post links to the latest commits and latest versions of the relevant files (so I don't spend so much time digging for them).
Hi guys, I hope you're well.
I work on a project called GraphFilter, where we use your library (we've even opened some issues here). Recently, a user asked us about the possibility of adding multiple edges simultaneously. I'd like to know if it's possible to implement this functionality.
We even tried to implement something similar, replacing the
_on_key_press
method, so that we could select all the desired vertices by dragging the left mouse button, and then press the button to add a new node, but we got the following traceback:We are willing to contribute if you find it interesting.
Thank you in advance for all your support!