Labeling And Highlighting

Min-Hsuan Peng, Wolfram

(RowDefault[, (Spacer1), , (Spacer1), ])  #WolframTechConf

ABSTRACT

Quick review of automatic labeling and highlighting

Labeling and highlighting clinic: curated questions

GraphicsRow[{
ListLogLogPlot[countrydata[[All,2;;3]]->countrydata[[All,1]],PlotTheme->"Detailed",FrameLabel->Automatic],Plot[Cos[x Sin[x]],{x,0,2Pi},PlotHighlighting->Placed["Dropline",Pi],ImageSize->300]}]

Types of automation

Optimize the distance between labels

Plot[Evaluate[Table[BesselJ[x,n],{n,1,5}]],{x,0,3},PlotLabels->Automatic]

TimelinePlot[historicalperiods,PlotLayout->"Vertical",PlotRangePadding->None]

PieChart[Sort@RandomReal[10,20],
ChartLabels->Callout[RandomWord[20]],PlotRange->All]

Automatic stacking

TimelinePlot[historicalperiods,ImageSize->600,PlotRangePadding->None]

BarChart[RandomInteger[10,20],
ChartLabels->Callout[RandomWord[20]]]

Feature collision avoidance: Point

SeedRandom[1];ListPlot[RandomReal[1,{50,2}]->RandomWord[50],LabelingFunction->Labeled[Automatic],ImageSize->400,LabelStyle->12]

ListPlot[RandomReal[1,{50,2}]->RandomWord[50],LabelingFunction->Callout[Automatic]]

SeedRandom[2];
BubbleChart[RandomReal[1,{30,3}],
ChartLabels->Callout[RandomWord[30]],
LabelStyle->12
]

Feature collision avoidance: Line

GraphicsGrid[Partition[Table[
Plot[Sin[i x],{x,0,10},
PlotLabels->Callout[HoldForm[Sin[Pi]],Automatic,Pi,CalloutMarker->"Circle"],
ImageSize->550
]
,{i,4}],2],ImageSize->800]

Type of automatic highlighting

Preset effects: style, Ball, Dropline, XSlice, YSlice

Components: point, line and label

({{      , , "IndicatedPoint"}, {      , , "NearestPoint"}, {      , , "XNearestPoint"}, {      , , "YNearestPoint"}})({{      , , "Crosshairs"}, {      , , "XYDroplines"}, {      , , "XLine"}, {      , , "YLine"}, {      , , "XDropline"}, {      , , "YDropline"}})({{      , , "XYLabel"}, {      , , "XLabel"}, {      , , "YLabel"}, {      , , "XYAxisLabels"}, {      , , "XAxisLabel"}, {      , , "YAxisLabel"}})

Ball

IndicatedPoint + XYLabel

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->"Ball"]

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->{"IndicatedPoint","XYLabel"},
Mesh->All,
MeshStyle->Directive[PointSize[0.01],Red]]

Dropline

IndicatedPoint + XYDroplines + XYLabel

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->"Dropline"]

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->{"IndicatedPoint","XYDroplines","XYLabel"}]

XSlice

XNearestPoint + XLine + YLabel

Plot[{Sinc[x],Sin[x]},{x,-2Pi,2Pi},PlotHighlighting->"XSlice"]

Plot[{Sinc[x],Sin[x]},{x,-2Pi,2Pi},PlotHighlighting->{"XNearestPoint","XLine","YLabel"}]

YSlice

YNearestPoint + YLine + XLabel

highlight all points along a horizontal slice

ParametricPlot[ReIm[(1/(((-(1/2)+(E^(I ω))))^2))],{ω,0,2Pi},PlotHighlighting->"YSlice"]

Labeling clinic

Why aren’t all of my labels shown?

ListPlot[{Callout[{1.7404133545310005`,0.9943079488168214`},"Si"],{1.7431478537360878`,0.996636142267291`},{1.7458823529411753`,0.9934257981652584`},Callout[{2.0193322734499195`,1.031526392234193`},"P"],{2.022066772655007`,1.0063035818317037`},{2.0248012718600945`,0.9795130652397709`}},PlotRange->All]

Diagnosis: The automatic labeling algorithm avoids placing labels on top of other points and outside of plot range. In this example, there is no place to put label “Si” without violating the prime directives.

Solution 1: Increase PlotRangePadding

ListPlot[{Callout[{1.7404133545310005`,0.9943079488168214`},"Si"],{1.7431478537360878`,0.996636142267291`},{1.7458823529411753`,0.9934257981652584`},Callout[{2.0193322734499195`,1.031526392234193`},"P"],{2.022066772655007`,1.0063035818317037`},{2.0248012718600945`,0.9795130652397709`}},PlotRangePadding->Scaled[0.1]]

Solution 2 : Change PlotRange

ListPlot[{Callout[{1.7404133545310005`,0.9943079488168214`},"Si"],{1.7431478537360878`,0.996636142267291`},{1.7458823529411753`,0.9934257981652584`},Callout[{2.0193322734499195`,1.031526392234193`},"P"],{2.022066772655007`,1.0063035818317037`},{2.0248012718600945`,0.9795130652397709`}},PlotRange->{{1.70,2.05},All}]

Solution 3: Add LabelVisibility

ListPlot[{Callout[{1.7404133545310005`,0.9943079488168214`},"Si",LabelVisibility->All],{1.7431478537360878`,0.996636142267291`},{1.7458823529411753`,0.9934257981652584`},Callout[{2.0193322734499195`,1.031526392234193`},"P"],{2.022066772655007`,1.0063035818317037`},{2.0248012718600945`,0.9795130652397709`}}]

Why aren’t all of my labels shown even with bigger image size

SeedRandom[1];ListPlot[RandomReal[1,{40,2}]->RandomWord[40],ImageSize->Automatic]

Diagnosis: Resizing the graphics doesn’t re-run the algorithm and the image size of the output cell is cached.

Solution: Set ImageSize explicitly

SeedRandom[1];ListPlot[RandomReal[1,{40,2}]->RandomWord[40],ImageSize->600]

But I really want all of my labels to be shown despite of overlapping

SeedRandom[1];ListPlot[RandomReal[NormalDistribution[],{40,2}]->RandomWord[40]]

Solution 1: Use LabelingFunction -> Callout to force every callout to be shown, change ImageSize, or label size

*comparing to Callout[Automatic]

SeedRandom[1];ListPlot[RandomReal[NormalDistribution[],{40,2}]->RandomWord[40],LabelingFunction->Callout]

SeedRandom[1];ListPlot[RandomReal[NormalDistribution[],{40,2}]->RandomWord[40],
LabelingFunction->Callout,
LabelStyle->10,
ImageSize->600]

Solution 2: Use LabelingSize to shorten the labels with ellipsis

SeedRandom[1];ListPlot[RandomReal[NormalDistribution[],{40,2}]->RandomWord[40],
LabelingSize->100,
LabelingFunction->Callout,
ImageSize->600]

flags=EntityValue[(EntityClass["Europe", EntityClass["Country","Europe"], "EntityClass[\"Country\", \"Europe\"]", "countries"]),"FlagImage"];

ListPlot[DimensionReduce[flags,2,Method->"TSNE",PerformanceGoal->"Quality"]->flags,
LabelingFunction->Callout,
LabelingSize->25,
Axes->False,
AspectRatio->1]

Can I force the labels to appear only in certain positions?

ListPlot[Range[10],LabelingFunction->(Callout[RandomWord[]]&)]

ListPlot[Range[10],LabelingFunction->(Callout[RandomWord[],Top]&)]

Solution: Use Method option AllowedPositions

"AllowedPositions" -> {"TopRight","TopLeft","BottomLeft","BottomRight",Right,Top,Left,Bottom};

SeedRandom[1];ListPlot[Range[10],LabelingFunction->(Callout[RandomWord[],Method->{"AllowedPositions"->{Right,Left}}]&)]

SeedRandom[1];ListPlot[{Sort@RandomReal[10,10],Sort@RandomReal[10,10]->RandomWord[10]}]

SeedRandom[1];ListPlot[{Sort@RandomReal[10,10],Sort@RandomReal[10,10]->RandomWord[10]},LabelingFunction->Callout[Automatic,Method->{"AllowedPositions"->{"TopLeft",Left,"BottomLeft"}}]]

Help! Adding a Callout changed the plot range!

g1=Plot[Sin[x],{x,0,2Pi},
Frame->True
]

g2=Plot[Sin[x],{x,0,2Pi},
PlotLabels->Callout[HoldForm["x = Pi"],Pi],
Frame->True
]

Diagnosis: Adding a Callout changes automatic plot range padding

Solution: Set PlotRangePadding explicitly

Plot[Sin[x],{x,0,2Pi},
PlotLabels->Callout[Automatic,Pi],
Frame->True,
PlotRangePadding->{{Scaled[0.02],Scaled[0.02]},{Scaled[0.05],Scaled[0.05]}}
]

How to change leader size for my callout?

Also, why isn’t my label pointing exactly at Pi/2?

Plot[Callout[Sin[x],"sin(x)",Pi/2,LeaderSize->50],{x,0,2 Pi}]

Diagnosis: The 3rd argument is label position and the 4th is leader position. If the label position is specified, the leader size cannot change it.

Solution: Set the label position to automatic and the leader position to Pi/2

Plot[Callout[Sin[x],"sin(x)",Automatic,Pi/2],{x,0,2 Pi}]

Plot[Callout[Sin[x],"sin(x)",Automatic,Pi/2,LeaderSize->50],{x,0,2 Pi}]

Highlighting clinic

Where did my automatic highlighting go?

Plot[Tooltip[Sin[x]],{x,0,2Pi}]

Diagnosis: Wrappers that use mouseover behavior take precedence over automatic highlighting.

Solution: Set PlotHighlighting explicitly to overwrite wrapper behavior

Yes, Tooltip will be shadowed if a “Ball” highlighting is used

Plot[Tooltip[Sin[x]],{x,0,2Pi},PlotHighlighting->"XYLabel"]

*compare to different highlighting methods like “XYLabel”

How do I change the label in a highlight

Plot[Sin[x],{x,0,2Pi}]

Solution: Use LabelingFunction parameter for the highlighting component

Plot[Sin[x],{x,0,2Pi},
PlotHighlighting->{"Ball",<|LabelingFunction->(Grid[Transpose@{{"x:","y:"},{Style[#[[1]],Red],Style[#[[2]],Blue]}}]&)|>}]

Follow-up: How to show more digits in the label?

Diagnosis: Highlighting labels are formatted strings of the coordinates

Solution: The workaround is to use ToExpression to convert the formatted string back to a numeric value

Plot[Sin[x],{x,0,2Pi},
PlotHighlighting->{"Ball",<|LabelingFunction->((Row[{"Sin[",NumberForm[ToExpression[#[[1]]]/Pi,4],"π] = ",ToExpression[#[[2]]]}])&)|>}]

Follow-up: Can I use a different labeling function for each curve?

Plot[{Sin[x],Cos[x]},{x,0,2Pi},
PlotHighlighting->{"Ball",<|LabelingFunction->((Row[{"Sin[",ToExpression[#[[1]]]/Pi,"π] = ",ToExpression[#[[2]]]}])&)|>}]

Diagnosis: The option PlotHighlighting applies overall highlighting to every curve

Solution:  To use a different labeling function for each curve, use wrapper Highlighted

Plot[{
Highlighted[Sin[x],{"Ball",<|LabelingFunction->((Row[{"Sin[",NumberForm[ToExpression[#[[1]]]/Pi,3],"π] = ",NumberForm[ToExpression[#[[2]]],3]}])&)|>}],
Highlighted[Cos[x],{"Ball",<|LabelingFunction->((Row[{"Cos[",NumberForm[ToExpression[#[[1]]]/Pi,3],"π] = ",NumberForm[ToExpression[#[[2]]],3]}])&)|>}]
},{x,0,2Pi}]

Q from Brett’s talk: Can I put one callout always on the left and one on the right of the slice line?

Plot[{Sin[x],Cos[x]},{x,0,2Pi},PlotHighlighting->{"XSlice"}]

Solution: Use the new method “AllowedPositions” for Callout

Plot[{
Highlighted[Sin[x],{"XLine","XNearestPoint",{"XYLabel",<|Method->{"AllowedPositions"->{Left}}|>}}],
Highlighted[Cos[x],{"XNearestPoint",{"XYLabel",<|Method->{"AllowedPositions"->{Right}}|>}}]
},{x,0,2Pi}]

Thank you

Init

$PlotTheme={"Presentation","Medium","Bold","ThickLine","PastelColor"};
countrydata=EntityValue[LinguisticAssistant,{"Name","Area","Population"}];
historicalperiods={(Entity["Afsharid Dynasty", Entity["HistoricalPeriod","AfsharidDynasty"], "Entity[\"HistoricalPeriod\", \"AfsharidDynasty\"]", "historical period"]),(Entity["Initial period", Entity["HistoricalPeriod","InitialPeriod"], "Entity[\"HistoricalPeriod\", \"InitialPeriod\"]", "historical period"]),(Entity["Joseon Dynasty", Entity["HistoricalPeriod","JoseonDynasty"], "Entity[\"HistoricalPeriod\", \"JoseonDynasty\"]", "historical period"]),(Entity["Liao Dynasty", Entity["HistoricalPeriod","LiaoDynasty"], "Entity[\"HistoricalPeriod\", \"LiaoDynasty\"]", "historical period"]),
(Entity["Nara period", Entity["HistoricalPeriod","NaraPeriod"], "Entity[\"HistoricalPeriod\", \"NaraPeriod\"]", "historical period"]),(Entity["Old Kingdom", Entity["HistoricalPeriod","OldKingdom"], "Entity[\"HistoricalPeriod\", \"OldKingdom\"]", "historical period"]),(Entity["Samanid Dynasty", Entity["HistoricalPeriod","SamanidDynasty"], "Entity[\"HistoricalPeriod\", \"SamanidDynasty\"]", "historical period"]),(Entity["Space Age", Entity["HistoricalPeriod","SpaceAge"], "Entity[\"HistoricalPeriod\", \"SpaceAge\"]", "historical period"]),(Entity["Tahirid Dynasty", Entity["HistoricalPeriod","TahiridDynasty"], "Entity[\"HistoricalPeriod\", \"TahiridDynasty\"]", "historical period"]),(Entity["Taishō period", Entity["HistoricalPeriod","TaishoPeriod"], "Entity[\"HistoricalPeriod\", \"TaishoPeriod\"]", "historical period"])};