问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/18250684/add-title-and-legend-to-igraph-plots