EdgeRenderingFunction and VertexRenderingFunction help - wolfram-mathematica

I'm trying to construct a LayeredGraphPlot where some nodes connect to other nodes, like a tree. I would like to have the freedom to choose the thickness, color, presence or absence of labeling of each edge.
I would also like to have the freedom to display some vertex names and display some vertices as just "dots". I can't seem to understand how EdgeRenderingFunction and VertexRenderingFunction enable me to do this.
I am new to mathematica. I've clicked on more information on Wolfram help page but it appears to have a vague description and not precise syntax, followed by some cute but unhelpful (to me) examples (As compared to matlab at mathworks where the help provides precise syntax.. at least in my mind).
I have looked up about 10 mathematics books (Smith and Blachman, mathematica demystified.. etc etc) but they all seem to cover the function superficially with one or two examples and not provide the most general syntax.
Can someone help with this and I would also appreciate tips on how to learn mathematica? I'm a smart guy and I should not have so much trouble learning how to use commands.
LayeredGraphPlot[{1->2,1->3,2->4,3->5,3->6}]
So for example, I'd like to:
Suppress all the vertex names except vertices 4,5 and 6.
Color as blue and thick the edges from 3->6, 2->4 and 1->3
All the other edges to be red and thin

VertexRenderingFunction and EdgeRenderingFunction allow you to take explicit control over the way that vertices and edges are drawn in the graph. Both functions are expected to return a symbolic graphics directive (or list of such directives) that is valid for the Graphics command.
Let's start with VertexRenderingFunction. We shall define a new function called drawVertex. A VertexRenderingFunction is called with two arguments: the position of the vertex (as an X/Y co-ordinate pair) and the name of the vertex.
drawVertex[position_, vertex:(4 | 5 | 6)] :=
Inset[Framed[vertex, Background -> LightMagenta], position]
drawVertex[position_, _] :=
{PointSize[Medium], Blue, Point[position]}
Two definitions are provided for drawVertex. The first is only applicable to the vertices 4 or 5 or 6. It draws those vertices as framed labels. The second definition is applicable to all other vertices and draws simple blue points.
Now for an EdgeRenderingFunction named drawEdge. The function will be passed three arguments: the endpoints of the edge, a list of the source and target vertices of the edge, and the label for the edge (if any). In our case, all edges will be drawn as arrows but the colour and thickness will vary depending upon the edge. The helper function edgeStyle is introduced to capture those differences:
drawEdge[ends_, fromTo_, label_] :=
Join[edgeStyle[fromTo], {Arrowheads[{{Automatic, 0.5}}], Arrow[ends]}]
edgeStyle[{3, 6} | {2, 4} | {1, 3}] :=
{Blue, Thick}
edgeStyle[_] :=
{Red, Thin}
With these definitions in place, we can now use them in conjunction with LayeredGraphPlot to produce a customized diagram:
LayeredGraphPlot[{1 -> 2, 1 -> 3, 2 -> 4, 3 -> 5, 3 -> 6},
VertexRenderingFunction -> drawVertex, EdgeRenderingFunction -> drawEdge ]

LayeredGraphPlot[
{1 -> 2, 1 -> 3, 2 -> 4, 3 -> 5, 3 -> 6},
VertexRenderingFunction ->
(If[Intersection[{4, 5, 6}, {#2}] != {},
{White, EdgeForm[Black], Disk[#, .1], Black, Text[#2, #1]},
{PointSize[Large], Point[#1]}] &),
EdgeRenderingFunction ->
(If[Intersection[{{3, 6}, {2, 4}, {1, 3}}, {#2}] != {},
{Blue, Thick, Line[#1]},
{Red, Line[#1]}] &)
]
Mathematica syntax is daunting at first glance. Almost every powerful tool is.
I think the short snippets provided here in StackOverflow as answers to new Mma users are a good starting point for the first steps. Please note that there are also advanced and much more difficult questions posted.
Mathematica is not intended for the casual user. If you are not planning to invest some time in learning and getting accustomed, I suggest trying another tool.
Finally, the LayeredGraphPlot[] function is not covered in depth in the help system, simply because it is a cousin of GraphPlot[], whose help page is the root for all Graph...[] family help searches.

I mimicked your code and managed to produce something very close to what I actually wanted. Thanks a lot for your help!
{drawVertex[position_,
vertex : (1111 | 1112 | 1121 | 1122 | 1211 | 1212 | 1221 | 1222)] :=
Inset[Framed[
Text[If[vertex == 1111, "80,70",
If[vertex == 1112, "50,60",
If[vertex == 1121, "105,50", If[vertex == 1122, "70,55",
If[vertex == 1211, "70,40",
If[vertex == 1212, "90,50",
If[vertex == 1221, "85,60", "40,50"]]]]]]]],
Background -> White], position]
drawVertex[position_, _] := {PointSize[Medium], Blue, Point[position]}
drawEdge[ends_, fromTo_,
label_] := {Join[
edgeStyle[fromTo], {Arrowheads[{{Automatic, 1}}], Arrow[ends]}],
Text[label, Mean[ends]]}
edgeStyle[{1, 11} | {11, 111} | {111, 1111}] := {Blue, Thick}
edgeStyle[_] := {Red, Thin}
LayeredGraphPlot[{{1 -> 11, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"1\", \"L\"}]]\)"}, {1 -> 12, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"1\", \"R\"}]]\)"}, {11 -> 111,
"\!\(\*SubscriptBox[\"H\", \"L\"]\)"}, {11 -> 112,
"\!\(\*SubscriptBox[\"H\", \"H\"]\)"}, {12 -> 121,
"\!\(\*SubscriptBox[\"H\", \"L\"]\)"}, {12 -> 122,
"\!\(\*SubscriptBox[\"H\", \"H\"]\)"}, {111 -> 1111,
"\!\(\*SubscriptBox[\"C\",
RowBox[{\"0\", \"L\"}]]\)"}, {111 -> 1112, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"0\", \"H\"}]]\)"}, {112 -> 1121, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"0\", \"L\"}]]\)"}, {112 -> 1122, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"0\", \"H\"}]]\)"}, {121 -> 1211, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"0\", \"L\"}]]\)"}, {121 -> 1212, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"0\", \"H\"}]]\)"}, {122 -> 1221, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"0\", \"L\"}]]\)"}, {122 -> 1222, "\!\(\*SubscriptBox[\"C\",
RowBox[{\"0\", \"H\"}]]\)"}}, EdgeRenderingFunction -> drawEdge,
VertexRenderingFunction -> drawVertex]}

Related

How is the BarSpacing option really implemented in Mathematica?

I'm trying to implement a DateListBarChart function that takes dated data and outputs a bar chart with the same placements as DateListPlot. It's essential that they plot data in the same horizontal position if given the same data, so they can be combined using Show. I am finding it difficult to get the settings for BarSpacing right so that the horizontal range of the plot doesn't change, and the bars stay in essentially the same place.
I have been unable to infer the correct scaling so that BarSpacing->{0.2,0.3} results in 20% of the x-axis length available for that group of bars is taken up with spacing between bars in that group, and 30% as spacing between groups of bars. For technical reasons I am doing this by passing things to RectangleChart. According to the documentation, BarSpacing is treated as absolute units in RectangleChart. Obviously the absolute sizes of the gaps need to be smaller if there are more series, and the bars need to be narrower.
Some examples:
arList = FoldList[0.9 #1 + #2 &, 0.01, RandomReal[NormalDistribution[0, 1], 24]]
{0.01, 0.334557, 2.02709, 1.1878, 1.9009, 3.08604, 2.36652, 3.04111,
3.32364, 3.22662, 3.12626, 2.59118, 1.69334, 1.21069, 0.23171,
0.689415, -0.852649, -0.124624, 0.58604, -0.481886, 0.221074,
-0.300329, 2.36137, 0.427789, -1.47747}
dists = RandomChoice[{3, 4}, Length[arList]]
{4, 4, 4, 3, 4, 3, 4, 3, 4, 4, 3, 4, 4, 3, 4, 4, 4, 4, 3, 4, 3, 3, 3, 3, 3}
Results in:
RectangleChart[Transpose[{dists - 0 - 0/2, arList}],
PlotRange -> {{0, 100}, {-2, 4}}, ChartStyle -> EdgeForm[None],
Frame -> True, GridLines -> Automatic, BarSpacing -> {0, 0}]
RectangleChart[Transpose[{dists - 0.7 - 0.5/2, arList}],
PlotRange -> {{0, 100}, {-2, 4}}, ChartStyle -> EdgeForm[None],
Frame -> True, GridLines -> Automatic, BarSpacing -> {0.7, 0.5}]
Notice how the data aren't spanning the same distance along the x-axis as the previous example.
It gets even messier when trying to chart multiple series (the same in this example, for illustration).
RectangleChart[
Transpose[{{dists - i/2 - j/2, arList}, {dists - i/2 - j/2,
arList}}, {2, 3, 1}], PlotRange -> {{0, 180}, {-2, 4}},
ChartStyle -> EdgeForm[None], Frame -> True, Ticks -> None,
GridLines -> Automatic, BarSpacing -> {i, j}]
I've been futzing for ages trying to find the right formula so that BarSpacing settings for the custom function (not seen here) induce the correct spacings and bar widths so that the horizontal plot range doesn't change as the BarSpacing does.
What am I missing?
EDIT: In response to belisarius, this is an example of where I am heading. It works, kind of (the bars aren't quite in alignment with the line, but this is probably the dates I am using) but the cases with stacked bars fail to plot with the bars where they should be, as do any kind of bar graph on its own where there are multiple series. (I'm quite proud of the date label placement algorithm: the powers that be at work don't want to give up that look.)
And here is one that just isn't working. The data should fill the horizontal range. (The different width bars are deliberate - it's a combination of annual and quarterly data.)
EDIT 2
I remember why I didn't use Filling in a DateListPlot to draw the bars as in Mike Honeychurch's package - if you have anything other than very skinny bars, they end up having the top edge in the wrong place.
DateListPlot[{dateARList},
PlotStyle -> {AbsolutePointSize[6], Yellow}, Filling -> {1 -> 0},
FillingStyle -> {1 -> {{AbsoluteThickness[12], Darker[Red, 0.25]}}},
PlotRange -> All]
Maybe using the ChartElementFunction option instead of BarSpacing helps. For example barplot in the code would plot a bar chart such that each bar has margins of gapl on the left and gapr on the right where gapl and gapr are fractions of the total width of the bar
scale[{{xmin_, xmax_}, {ymin_, ymax_}}, {gapl_, gapr_}] :=
{{xmin (1 - gapl) + xmax gapl, ymin}, {xmax (1 - gapr) + xmin gapr, ymax}}
barplot[dists_, arList_, {gapl_, gapr_}, opts___] :=
RectangleChart[Transpose[{dists, arList }], opts,
Frame -> True,
GridLines -> Automatic, BarSpacing -> 0,
ChartElementFunction -> (Rectangle ## scale[#, {gapl, gapr}] &)]
Usage:
To plot the original bar chart with no gaps
barplot[dists, arList, {0, 0}]
This would plot a bar chart with a margin of 0.2 on both sides which results in a bar chart with gaps of 0.4 times the total width of the bars. Note that the positions of the bars matches with those in the first figure.
barplot[dists, arList, {0.2, 0.2}]
You can plot multiple series by doing something like
Show[barplot[dists, arList 0.9, {0, 0.5}],
barplot[dists, arList 0.8, {0.5, 0}, ChartStyle -> LightGreen]]
You may relieve your complaint about FillingStyle by using CapForm["Butt"].
list = {0.01, -0.81, 0.12, 0.81, 1.79, 1.1, 0.41, 1., 1.33, 1.08,
2.16, 1.13, 1.92, 1.64, 1.31, 1.94, 1.71, 0.91, 2.32, 0.95, 1.29,
1.28, 2.97, 4.45, 5.11}
DateListPlot[list, {2000, 8},
PlotStyle -> {AbsolutePointSize[6], Yellow}, Filling -> {1 -> 0},
FillingStyle -> {1 -> {{CapForm["Butt"], AbsoluteThickness[14],
Darker[Red, 0.25]}}}, PlotRange -> {0, 6}, ImageSize -> 400]

How to choose the numbers shown on the axes of a plot in mathemetica?

I have already checked all the examples and settings in the Mathematica documentation center, but couldn't find any example on how to choose the numbers that will be shown on the axes.
How do I change plot axis numbering like 2,4,6,.. to PI,2PI,3PI,...?
Howard has already given the correct answer in the case where you want the labels Pi, 2 Pi etc to be at the values Pi, 2 Pi etc.
Sometimes you might want to use substitute tick labels at particular values, without rescaling data.
One of the other examples in the documentation shows how:
Plot[Sin[x], {x, 0, 10},
Ticks -> {{{Pi, 180 \[Degree]}, {2 Pi, 360 \[Degree]}, {3 Pi,
540 \[Degree]}}, {-1, 1}}]
I have a suite of small custom functions for formatting Ticks the way I want them. This is probably too much information if you are just starting out, but it is worth knowing that you can use any number format and substitute anything into your ticks if desired.
myTickGrid[min_, max_, seg_, units_String, len_?NumericQ,
opts : OptionsPattern[]] :=
With[{adj = OptionValue[UnitLabelShift], bls = OptionValue[BottomLabelShift]},
Table[{i,
If[i == max,
DisplayForm[AdjustmentBox[Style[units, LineSpacing -> {0, 12}],
BoxBaselineShift -> If[StringCount[units, "\n"] > 0, adj + 2, adj]]],
If[i == min,
DisplayForm#AdjustmentBox[Switch[i, _Integer,
NumberForm[i, DigitBlock -> 3,
NumberSeparator -> "\[ThinSpace]"], _, N[i]],
BoxBaselineShift -> bls],
Switch[i, _Integer, NumberForm[i, DigitBlock -> 3,
NumberSeparator -> "\[ThinSpace]"], _, N[i]]]], {len, 0}}, {i,
If[Head[seg] === List, Union[{min, max}, seg], Range[min, max, seg]]}]]
And setting:
Options[myTickGrid] = {UnitLabelShift -> 1.3, BottomLabelShift -> 0}
SetOptions[myTickGrid, UnitLabelShift -> 1.3, BottomLabelShift -> 0]
Example:
Plot[Erfc[x], {x, -2, 2}, Frame -> True,
FrameTicks -> {myTickGrid[-2, 2, 1, "x", 0.02, UnitLabelShift -> 0],
myTickGrid[0, 2, {0.25, .5, 1, 1.8}, "Erfc(x)", 0.02]}]
You can find an example here:
Ticks -> {{Pi, 2 Pi, 3 Pi}, {-1, 0, 1}}
Ticks also accepts a function, which will save you the trouble of listing the points manually or having to change the max value each time. Here's an example:
xTickFunc[min_, max_] :=
Table[{i, i, 0.02}, {i, Ceiling[min/Pi] Pi, Floor[max/Pi] Pi, Pi}]
Plot[Sinc[x], {x, -5 Pi, 5 Pi}, Ticks -> {xTickFunc, Automatic},
PlotRange -> All]
If you want more flexibility in customizing your ticks, you might want to look into LevelScheme.

VertexCoordinate Rules and VertexList from GraphPlot Graphic

Is there any way of abstracting the vertex order that GraphPlot applies to VertexCoordinate Rules from the (FullForm or InputForm) of the graphic produced by GraphPlot? I do not want to use the GraphUtilities function VertexList. I am also aware of GraphCoordinates, but both of these functions work with the graph, NOT the graphics output of GraphPlot.
For example,
gr1 = {1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6, 6 -> 1};
gp1 = GraphPlot[gr1, Method -> "CircularEmbedding",
VertexLabeling -> True];
Last#(gp1 /. Graphics[Annotation[x___], ___] :> {x})
gives the following list of six coordinate pairs:
VertexCoordinateRules -> {{2., 0.866025}, {1.5, 1.73205}, {0.5,
1.73205}, {0., 0.866025}, {0.5, 1.3469*10^-10}, {1.5, 0.}}
How do I know which rule applies to which vertex, and can I be certain that this is
the same as that given by VertexList[gr1]?
For example
Needs["GraphUtilities`"];
gr2 = SparseArray#
Map[# -> 1 &, EdgeList[{2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6}]];
VertexList[gr2]
gives {1, 2, 3, 4, 5}
But ....
gp2 = GraphPlot[gr2, VertexLabeling -> True,
VertexCoordinateRules ->
Thread[VertexList[gr1] ->
Last#(gp1 /. Graphics[Annotation[x___], ___] :> {x})[[2]]]];
Last#(gp2 /. Graphics[Annotation[x___], ___] :> {x})
gives SIX coordinate sets:
VertexCoordinateRules -> {{2., 0.866025}, {1.5, 1.73205}, {0.5,
1.73205}, {0., 0.866025}, {0.5, 1.3469*10^-10}, {1.5, 0.}}
How can I abstract the correct VertexList for VertexCoordinateRules for gr2, for example?
(I am aware that I can correct things by taking the VertexList after generating gr2 as follows, for example)
VertexList#
SparseArray[
Map[# -> 1 &, EdgeList[{2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6}]], {6, 6}]
{1, 2, 3, 4, 5, 6}
but the information I need appears to be present in the GraphPlot graphic: how can I obtain it?
(The reason I convert the graph to an adjacency matrix it that, as pointed out by Carl Woll of Wolfram, it allows me to include an 'orphan' node, as in gp2)
With vertex labeling, one way is to get coordinates of the labels. Notice that output of GraphPlot is in GraphicsComplex where coordinates of coordinate aliases are as first label, you can get it as
points = Cases[gp1, GraphicsComplex[points_, __] :> points, Infinity] // First
Looking at FullForm you'll see that labels are in text objects, extract them as
labels = Cases[gp1, Text[___], Infinity]
The actual label seems to be two levels deep so you get
actualLabels = labels[[All, 1, 1]];
Coordinate alias is the second parameter so you get them as
coordAliases = labels[[All, 2]]
Actual coordinates were specified in GraphicsComplex, so we get them as
actualCoords = points[[coordAliases]]
There a 1-1 correspondence between list of coordinates and list of labels, so you can use Thread to return them as list of "label"->coordinate pairs.
here's a function that this all together
getLabelCoordinateMap[gp1_] :=
Module[{points, labels, actualLabels, coordAliases, actualCoords},
points =
Cases[gp1, GraphicsComplex[points_, __] :> points, Infinity] //
First;
labels = Cases[gp1, Text[___], Infinity];
actualLabels = labels[[All, 1, 1]];
coordAliases = labels[[All, 2]];
actualCoords = points[[coordAliases]];
Thread[actualLabels -> actualCoords]
];
getLabelCoordinateMap[gp1]
Not that this only works on labelled GraphPlot. For ones without labels you could try to extract from other graphics objects, but you may get different results depending on what objects you extract the mapping from because there seems to be a bug which sometimes assigns line endpoints and vertex labels to different vertices. I've reported it. The way to work around the bug is to either always use explicit vertex->coordinate specification for VertexCoordinateList, or always use "adjacency matrix" representation. Here's an example of discrepancy
graphName = {"Grid", {3, 3}};
gp1 = GraphPlot[Rule ### GraphData[graphName, "EdgeIndices"],
VertexCoordinateRules -> GraphData[graphName, "VertexCoordinates"],
VertexLabeling -> True]
gp2 = GraphPlot[GraphData[graphName, "AdjacencyMatrix"],
VertexCoordinateRules -> GraphData[graphName, "VertexCoordinates"],
VertexLabeling -> True]
BTW, as an aside, here are the utility functions I use for converting between adjacency matrix and edge rule representation
edges2mat[edges_] := Module[{a, nodes, mat, n},
(* custom flatten to allow edges be lists *)
nodes = Sequence ### edges // Union // Sort;
nodeMap = (# -> (Position[nodes, #] // Flatten // First)) & /#
nodes;
n = Length[nodes];
mat = (({#1, #2} -> 1) & ### (edges /. nodeMap)) //
SparseArray[#, {n, n}] &
];
mat2edges[mat_List] := Rule ### Position[mat, 1];
mat2edges[mat_SparseArray] :=
Rule ### (ArrayRules[mat][[All, 1]] // Most)
If you execute FullForm[gp1] you'll get a bunch of output which I won't post here. Near the start of the output you'll find a GraphicsComplex[]. This is, essentially, a list of points and then a list of uses of those points. So, for your graphic gp1 the beginning of the GraphicsComplex is:
GraphicsComplex[
List[List[2., 0.866025], List[1.5, 1.73205], List[0.5, 1.73205],
List[0., 0.866025], List[0.5, 1.3469*10^-10], List[1.5, 0.]],
List[List[RGBColor[0.5, 0., 0.],
Line[List[List[1, 2], List[2, 3], List[3, 4], List[4, 5],
List[5, 6], List[6, 1]]]],
The first outermost list defines the positions of 6 points. The second outermost list defines a bunch of lines between those points, using the numbers of the points within the first list. It's probably easier to understand if you play around with this.
EDIT: In response to OP's comment, if I execute:
FullForm[GraphPlot[{3 -> 4, 4 -> 5, 5 -> 6, 6 -> 3}]]
I get
Graphics[Annotation[GraphicsComplex[List[List[0.`,0.9997532360813222`],
List[0.9993931236462025`,1.0258160108662504`],List[1.0286626995939243`,
0.026431169015735057`],List[0.02872413637035287`,0.`]],List[List[RGBColor[0.5`,0.`,0.`],
Line[List[List[1,2],List[2,3],List[3,4],List[4,1]]]],List[RGBColor[0,0,0.7`],
Tooltip[Point[1],3],Tooltip[Point[2],4],Tooltip[Point[3],5],Tooltip[Point[4],6]]],
List[]],Rule[VertexCoordinateRules,List[List[0.`,0.9997532360813222`],
List[0.9993931236462025`,1.0258160108662504`],
List[1.0286626995939243`,0.026431169015735057`],List[0.02872413637035287`,0.`]]]],
Rule[FrameTicks,None],Rule[PlotRange,All],Rule[PlotRangePadding,Scaled[0.1`]],
Rule[AspectRatio,Automatic]]
The list of vertex positions is the first list inside the GraphicsComplex. Later in the FullForm you can see the list where Mathematica adds tooltips to label the vertices with the identifiers you supplied in the original edge list. Since what you are now looking at is the code describing a graphic there's only an indirect relationship between your vertices and what will be plotted; the information is all there but not entirely straightforward to unpack.
p2 = Normal#gp1 // Cases[#, Line[points__] :> points, Infinity] &;
p3 = Flatten[p2, 1];
ListLinePlot[p3[[All, 1 ;; 2]]]
V12.0.0

Getting VertexRenderingFunction to (not) scale

I'm having problem with custom VertexRenderingFunction showing at different sizes for different graphs. An example is below, the default vertex rendering function has the desired behavior since vertices look the same in all graphs, any suggestion how to achieve that with custom vertices?
(source: yaroslavvb.com)
edges = Most[
ArrayRules[GraphData[{"Path", 5}, "AdjacencyMatrix"]]][[All, 1]];
doit[vrf_] :=
Print /# Table[
GraphPlot[Rule ### edges[[k ;;]], VertexRenderingFunction -> vrf,
VertexLabeling -> True], {k, 1, Length[edges]}];
doit[({White, EdgeForm[Black], Disk[#, .1], Black, Text[#2, #1]} &)];
doit[Automatic];
Update, 1 hour later:
Michael Pilat as usual gives the solution, here's what it looks like with (Inset[Graphics[{White, EdgeForm[Black], Disk[{0, 0}, .05], Black,
Text[#2, {0, 0}]}, ImageSize -> 25], #] &) for rendering function
(source: yaroslavvb.com)
Inset a Graphics expression with the ImageSize option to place your vertices:
GraphPlot[Rule ### edges,
VertexRenderingFunction -> (Inset[
Graphics[{White, EdgeForm[Black], Disk[{0, 0}, .05], Black,
Text[#2, {0, 0}]}, ImageSize -> 25], #] &),
VertexLabeling -> True]
ImageSize can take a variety of values from printer's points to a Scaled value.
Inset can also/instead take a size in its fourth argument, but the default setting defers to the ImageSize of the inset Graphics object, which is a little cleaner to use in this case.
Hope that helps!

tips for creating Graph diagrams

I'd like to programmatically create diagrams like this
(source: yaroslavvb.com)
I imagine I should use GraphPlot with VertexCoordinateRules, VertexRenderingFunction and EdgeRenderingFunction for the graphs. What should I use for colored beveled backgrounds?
Edit
Using mainly Simon's ideas, here's a simplified "less robust" version I ended up using
Needs["GraphUtilities`"];
GraphPlotHighlight[edges_, verts_, color_] := Module[{},
vpos = Position[VertexList[edges], Alternatives ## verts];
coords = Extract[GraphCoordinates[edges], vpos];
(* add .002 because end-cap disappears when segments are almost colinear *)
AppendTo[coords, First[coords] + .002];
Show[Graphics[{color, CapForm["Round"], JoinForm["Round"],
Thickness[.2], Line[coords], Polygon[coords]}],
GraphPlot[edges], ImageSize -> 150]
]
SetOptions[GraphPlot,
VertexRenderingFunction -> ({White, EdgeForm[Black], Disk[#, .15],
Black, Text[#2, #1]} &),
EdgeRenderingFunction -> ({Black, Line[#]} &)];
edges = GraphData[{"Grid", {3, 3}}, "EdgeRules"];
colors = {LightBlue, LightGreen, LightRed, LightMagenta};
vsets = {{8, 5, 2}, {7, 5, 8}, {9, 6, 3}, {8, 1, 2}};
MapThread[GraphPlotHighlight[edges, #1, #2] &, {vsets, colors}]
(source: yaroslavvb.com)
Generalising Samsdram's answer a bit, I get
GraphPlotHighlight[edges:{((_->_)|{_->_,_})..},hl:{___}:{},opts:OptionsPattern[]]:=Module[{verts,coords,g,sub},
verts=Flatten[edges/.Rule->List]//.{a___,b_,c___,b_,d___}:>{a,b,c,d};
g=GraphPlot[edges,FilterRules[{opts}, Options[GraphPlot]]];
coords=VertexCoordinateRules/.Cases[g,HoldPattern[VertexCoordinateRules->_],2];
sub=Flatten[Position[verts,_?(MemberQ[hl,#]&)]];
coords=coords[[sub]];
Show[Graphics[{OptionValue[HighlightColor],CapForm["Round"],JoinForm["Round"],Thickness[OptionValue[HighlightThickness]],Line[AppendTo[coords,First[coords]]],Polygon[coords]}],g]
]
Protect[HighlightColor,HighlightThickness];
Options[GraphPlotHighlight]=Join[Options[GraphPlot],{HighlightColor->LightBlue,HighlightThickness->.15}];
Some of the code above could be made a little more robust, but it works:
GraphPlotHighlight[{b->c,a->b,c->a,e->c},{b,c,e},VertexLabeling->True,HighlightColor->LightRed,HighlightThickness->.1,VertexRenderingFunction -> ({White, EdgeForm[Black], Disk[#, .06],
Black, Text[#2, #1]} &)]
EDIT #1:
A cleaned up version of this code can be found at http://gist.github.com/663438
EDIT #2:
As discussed in the comments below, the pattern that my edges must match is a list of edge rules with optional labels. This is slightly less general than what is used by the GraphPlot function (and by the version in the above gist) where the edge rules are also allowed to be wrapped in a Tooltip.
To find the exact pattern used by GraphPlot I repeatedly used Unprotect[fn];ClearAttributes[fn,ReadProtected];Information[fn] where fn is the object of interest until I found that it used the following (cleaned up) function:
Network`GraphPlot`RuleListGraphQ[x_] :=
ListQ[x] && Length[x] > 0 &&
And##Map[Head[#1] === Rule
|| (ListQ[#1] && Length[#1] == 2 && Head[#1[[1]]] === Rule)
|| (Head[#1] === Tooltip && Length[#1] == 2 && Head[#1[[1]]] === Rule)&,
x, {1}]
I think that my edges:{((_ -> _) | (List|Tooltip)[_ -> _, _])..} pattern is equivalent and more concise...
For simple examples where you are only connecting two nodes (like your example on the far right), you can draw lines with capped end points like this.
vertices = {a, b};
Coordinates = {{0, 0}, {1, 1}};
GraphPlot[{a -> b}, VertexLabeling -> True,
VertexCoordinateRules ->
MapThread[#1 -> #2 &, {vertices, Coordinates}],
Prolog -> {Blue, CapForm["Round"], Thickness[.1], Line[Coordinates]}]
For more complex examples (like second from the right) I would recommend drawing a polygon using the vertex coordinates and then tracing the edge of the polygon with a capped line. I couldn't find a way to add a beveled edge directly to a polygon. When tracing the perimeter of the polygon you need to add the coordinate of the first vertex to the end of the line segment that the line makes the complete perimeter of the polygon. Also, there are two separate graphics directives for lines CapForm, which dictates whether to bevel the ends of the line, and JoinForm, which dictates whether to bevel the intermediate points of the line.
vertices = {a, b, c};
Coordinates = {{0, 0}, {1, 1}, {1, -1}};
GraphPlot[{a -> b, b -> c, c -> a}, VertexLabeling -> True,
VertexCoordinateRules ->
MapThread[#1 -> #2 &, {vertices, Coordinates}],
Prolog -> {Blue, CapForm["Round"], JoinForm["Round"], Thickness[.15],
Line[AppendTo[Coordinates, First[Coordinates]]],
Polygon[Coordinates]}]
JoinForm["Round"] will round the joins of line segments.
You'll want a filled polygon around the centers of the vertices in the colored region, then a JoinForm["Round"], ..., Line[{...}] to get the rounded corners.
Consider
foo = GraphPlot[{a -> b, a -> c, b -> d, b -> e, b -> f, c -> e, e -> f},
VertexRenderingFunction ->
({White, EdgeForm[Black], Disk[#, .1], Black, Text[#2, #1]} &)]
Show[
Graphics[{
RGBColor[0.6, 0.8, 1, 1],
Polygon[foo[[1, 1, 1, 1, 1, {2, 5, 6, 2}]]],
JoinForm["Round"], Thickness[0.2],
Line[foo[[1, 1, 1, 1, 1, {2, 5, 6, 2}]]]
}],
foo
]
where foo[[1,1,1,1,1]] is the list of vertex centers and {2,5,6} pulls out the {b,e,f} vertices. ({2,5,6,2} closes the line back at its starting point.)
There's plenty of room for prettifying, but I think this covers the ingredient you didn't mention above.

Resources