Советы по созданию графических диаграмм
Я хотел бы программно создавать диаграммы, как это
(источник: yaroslavvb.com)
Я полагаю, что я должен использовать GraphPlot с VertexCoordinateRules, VertexRenderingFunction и EdgeRenderingFunction для графиков. Что я должен использовать для цветных скошенных фонов?
Изменить
Используя в основном идеи Саймона, здесь в упрощенной "менее надежной" версии я использовал
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)
Ответы
Ответ 1
Обобщающий Самсдрам немного отвечает, я получаю
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]} &)]
ИЗМЕНИТЬ № 1:
Очищенную версию этого кода можно найти на http://gist.github.com/663438
ИЗМЕНИТЬ № 2:
Как обсуждалось в комментариях ниже, шаблон, который должен соответствовать мой edges
, - это список правил края с необязательными ярлыками. Это немного меньше общего, чем то, что используется функцией GraphPlot
(и версией в приведенном выше gist), где край правила также могут быть обернуты в Tooltip
.
Чтобы найти точный шаблон, используемый GraphPlot
, я неоднократно использовал Unprotect[fn];ClearAttributes[fn,ReadProtected];Information[fn]
, где fn
является объектом интереса, пока не обнаружил, что он использовал следующую (очищенную) функцию:
Network`GraphPlot`RuleListGraphQ[x_] :=
ListQ[x] && Length[x] > 0 &&
[email protected]@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)[_ -> _, _])..}
эквивалентен и более кратким...
Ответ 2
Для простых примеров, когда вы только соединяете два узла (например, ваш пример справа), вы можете рисовать линии с закрытыми конечными точками, как это.
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]}]
Для более сложных примеров (например, второй справа) я бы рекомендовал рисовать многоугольник, используя координаты вершин, а затем прослеживать край многоугольника с закрытой линией. Я не мог найти способ добавить скошенный край непосредственно к полигону. При прослеживании периметра многоугольника вам нужно добавить координату первой вершины в конец отрезка линии, чтобы линия делала полный периметр полигона. Кроме того, существуют две отдельные графические директивы для строк 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]}]
Ответ 3
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
]
где foo [[1,1,1,1,1]] - список вершинных центров, а {2,5,6} вытягивает вершины {b, e, f}. ({2,5,6,2} закрывает линию в начальной точке.)
Там много места для преувеличения, но я думаю, что это охватывает ингредиент, о котором вы не упомянули выше.