Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Un)directed mixed graph #82

Open
lcastri opened this issue Feb 6, 2024 · 5 comments
Open

(Un)directed mixed graph #82

lcastri opened this issue Feb 6, 2024 · 5 comments

Comments

@lcastri
Copy link

lcastri commented Feb 6, 2024

Hi there! Is there the possibility to generate a graph with some edges that are directed (with arrow) and some undirected?

Thank you,
Luca

@paulbrodersen
Copy link
Owner

It's not a feature that is currently supported, but I will add it to the TODO list.

The only workaround I can see is to plot the network twice, first all edges with arrow heads and then the remaining ones (or vice-versa).

Figure_1

import matplotlib.pyplot as plt
import netgraph

edges = [(0, 1), (1, 2), (2, 0)]

# set or precompute node positions
pos = {
    0 : (0.1, 0.1),
    1 : (0.9, 0.1),
    2 : (0.5, 0.7),
}

fig, ax = plt.subplots()
netgraph.Graph(edges[:-1], nodes=[0, 1, 2], node_layout=pos, arrows=True, ax=ax)
netgraph.Graph(edges[-1:], nodes=[0, 1, 2], node_layout=pos, arrows=False, ax=ax)
plt.show()

If the desired node_alpha is less than one, one of the two function calls to Graph should be with node_alpha set to zero.
Note that the interactive variants won't work properly with this workaround (at least I would be surprised if they did!).

@paulbrodersen
Copy link
Owner

Actually, I came up with a better way that doesn't break interactive Graph variants.

Similarly, to issue #83, you can simply instantiate the Graph object (or any of its derived classes), and then manipulate the edge artists individually, and either add or remove arrows by setting the head_width and head_length attributes appropriately.

Figure_1

import matplotlib.pyplot as plt

from netgraph import Graph

fig, ax = plt.subplots()
g = Graph([(0, 1), (1, 2), (2, 0)], arrows=True, node_labels=True, ax=ax)
edge_artist = g.edge_artists[(0, 1)]
edge_artist.head_width = 1e-12 # don't set them to zero as this can cause numerical issues 
edge_artist.head_length = 1e-12
edge_artist._update_path()
plt.show()

@lcastri
Copy link
Author

lcastri commented Feb 9, 2024

Hi,

Thank you for the solutions; the second one seems to be the best.

I tried to play around with the library and managed to achieve a similar result with minimal modifications.

I defined a dictionary called "arrows":

arrows = {
(0, 1)  : False, 
(1, 2)  : True,
(2, 0) : True
}

Then, I used the dictionary in the graph definition:

fig, ax = plt.subplots()
g = Graph([(0, 1), (1, 2), (2, 0)], arrows=arrows, node_labels=True, ax=ax)
plt.show()

To implement this, I only needed to modify the "draw_edges" method in the "_main.py" script as follows:

if arrows[edge]:
    head_length = 2 * edge_width[edge]
    head_width = 3 * edge_width[edge]
else:
    head_length = 0
    head_width = 0

instead of

if arrows:
    head_length = 2 * edge_width[edge]
    head_width = 3 * edge_width[edge]
else:
    head_length = 0
    head_width = 0

However, I haven't extensively tested this modification for all types of graphs, so I do not know what else it can affects.

Luca

@paulbrodersen
Copy link
Owner

Hi Luca, your proposal is very similar to what I have in mind. Basically, the plan is to support 3 cases:

  1. arrows is a just a boolean. Everything remains as before to retain backwards compatibility.
  2. arrows is a dict.
    a) arrows is a dict mapping edge IDs to a boolean (= your suggestion).
    b) arrows is a dict mapping edge IDs to a tuple (head length, head width) (= solution for issue Changing arrow size while keeping edge width intact #83).

Would that work for you?

@lcastri
Copy link
Author

lcastri commented Feb 9, 2024

Yes absolutely :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants