Add title and legend to igraph plots
igraph, python
Solution
R provides a pretty advanced plotting system on its own and the R interface simply makes use of this so that's why you can simply create plot titles and legends in R. Python does not provide any plotting by default, so igraph uses the Cairo library to draw graph plots. However, Cairo is "just" a generic vector graphics library. That's why you don't get the same advanced plotting capabilities in Python.
The `plot` function of igraph creates a `Plot` object in the background, adds the graph being plotted to the plot itself, creates an appropriate Cairo surface for it, and then starts drawing the graph on the Cairo surface. All this happens behind the scenes if you simply call `plot` with a graph as an argument. However, you can create a `Plot` object manually and then add labels to it before it is being plotted, like this:
>>> plot = Plot("plot.png", bbox=(600, 600), background="white")
At this point, you have a `plot` variable, which is an instance of `igraph.drawing.Plot`. The plot is backed by a Cairo image surface which is 600 pixels wide and 600 pixels high, and which will eventually be saved into a filed named `plot.png`. (You can also supply a Cairo surface directly in the first argument of the `Plot` constructor). Calling `plot.redraw()` would draw the plot but not save it yet. Calling `plot.save()` would draw the plot if it has not been drawn yet and then save it to the given filename.
You can then do two things with a plot:
Add an arbitrary object to the plot that has a `__draw__` method. `Graph` objects have such a method so you can add a graph to the plot as follows:
>>> g = Graph.GRG(100, 0.2)
>>> plot.add(g, bbox=(20, 20, 580, 580))
Grab its `surface` property to access the Cairo surface on which the drawing is done, construct a Cairo drawing context with this surface, and then draw on the plot directly with Cairo using the drawing context.
The second option is how we are going to add labels to the plot. Luckily igraph provides a class named `TextDrawer` in the `igraph.drawing.text` package that helps us a bit with wrapping and alignment issues. We simply have to create a `TextDrawer` and then call its `draw_at` method to add a label to the plot at a given location:
>>> import cairo
>>> context = cairo.Context(plot.surface)
>>> text_drawer = TextDrawer(context, text="Test label", halign=TextDrawer.LEFT)
>>> text_drawer.draw_at(x=100, y=100)
The `TextDrawer` will draw the label with the current font of the Cairo context, so you have to use the `set_font_face`, `set_font_size` and related methods of the Cairo context to adjust the font that is used for drawing.
Putting it all together, the example goes like this:
from igraph import Graph, Plot
from igraph.drawing.text import TextDrawer
import cairo
# Construct the plot
plot = Plot("plot.png", bbox=(600, 650), background="white")
# Create the graph and add it to the plot
g = Graph.GRG(100, 0.2)
plot.add(g, bbox=(20, 70, 580, 630))
# Make the plot draw itself on the Cairo surface
plot.redraw()
# Grab the surface, construct a drawing context and a TextDrawer
ctx = cairo.Context(plot.surface)
ctx.set_font_size(36)
drawer = TextDrawer(ctx, "Test title", halign=TextDrawer.CENTER)
drawer.draw_at(0, 40, width=600)
# Save the plot
plot.save()
The example will add a title to the plot. Constructing a legend is more involved but I hope you can proceed further based on this idea. The labels of the legend can be constructed with repeatedly calling the `draw` or `draw_at` method of a `TextDrawer` (after adjusting the `text` property of the `TextDrawer` between calls of course). You can draw a box around the legend using standard Cairo calls. You can also use the node drawer classes in `igraph.drawing.shapes` if you want to draw node shapes similar to those that igraph uses when it draws a graph.
Problem
In igraph for python, can you add a legend and title to a plot? Neither is mentioned in the manual or the tutorial as far as I can see. It is possible in R however.