How to annotate multiple datasets in ListPlots

前端 未结 3 1750
时光取名叫无心
时光取名叫无心 2020-12-16 02:23

Frequently I have to visualize multiple datasets simultaneously, usually in ListPlot or its Log-companions. Since the number of datasets is usually larger than the number of

相关标签:
3条回答
  • 2020-12-16 03:19

    Are you going to be plotting computable curves or actual data?

    If it's computable curves, then it's common to use a plot legend (key). You can use different dashings and thicknesses to differentiate between the lines on a grayscale printer. There are many examples in the PlotLegends documentation.

    If it's real data, then normally the data is sparse enough that you can use PlotMarkers for the actual data points (i.e. don't specify Mesh). You can use automatic PlotMarkers, or you can use custom PlotMarkers including BoxWhisker markers to indicate the various uncertainties.

    0 讨论(0)
  • 2020-12-16 03:20

    One approach is to generate the plots separately and then show them together. This yields code that is more like yours than the other post, since PlotMarkers seems to play the way we expect when dealing with one data set. We can get the same coloring using ColorData with PlotStyle. Here's the result:

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

    enter image description here

    0 讨论(0)
  • 2020-12-16 03:24

    You could try something along these lines. Make each line into a button which, when clicked, identifies itself.

    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
    

    If you add an EventHandler you can get the location where you clicked and add an Inset with the relevant positioned label to the plot. Wrap the plot in a Dynamic so it updates itself after each button click. It works fine.

    In response to comments, here is a fuller version:

    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"])]]
    

    To add a label click on the line. The final annotated chart, set to 'plainplot', is printable and copyable, and contains no dynamic elements.

    [Later in the day] Another version, this time generic, and based on the initial chart. (With parts of Mark McClure's solution used.) For different plots 'ff' and 'spec' can be edited as desired.

    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"])]]
    

    Here's how it looks. After annotation the plain graphics object can be found set to the 'plainplot' variable.

    Annotated Chart

    0 讨论(0)
提交回复
热议问题