Here is an interactive version, with definition below.
A functional plot,
functionplot=Plot[{Sin[x],Cos[x]},{x,0,2\[Pi]},
Frame->{True,True,False,False},
FrameLabel->{"x","y(x)"},
FrameStyle->Directive[13,Italic],
PlotStyle->Thick,
PlotRangeClipping->False,
PlotRange->{-1.2,1.2},
AxesStyle->Dashed];
To label this plot with specified labels for each curve (Sin
, Cos
), run the following to get automatically updating labels based on mouse pointer proximity to each curve; click with the mouse to stick labels wherever you wish:
dynamicLabeled[functionplot,{{Sin,"Sine"},{Cos,"Cosine"}}]

(The above image does not do justice to the Dynamic interactivity.)
It works with ListPlot
too:
data1=Table[{x,.5Exp[-1/2 ((x-5)/1)^2]+RandomReal[NormalDistribution[0,.05]]},{x,0,10,.25}];
data2=Table[{x,-Sin[x]+RandomReal[NormalDistribution[0,.08]]},{x,2,8,.1}];
dataplot=ListPlot[{data1,data2},
PlotStyle->{Thick,PointSize[0.015]},
PlotRange->{-1.2,1.45},
Joined->{True,False}];
dynamicLabeled[dataplot,{{data1,"Exponential"},{data2,"Sinusoidal"}}]

The current state of the plot for the dynamicPlot most recently clicked can be stored in a global variable for later processing or export. In the code below this is set to currentPlot
.
Some parts are hard-coded (arrow styling and label styling)---you can tune those to suit, or extend the flexibility. It does not handle mixed functional-data plots, but that is easy to circumvent by turning the data into an InterpolatingFunction
, or displaying the function as a Table
of points. Have fun.
Here is the definition of dynamicLabeled
:
Clear[dynamicLabeled];
dynamicLabeled[plot_,labelling_] := DynamicModule[
{p,x,x1,x2,storedlabels={},currentlabel,aspect,distances,xs,rs,res,ind,ps,ps1,curves,labels,pt},
curves=labelling[[All,1]];
labels=labelling[[All,2]];
aspect=Options[plot,AspectRatio][[1,2]];
Dynamic[
p=MousePosition["Graphics"];
If[p=!=None,
pt={p[[1]],p[[2]]/aspect};
Switch[curves,
_?(VectorQ[#,AtomQ]&),
(* list of functions *)
rs=Quiet@FindMinimum[Norm[pt-{x,#[x]/aspect}],{x,p[[1]]}]&/@curves;
res={#[[1]],#[[2,1,2]]}&/@rs;
distances=res[[All,1]];
xs=res[[All,2]];
ps=Quiet@MapThread[{#1,#2[#1]}&,{xs,curves}];,
_,
(* functions is a list of data *)
ps1=Flatten[Nearest[#,pt,1]]&/@(curves/.{x_?NumericQ,y_?NumericQ}:>{x,y/aspect});
distances=Norm[#-pt]&/@ps1;
ps=ps1/.{x_?NumericQ,y_?NumericQ}:>{x,y*aspect};
];
ind=Flatten[Position[distances,Min[distances]]][[1]];
];
MouseAppearance[
EventHandler[
currentPlot = Show[plot,
Epilog->{
storedlabels,
If[p=!=None,
currentlabel={
Text[Style[labels[[ind]],13],p,{0,Sign[ps[[ind]][[2]]-p[[2]]]}],
Arrow[{p,ps[[ind]]}]
}
]
}
],
{{"MouseClicked",1}:>(AppendTo[storedlabels,currentlabel])}
],
Graphics[{PointSize[0],Point[{0,0}]}]
]
]
]
PlotLegends`
is horrible in the question without being stubborn about wanting to kludge through with it! Welcome, please go through Jens' awesome answer for what you want. If you want to place the label on each curve separately, then I suggest you look at this answer by Simon $\endgroup$PlotLegends
is the answer you're asking the wrong question :) I second R.Ms recommendation re: code from Jens and Simon. It is always preferable to roll your own legends IMO. $\endgroup$PlotLegends
is aweful. Once I accepted that and created my own system, I've been better off. $\endgroup$