How to draw an arrow edge with ArrowEdgeDrawer in python-graph? - python

I want to draw a plot which shows a graph being transformed to another graph using python-graph. So I need an single arrow pointing from the first graph to the second. I'm considering using ArrowEdgeDrawer class, but I cannot find out how to use it properly. Any one can offer me a demo of creating and using an ArrowEdgeDrawer object will be appreciated.

ArrowEdgeDrawer is not meant to be used to draw arbitrary arrows on a plot; as its name implies, it is an edge drawer. Graph drawer classes use ArrowEdgeDrawer by default to draw undirected edges as straight lines and directed edges as lines with arrowheads, therefore the public methods of ArrowEdgeDrawer take two graph vertices as arguments and not arbitrary points on a plot. In a really convoluted way, you could probably create a "fake" graph containing two invisible vertices (with vertex shape = "none") and a directed edge between them, and then overlay this graph on top of your actual graphs, but I think it is much easier to draw on the drawing canvas directly. igraph uses Cairo as the drawing backend, and you can access the Cairo surface of an igraph plot using the surface property of an appropriately constructed Plot object. You can then create a Cairo drawing context for the surface and draw on it directly. For example:
from igraph import Graph, Plot
from cairo import Context
# Create two graphs
g = Graph.Ring(5)
g2 = Graph.Full(5)
# Create a figure containing the two graphs
fig = Plot("test.pdf", bbox=(800, 360), background="white")
fig.add(g, bbox=(20,20,340,340))
fig.add(g2, bbox=(460,20,780,340))
# Force the figure to be drawn
fig.redraw()
# Create a Cairo drawing context
ctx = Context(fig.surface)
# Draw an arrow
ctx.set_source_rgb(0,0,0)
ctx.move_to(360,180)
ctx.line_to(430,180)
ctx.stroke()
ctx.move_to(440,180)
ctx.line_to(430,170)
ctx.line_to(430,190)
ctx.line_to(440,180)
ctx.fill()
# Save the figure
fig.save()

Related

How to plot subgraph of a networkx multipartite graph as a new graph with refreshed positions

NetworkX offers G.subgraph(node_list) but when I plot it, it retains the node positions in the original full multipartite graph which is messy. I want the subgraph to be recalculated as a new plot (relatively centered) still retaining its multipartite layers but cleaner in terms of nodes vertical position. I'm using hvplot for displaying the graph using hvplot.networkx as hvnx. Additionally with this subplot from hvplot, there are some strange lines coming from the graph which don't show when i just use nx.draw(G.subgraph(node_list), pos).
Thanks.
Solved both the problems.
by creating new position layout by passing in the subgraph instead of main graph.
corrected hvnx output by converting the graph to undirected.
GU = G.subgraph(node_list).to_undirected()
pos = nx.multipartite_layout(GU, subset_key="layer")
hvnx.draw(GU, pos)

Plotting points within a triangle

I'm using Python, and I have some data which can be projected on to points within an equilateral triangle whose side lengths sum to 1.
I'm not sure if there is an easy way to visualise a plot like this from Matplotlib or similar libraries, or if I'm just going to have to use a drawing package from scratch to make it happen. Any pointers gratefully recieved. Thanks!
If all you want to do is plot a few dots on a graph, you can infact use Matfplotlib's scatter plots for this:
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html
Using plt.xlim(*min*, *max*) and plt.ylim(*min*, *max*), you can set the limits of the graph manually to fit your values (might not be neccessary though).
You can draw lines on the graph for the triangle shape (if you need that): How to draw a line with matplotlib?
If you don't need a scale, you can even remove that to have a blank canvas: Matplotlib plots: removing axis, legends and white spaces

Set zorder for the labels (vertex_text) in graph_tool

I have a case in which vertex_text is hidden behind the one of the vertices (indicated by the red square in the image below). I have drawn this network using graph_tool's circular layout (minimize_nested_blockmodel_dl).
In the graph_tools docs (https://graph-tool.skewed.de/static/doc/draw.html), I did not find any way to set the zorder for the vertex_text.
I wonder if setting zorders for elements is possible in graph_tool. I would like to know if there is any workaround for this, while keeping the plot and the labels as they are i.e. same size, layout and locations.
If this is useful, for reference, here's are the vertex related parameters I used that went into the draw module:
vertex_text=[list of labels],
vertex_fill_color=[list of colors],
valpha=1,
vertex_size=10,
vertex_pen_width=0,
vertex_text_position=-2,
This can be done using the vorder parameter, which determines the relative order with which nodes and their labels are drawn.

Reuse result of stochastic python-igraph layout for future plotting

I can successfully draw a nice network using the kk layout. Unfortunately, as kk is a stochastic layout, it looks different every time I plot it.
Is there a way to plot it twice with the same vertex and node arrangement but varying the visual style? I would like to visualize changes by changing the vertex colors and showing both plots side-by-side. Of course, in the future I might be interested in modifying edges too but this is not an issue right now.
I'm completely fine with the fact that the layout changes for every run of my programm, it should just plot it consistently within one run.
I can plot it twice if I save the resulting SVG but of course modyfining the underlying graph would be more elegant than just tweaking the raw SVG.
This plots the same layout twice but only as SVG:
s = cairo.SVGSurface(None, 800, 800)
model = ig.plot(g, **visual_style,
vertex_label=[label_for_title(vertex[1]['title']) for vertex in enumerate(g.vs)],
edge_color=[color_for_rating(edge[1]['rating']) for edge in enumerate(g.es)],
target=s,
mark_groups=action_systems)._repr_svg_()
display(SVG(model))
display(SVG(model))
Yes, there is, because igraph lets you store the layout of the vertices as an object: my_layout = g.layout('kk').
So you can plot your graph g multiple times with the same layout:
my_layout = g.layout('kk')
igraph.plot(g,layout=my_layout)
#now change g and/or the visual style
g.delete_edges([0,3,4])
igraph.plot(g,layout=my_layout,vertex_color=['blue' for _ in g.vs])
The new plotted graph will have the same vertex positions but now a few edges will be gone and all the vertices will be blue, naturally.

draw a large graph with many nodes and edges with igraph

I'm trying to visualize a big data set of nodes and edges and I have two files: nodes.txt and edges.txt and I want draw a graph for them. it's got 403,394 nodes and 3,387,388 edges. good to know I generate them randomly.
So I decide using igraph python to draw it by layout and plot but when I try to draw a simple graph with few edges it works but with this huge data set it got an memory error and doesn't work right. I want some help to draw a graph from my edge list with igraph. or maybe there is some better way to do, so suggest it to me.
I use layout with Drl algorithm and use the function plot.

Categories