创建图表的技巧

15

我希望能够以编程的方式创建像这样的图表:
(来源:yaroslavvb.com)

我想我应该使用GraphPlot、VertexCoordinateRules、VertexRenderingFunction和EdgeRenderingFunction来绘制图形。那么什么可以用于着色斜角背景呢?

编辑 主要使用Simon的思路,这是我最终使用的简化版"不太健壮"

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}]


(来源:yaroslavvb.com)


你是如何制作你问题中使用的图表的? - Simon
在网上找到了它们。我怀疑是使用某些Latex包完成的。 - Yaroslav Bulatov
Wolfram在http://www.youtube.com/watch?v=8afAaSiwD78的9:15左右谈到了“highlight graph function”--也许它将会内置在下一个版本中? - Simon
有趣...顺便说一下,看起来技术会议演示笔记已经发布了(尽管沃尔夫拉姆的没有)-- http://www.wolfram.com/events/techconf2010/speakers.html - Yaroslav Bulatov
http://reference.wolfram.com/mathematica/ref/HighlightGraph.html - Simon
3个回答

11

稍微概括一下Samsdram的答案,我得到了

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}];

上面的一些代码可以更加健壮一些,但它能够工作:

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]} &)]

Mathematica图形


编辑#1: 这段代码的清理版本可以在http://gist.github.com/663438找到。

编辑#2: 正如下面的评论所讨论的那样,我的edges必须匹配的模式是带有可选标签的边规则列表。这比由GraphPlot函数(以及上面本中使用的内容)稍微不够通用,其中边规则也允许包装在Tooltip中。

为了找到GraphPlot使用的确切模式,我反复使用Unprotect[fn];ClearAttributes[fn,ReadProtected];Information[fn],其中fn是感兴趣的对象,直到我发现它使用了以下(清理后)函数:

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}]
我认为我的edges:{((_ -> _) | (List|Tooltip)[_ -> _, _])..}模式是等效且更加简洁的...

你想用“edges”模式匹配什么? - Yaroslav Bulatov
GraphPlot 生成的 GraphicsComplex 中顶点的顺序就是它们在 edges 中出现的顺序。我的 verts=... 只是一种获取顶点列表的丑陋方式,以便我知道从 g 中提取哪些坐标并传递给 Graphics 命令。这是一个权宜之计,因为如果 VertexLabeling->False,那么 GraphPlot 不会保留任何关于哪个顶点是哪个的信息。 - Simon
2
@Yaroslav 三个步骤(抱歉有点乱...)(1)Unprotect[GraphPlot];ClearAttributes[GraphPlot,ReadProtected];Information[GraphPlot] (2)Unprotect[NetworkGraphPlotDumpPrivateRuleListGraphQ];ClearAttributes[NetworkGraphPlotDumpPrivateRuleListGraphQ,ReadProtected];Information[NetworkGraphPlotDumpPrivateRuleListGraphQ] (3)Unprotect[NetworkGraphPlotRuleListGraphQ];ClearAttributes[NetworkGraphPlotRuleListGraphQ,ReadProtected];Information[NetworkGraphPlotRuleListGraphQ]` - Simon
@Simon,你最后两条评论非常有趣!你能否编辑你的答案并将它们包含进去?在这里,评论中它们几乎被隐藏起来,对于未来的读者来说不太方便,我猜你花了很多力气才挖掘出来。 - Dr. belisarius
@belisarius 谢谢。这并不是我的答案的一部分,但你是正确的,这些东西确实会在评论中丢失。我已经编辑了我的答案。 - Simon
显示剩余6条评论

5

对于仅连接两个节点的简单示例(例如您在最右侧的示例),您可以绘制带有帽状端点的线条,如下所示。

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]}]

Mathematica graphics

对于更复杂的示例(如最右边的图形),建议使用顶点坐标绘制多边形,然后使用带有盖头的线跟踪多边形的边缘。我无法找到直接向多边形添加斜角边缘的方法。在跟踪多边形周长时,您需要将第一个顶点的坐标添加到使线段完整覆盖多边形周长的线段的末尾。此外,有两个用于线条的不同图形指令:CapForm,它决定是否将线的末端斜角化,以及JoinForm,它决定是否将线的中间点斜角化。

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]}]

Mathematica graphics


你如何使用它来仅突出显示顶点的子集? - Simon

4

JoinForm["Round"]可以使线段的连接处变得圆润。

你需要在彩色区域的顶点中心周围绘制填充多边形,然后使用JoinForm["Round"], ..., Line[{...}]来获得圆角效果。

考虑以下代码:

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
]
Mathematica graphics

其中foo[[1,1,1,1,1]]是顶点中心的列表,而{2,5,6}则提取出{b,e,f}的顶点。({2,5,6,2}将线条闭合至起点。)

还有很多可以美化的地方,但我认为这已经涵盖了你上面没有提到的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接