In a previous answer posted by Simon Woods on the question of how to automatically locate non-overlapping labels to data shown in a ListPlot; see below:

Using this as the as a starting point from the original question:

data=Table[{t,Re[3 Exp[I 5/2 t]]-t,Im[5 Exp[I 5/2 t]]},{t,0,10}];
labels=Text["Label " <>ToString[#[[1]]],1.1 #[[{2,3}]]]&/@data
Show[dataPlot, Graphics[{Red, labels}], PlotRange -> 10{{-1, 1}, {-1, 1}}, AspectRatio->1]

Simon Wood's proposed this solution:

  xi=bd MapThread[Rescale,{x,p}];
  xx=Table[xi+a o Reverse[ls],{a,{1,-1,0}}];
  p1=First@Pick[pos,Negative[d-2 Min[d]]];

addlabels[g_Graphics,labels_, o_:{0,0}]:=Fold[Show[#1, positionlabel[##, o]]&, g, labels] 

I found this to work well with low point density, but it becomes too confusing with a large number of points. It seems that a visual guide to the label would be very helpful. How would one add a line between each data point and its label and still use basic solution for placing the labels, which prevents overlap?

For reference this is something I found that shows what I am looking to achieve with the exception that it doesn't automatically place the Labels:

Deploy@DynamicModule[{pt=({##2}&@@@data),pt2=(2 {##2}&@@@data),
ListPlot[List/@pt,PlotStyle->PointSize[Large],PlotRange->30 {{-1,1},`enter code here`{-1,1}},AspectRatio->1,
    Locator[Dynamic@pt2[[#]],Style[lbls[[#]],colors[[#]],"Panel"]]}&/@Range [Length@pt]])]]

Which would result in this after manually moving the labels:

Mathematica graphics

I am having difficulty determining the resulting location of the each Label form Simon's solution which is needed to define each Line segment to each point in the point.

Hopefully I have uploaded the example code and images correctly, but this is the first time I have used stack exchange.

Kind Regards,

Charles Koehler


1 Answer 1

data = Table[{t, Re[3 Exp[I 5/2 t]] - t, Im[5 Exp[I 5/2 t]]}, {t, 0, 10}];
labels2 = {Style["Label " <> ToString[#[[1]]], 12], 1.1 #[[{2, 3}]]} & /@ data;
llp = addlabels[ListPlot[List /@ data[[All, {2, 3}]], 
   BaseStyle -> PointSize -> Large], labels2]

enter image description here

First, we extract the scaled coordinates of Insets and Rescale them using PlotRange[llp]. We create a rule associating each label with its rescaled coordinates:

insetLabelsToCoords = Cases[llp, Inset[lbl_, Scaled[coord_], ___] :> 
   (First@ lbl -> (Rescale[#, {0, 1}, #2]&@@@Thread[{coord, PlotRange[llp]}])), Infinity];

We create a second rule associating each original coordinate with its label:

coordsToLabels = #[[2;;3]] -> "Label " <> ToString[#[[1]]] & /@ data;

For each point in data we find the coordinates of the Inset containing the label of that point:

lines = Line[{#[[2;;3]] /. coordsToLabels /. insetLabelsToCoords, #[[2;;3]]} & /@ data];

Show[llp, Graphics[{Arrowheads[.02], Arrow@lines}], ImageSize -> 500]

enter image description here

Original answer:

An alternative approach using Callout:

data2 = {Callout[#[[2;;3]],"Label " <> ToString[#[[1]]], 
         Background -> LightGray, CalloutMarker -> "Circle"]} & /@ data;

ListPlot[data2, BaseStyle -> PointSize -> Large]

enter image description here

  • $\begingroup$ Hello kglr, Thanks for both answers, they both have merit. The Callout solution is easy to use but it has the problem of allowing overlapping Labels, while the first solution is very close to what I need, it seems to arbitrarily position the start of the arrow at the center of the label as opposed to a location around the Label that is closest to the point. $\endgroup$ Jul 14, 2017 at 19:53
  • $\begingroup$ Hi @Charles, I can't think of a straightforward way for finding the location around the Label that is closest to the point. This would require finding the bounding boxes of the labels (which depends on the size of label content) in addition to the centers obtained from Simon's function. $\endgroup$
    – kglr
    Jul 14, 2017 at 20:29
  • $\begingroup$ Hi @kglr, at this point is seems too difficult to make this work any better. In my usage I will only use the Label and Arrow function to identify outliers in my data plots. Thank you for your help for now. If I find or develop any improvements I will post them to share. Best Regards: $\endgroup$ Jul 17, 2017 at 14:37
  • $\begingroup$ @Charles, thank you for the accept. $\endgroup$
    – kglr
    Jul 17, 2017 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.