Как аннотировать несколько наборов данных в ListPlots
Часто мне приходится визуализировать несколько наборов данных одновременно, обычно в ListPlot или его Log-компаньонах. Так как количество наборов данных обычно больше, чем количество легко различимых стилей линий, и создание больших легенд сюжета все еще несколько не интуитивно, я все еще ищу хороший способ аннотировать различные линии / наборы на моих графиках. Всплывающая подсказка удобна при работе на экране, но она не помогает, если мне нужно печатать сюжет.
Недавно я поэкспериментировал с опцией Mesh для перечисления наборов данных и нашел некоторые странные вещи
GraphicsGrid[Partition[Table[ListPlot[
Transpose@
Table[{Sin[x], Cos[x], Tan[x], Cot[x]}, {x, 0.01, 10, 0.1}],
PlotMarkers -> {"1", "2", "3", "4"}, Mesh -> i, Joined -> True,
PlotLabel -> "Mesh\[Rule]" <> ToString[i], ImageSize -> 180], {i,
1, 30}], 4]]
Результат выглядит так на моей машине (Windows 7 x64, Mathematica 8.0.1):
Как ни странно, для Mesh->2, 8 и 10 результат выглядит так, как я ожидал, а остальные нет. Либо я не понимаю вариант Mesh, либо он меня не понимает.
Вот мои вопросы:
- Меш в ListPLot прослушивается или я использую его неправильно?
- Как я могу сместить точки сетки последовательных наборов, чтобы избежать наложения надписей?
- У вас есть другие предложения, как аннотировать / перечислять несколько наборов данных на графике?
3 ответа
Вы можете попробовать что-то в этом роде. Сделайте каждую строку кнопкой, которая при нажатии идентифицирует себя.
plot=Plot[{Sin[x],Cos[x]},{x,0,2*Pi}];
sinline=plot[[1,1,3,2]];
cosline=plot[[1,1,4,2]];
message="";
altplot=Append[plot,PlotLabel->Dynamic[message]];
altplot[[1,1,3,2]]=Button[sinline,message="Clicked on the Sin line"];
altplot[[1,1,4,2]]=Button[cosline,message="Clicked on the Cos line"];
altplot
Если вы добавите EventHandler, вы можете получить местоположение, в котором вы щелкнули, и добавить вкладку с соответствующей позиционной меткой на график. Оберните график в динамический, чтобы он обновлялся после каждого нажатия кнопки. Работает нормально.
В ответ на комментарии, вот более полная версия:
plot = Plot[{Sin[x], Cos[x]}, {x, 0, 2*Pi}];
sinline = plot[[1, 1, 3, 2]];
cosline = plot[[1, 1, 4, 2]];
AddLabel[label_] := (AppendTo[plot[[1]],
Inset[Framed[label, Background -> White], pt]];
(* Remove buttons for final plot *)
plainplot = plot;
plainplot[[1, 1, 3, 2]] = plainplot[[1, 1, 3, 2, 1]];
plainplot[[1, 1, 4, 2]] = plainplot[[1, 1, 4, 2, 1]]);
plot[[1, 1, 3, 2]] = Button[sinline, AddLabel["Sin"]];
plot[[1, 1, 4, 2]] = Button[cosline, AddLabel["Cos"]];
Dynamic[EventHandler[plot,
"MouseDown" :> (pt = MousePosition["Graphics"])]]
Чтобы добавить ярлык, нажмите на строку. Окончательный аннотированный график, установленный как "plainplot", пригоден для печати и копирования и не содержит динамических элементов.
[Позже в тот же день] Еще одна версия, на этот раз общая и основанная на первоначальном графике. (С использованием частей решения Марка МакКлюра.) Для разных графиков "ff" и "spec" можно редактировать по желанию.
ff = {Sin, Cos, Tan, Cot};
spec = Range[0.1, 10, 0.1];
(* Plot functions separately to obtain line counts *)
plots = Array[ListLinePlot[ff[[#]] /@ spec] &, Length@ff];
plots = DeleteCases[plots, Line[_?(Length[#] < 3 &)], Infinity];
numlines = Array[Length@Cases[plots[[#]], Line[_], Infinity] &,
Length@ff];
(* Plot functions together for annotation plot *)
plot = ListLinePlot[#@spec & /@ ff];
plot = DeleteCases[plot, Line[_?(Length[#] < 3 &)], Infinity];
lbl = Flatten@Array[ConstantArray[ToString@ff[[#]],
numlines[[#]]] &, Length@ff];
(* Line positions to substitute with buttons *)
linepos = Position[plot, Line, Infinity];
Clear[line];
(* Copy all the lines to line[n] *)
Array[(line[#] = plot[[Sequence @@ Most@linepos[[#]]]]) &,
Total@numlines];
(* Button function *)
AddLabel[label_] := (AppendTo[plot[[1]],
Inset[Framed[label, Background -> White], pt]];
(* Remove buttons for final plain plot *)
plainplot = plot;
bpos = Position[plainplot, Button, Infinity];
Array[(plainplot[[Sequence @@ Most@bpos[[#]]]] =
plainplot[[Sequence @@ Append[Most@bpos[[#]], 1]]]) &,
Length@bpos]);
(* Substitute all the lines with line buttons *)
Array[(plot[[Sequence @@ Most@linepos[[#]]]] = Button[line[#],
AddLabel[lbl[[#]]]]) &, Total@numlines];
Dynamic[EventHandler[plot,
"MouseDown" :> (pt = MousePosition["Graphics"])]]
Вот как это выглядит. После аннотации можно найти простой графический объект с переменной 'plainplot'.
Один из подходов состоит в том, чтобы создавать графики отдельно, а затем показывать их вместе. Это дает код, который больше похож на ваш, чем на другой пост, так как PlotMarkers
кажется, играет так, как мы ожидаем, когда имеем дело с одним набором данных. Мы можем получить ту же окраску, используя ColorData
с PlotStyle
, Вот результат:
ff = {Sin, Cos, Tan, Cot};
plots = Table[ListLinePlot[ff[[i]] /@ Range[0.1, 10, 0.1],
PlotStyle -> {ColorData[1, i]},
PlotMarkers -> i, Mesh -> 22], {i, 1, Length[ff]}];
(* Delete the spurious asymptote looking thingies. *)
plots = DeleteCases[plots, Line[ll_?(Length[#] < 4 &)], Infinity];
Show[plots, PlotRange -> {-4, 4}]
Собираетесь ли вы строить расчетные кривые или фактические данные?
Если это вычисляемые кривые, то обычно используется легенда сюжета (ключ). Вы можете использовать различные штрихи и толщину, чтобы различать линии на принтере в оттенках серого. В документации PlotLegends много примеров.
Если это реальные данные, то, как правило, данные достаточно разрежены, чтобы вы могли использовать PlotMarkers
для фактических точек данных (т.е. не указывать Mesh
). Вы можете использовать автоматический PlotMarkers
, или вы можете использовать пользовательские PlotMarkers
в том числе BoxWhisker
маркеры для обозначения различных неопределенностей.