Automatic Labeling

MinHsuan Peng, Wolfram

Abstract

Automated Labeling in visualization was introduced in Wolfram Language in version 10.4. In version 12, we extended the feature into many 2D and 3D visualization functions. 
Labeling automation includes algorithms that find label locations with minimal conflicts, optimization problems for adjusting positions for chart and curve labels, and resizing non-textual labels to fit in the graphics for maximal display.

FlipView[{Plot[Callout[PDF[NormalDistribution[0,2],x],"click me",1.9],{x,-4,4},PlotRange->{{-6,6},{0,0.25}},PlotLabels->Callout["𝒩(0,2)",Above,LabelStyle->20]],Plot[Callout[ghostfunction[x],"boo",Automatic,1.75,LabelStyle->20],{x,-4,4},PlotRange->{{-6,6},{0,0.25}}]}]

Twitch Talk - Labeled Visualization

What’s New in 12 - Labeled Visualization

Labels in Data Visualization

Label automation can enhance data visualization.

Example - Population vs GDP(per capita)

Mostly you see:

RectangleChart[EntityValue[(EntityClass["Group of 7", EntityClass["Country","GroupOf7"], "EntityClass[\"Country\", \"GroupOf7\"]", "countries"]),EntityFunction[e,{e["Population"],((e["GDP"])/(e["Population"]))}]],ChartLabels->Placed[EntityValue[(EntityClass["Group of 7", EntityClass["Country","GroupOf7"], "EntityClass[\"Country\", \"GroupOf7\"]", "countries"]),"Name"],Axis,Rotate[#,90Degree]&],LabelStyle->20,AxesLabel->{"Population","GDPPerCapita"},Frame->False,Axes->True,ImageSize->700,ColorFunction->(ColorData["IslandColors"][#2]&)]

Better:

RectangleChart[EntityValue[(EntityClass["Group of 7", EntityClass["Country","GroupOf7"], "EntityClass[\"Country\", \"GroupOf7\"]", "countries"]),EntityFunction[e,{e["Population"],e["GDP"]/e["Population"]}]],ChartLabels->Placed[EntityValue[(EntityClass["Group of 7", EntityClass["Country","GroupOf7"], "EntityClass[\"Country\", \"GroupOf7\"]", "countries"]),"Name"],Center,Rotate[#,90Degree]&],ImageSize->600,LabelStyle->20,FrameLabel->{"Population","GDPPerCapita"},ColorFunction->(ColorData["IslandColors"][#2]&)]

Even better:

FlipView@Table[RectangleChart[EntityValue[(EntityClass["Group of 7", EntityClass["Country","GroupOf7"], "EntityClass[\"Country\", \"GroupOf7\"]", "countries"]),EntityFunction[e,{e["Population"],e["GDP"]/e["Population"]}]],ChartLabels->Callout[EntityValue[(EntityClass["Group of 7", EntityClass["Country","GroupOf7"], "EntityClass[\"Country\", \"GroupOf7\"]", "countries"]),"Name"],LabelStyle->size],FrameLabel->{"Population","GDPPerCapita"},ColorFunction->(ColorData["IslandColors"][#2]&),ImageSize->700],{size,{16,20,24,28}}]

example -energy production of G6

data=;
data=MapAt[Callout[#,"zero nuclear since 1990"]&,data,{3,2}];
data=MapAt[Callout[#,"never had nuclear"]&,data,{4,2}];
BarChart[data,ChartLabels->{Callout[{"France","Germany","Italy","Poland","Spain","United Kingdom"},LabelStyle->24],None},]

Labels in Data Visualization

Labeled

useful for adding individual information

Labeled[exp, "label",…]

{ListPlot[{1,Labeled[3,"label"],2,4,3},AspectRatio->1,ImageSize->300,Frame->True,FrameTicks->None,LabelStyle->24,PlotStyle->PointSize[0.05`],PlotMarkers->None],
GeoListPlot[{Labeled[(Entity["New York City", Entity["City",{"NewYork","NewYork","UnitedStates"}], "Entity[\"City\", {\"NewYork\", \"NewYork\", \"UnitedStates\"}]", "city"]),"NYC"],(Entity["Boston", Entity["City",{"Boston","Massachusetts","UnitedStates"}], "Entity[\"City\", {\"Boston\", \"Massachusetts\", \"UnitedStates\"}]", "city"]),(Entity["Buffalo", Entity["City",{"Buffalo","NewYork","UnitedStates"}], "Entity[\"City\", {\"Buffalo\", \"NewYork\", \"UnitedStates\"}]", "city"])},]
}

Callout

useful for adding individual information with extra clarification

Callout[exp, "label",…]

{ListPlot[{1,Callout[3,"label",LeaderSize->15],2,4,3},],
PieChart[{10,Callout[10,"label"],5,1,7},]
}

PlotLabels, ChartLabels

useful for adding labels respectively to the data

PlotLabels -> {(Subscript[label, 1]),(Subscript[label, 2]),…}

ChartLabels -> {{(Subscript[label, 1]),(Subscript[label, 2]),…},…}

SeedRandom[4];{ListLinePlot[{{3,1,4,2,6},{2,1,4,6,7},{5,1,6,7,4}},PlotLabels->{"label1","label2","label3"},AspectRatio->1,ImageSize->375,Frame->True,FrameTicks->None,LabelStyle->16,PlotStyle->PointSize[0.05`]],
ListPlot[{
RandomReal[BinormalDistribution[{1,2},{1,6},0.4],60],
RandomReal[BinormalDistribution[{2,1},{3,1},0.7],60]},PlotLabels->Callout[{"label1","label2"},Above],AspectRatio->1,ImageSize->300,Frame->True,FrameTicks->None,LabelStyle->24,PlotStyle->PointSize[0.05`]],
RectangleChart[RandomInteger[{3,10},{5,2}],ChartLabels->Callout[RandomWord[5]],AspectRatio->1,ImageSize->300,Frame->False,FrameTicks->None,ChartStyle->97,LabelStyle->24]}

LabelingFunction

useful to add labels programatically

LabelingFunction -> Function[{value, index, labels}, labelfunc[value, index, labels]]

SeedRandom[2];{ListPlot[{1,3,2,4,3},LabelingFunction->(#[[2]]&),AspectRatio->1,ImageSize->300,Frame->True,FrameTicks->None,LabelStyle->24,PlotStyle->PointSize[0.05`],PlotMarkers->None],
BarChart[{1,3,2,4,3},LabelingFunction->(Placed[#,Top]&),AspectRatio->1,ImageSize->300,Frame->True,FrameTicks->None,LabelStyle->24],
BubbleChart[RandomInteger[{1,10},{8,3}],LabelingFunction->(Callout[EntityValue[(EntityClass["Group of 8", EntityClass["Country","GroupOf8"], "EntityClass[\"Country\", \"GroupOf8\"]", "countries"]),"Name"][[#2[[2]]]]]&),AspectRatio->1,ImageSize->300,Frame->True,FrameTicks->None,LabelStyle->24]
}

Others

GeoLabels

EventLabels

ContourLabels

Supported functioms

ListPlot, ListLinePlot, StackedListPlot, ListLogPlot, ListLogLogPlot, ListLogLinearPlot, ListStepPlot, (GeoListPlot)

ListPolarPlot, ComplexListPlot

DateListPlot, StackedDateListPlot, DateListLogPlot, DateListStepPlot

ListPlot3D, ListPointPlot3D

FeatureSpace, FeatureSpacePlot3D

BarChart, RectangleChart, PieChart, SectorChart, BubbleChart

Labels in Function Visualization

Labeled

useful for adding individual information

Labeled[exp, "label",…]

{Plot[Labeled[Sin[x^2]Log[x],"label",1],{x,0,3},AspectRatio->1,Frame->True,FrameTicks->None,ImageSize->300,LabelStyle->14],
ParametricPlot[Labeled[{Sin[x^2],Log[x]},"label",2],{x,0,3},AspectRatio->1,Frame->True,FrameTicks->None,ImageSize->300,LabelStyle->14]
}

Callout

useful for adding individual information with extra clarification

Callout[exp, "label",…]

{Plot[Callout[Sin[x^2]Log[x],"label",1],{x,0,3},AspectRatio->1,Frame->True,FrameTicks->None,ImageSize->300,LabelStyle->14],
RegionPlot[Callout[1/2<x^2+y^3<2.5,"label",{0,0.5}],{x,-2,2},{y,-2,2},AspectRatio->1,Frame->True,FrameTicks->None,ImageSize->300,LabelStyle->14],
Plot3D[Callout[Sin[x]Sin[y]Log[x],"label"],{x,0,2Pi},{y,0,2Pi},ImageSize->300,Axes->False,Boxed->False,BoxRatios->1]}

PlotLabels

useful for adding labels respectively to the data

PlotLabels -> {(Subscript[label, 1]),(Subscript[label, 2]),…}

{Plot[Evaluate[Table[BesselJ[i,x],{i,4}]],{x,0,5},PlotLabels->Automatic,AspectRatio->1,Frame->True,FrameTicks->None,ImageSize->375,LabelStyle->16],
ParametricPlot[Evaluate[Table[{i Cos[u],i Sin[u]},{i,1,3}]],{u,0,2Pi},PlotLabels->Automatic,AspectRatio->1,Frame->True,FrameTicks->None,ImageSize->465,LabelStyle->16]
}

Supported functions

Plot, LogPlot, LogLogPlot, LogLinearPlot

PolarPlot, ParametricPlot, RegionPlot, ContourPlot, DensityPlot

Plot3D, ParametricPlot3D, SphericalPlot3D...

DiscretePlot/3D

DiscretePlot[Callout[Prime[t],Prime[t]],{t,20}]

DiscretePlot[Callout[Prime[t],HoldForm[Prime[t]]],{t,20}]

FeatureSpacePlot/3D

data=Append@@@ExampleData[{"MachineLearning","Titanic"},"Data"];

Take[data,5]

Length[data]

features=DimensionReduce[data,2];

ListPlot[features,LabelingFunction->(Callout[data[[#2[[2]]]]]&),ImageSize->800]

ListPlot[features,LabelingFunction->(Callout[data[[#2[[2]]]],LabelVisibility->All]&),ImageSize->800]

FeatureSpacePlot[data,ImageSize->800]

LabelingSize

z=ImageResize[#,200]&/@WebImageSearch["zombie","Thumbnails"]

ListPlot[RandomReal[1,{10,2}]->z,LabelingSize->100]

az=ImageResize[#,200]&/@WebImageSearch["asian zombie","Thumbnails"]

SeedRandom[1];FeatureSpacePlot[RandomSample[z~Join~az,15],LabelingSize->100]

Point Labeling Automation

conflicts avoidance

points=Table[{Cos[x],Sin[x]},{x,0,2Pi,2Pi/12}];
FlipView@Table[ListPlot[{Callout[{0,0},"label"]}~Join~points[[1;;n]],PlotRange->{{-4,4},{-4,4}},
LabelStyle->20,
AspectRatio->1/GoldenRatio,
PlotMarkers->None,
PlotStyle->PointSize[0.01]
],{n,1,Length[points]}]

density

SeedRandom[1];word=RandomWord[210];
points=RandomReal[BinormalDistribution[{1,2},{1,6},0.4],210];FlipView@Table[ListPlot[points[[1;;n]],LabelingFunction->(Callout[word[[#2[[2]]]]]&),PlotRange->{{-3,4},{-20,25}}],{n,10,210,100}]

Point Labeling Automation

ImageSize

SeedRandom[1];word=RandomWord[200];points=RandomReal[BinormalDistribution[{1,2},{1,6},0.4],200];FlipView[Table[ListPlot[points,LabelingFunction->(Callout[word[[#2[[2]]]]]&),ImageSize->i,Frame->None,PlotMarkers->None],{i,400,800,200}]]

ViewPoint

SeedRandom[1];word=RandomWord[200];points=RandomReal[MultinormalDistribution[{1,2,3},{{2,1/2,-1/3},{1/2,1,0},{-1/3,0,2/3}}],200];FlipView[Table[With[{v=RotationTransform[θ,{0,0,1}][{3,0,3}]},ListPointPlot3D[points,LabelingFunction->(Callout[word[[#2[[2]]]]]&),ImageSize->500,ViewPoint->v,Boxed->True]],{θ,0,Pi/2,Pi/8}]]

Other Automations

Automatic label

ReImPlot[{ArcSin[x],ArcCos[x]},{x,-4,4},PlotLabels->"Expressions"]

label location for curve

m=Table[FindMaximum[x Cos[x],{x,i}],{i,{1,6,13}}];
Plot[Callout[x Cos[x],m[[All,1]],Automatic,x/.m[[All,2]],LabelStyle->20],{x,0,14},ImageSize->500]

Quadratic Optimization Problem

FlipView@Table[Plot[{Sin[x],Sin[a^1.1 x],Sin[a^1.5 x]},{x,0,2Pi},PlotLabels->Automatic,LabelStyle->24,ImageSize->700],{a,1.02,1.4,0.04}]

data=Nest[Accumulate,RandomReal[{1,10},16],2];
labels=RandomWord[Length[data]];
FlipView@Table[PieChart[Take[data,n],ChartLabels->Callout[labels,LeaderSize->25],LabelStyle->20,ImageSize->700,ImagePadding->70,PlotTheme->"Web",ChartStyle->55],{n,10,Length[data],2}]

Special Plots

ParametricPlot, RegionPlot

ParametricPlot[Evaluate@Table[{u Sin[2u+i],u Cos[2u+i]},{i,1,4,1}],{u,0,2Pi},PlotLabels->Callout["Expressions",LabelStyle->20],ImageSize->800,Axes->False,PlotRangePadding->Scaled[0.05`]]

f[z_]:=1/(z^3-1)

RegionPlot[{Callout[Abs[f[x+I y]]>1,HoldForm[Abs[f[z]]>1],{1,1/2},Frame->True,RoundingRadius->4,FrameMargins->5],
Callout[Abs[f[x+I y]]<0.5,HoldForm[Abs[f[z]]<0.5],{1,-1.25}]},{x,-2,2},{y,-2,2},ImageSize->Large,LabelStyle->20,PlotStyle->{Blend[{Purple,Orange}],LightOrange},BoundaryStyle->White,Frame->True]

Plot3D, ListPlot3D, SphericalPlot3D, ParametricPlot3D...

Plot3D[Callout[Sin[x]Cos[y^1.1]Log[x],{"maximum","minimum"},{Above,Below,{x,y}/.max[[2]]},LabelStyle->{White,24},CalloutStyle->{Directive[AbsoluteThickness[3],Opacity[1]],Opacity[0]}],{x,0,2π},{y,0,2π},PlotTheme->{"Web"},Boxed->False,Axes->False,BoxRatios->1,AspectRatio->0.9`,Mesh->Automatic,MeshStyle->Directive[Thin,Darker[Blend[{Blue,Green}]]],Background->Darker[Blend[{Blue,Green}]],ImageSize->Large]

ParametricPlot3D[{u Sin[6u],u Cos[6u],-u/2},{u,0,2Pi},PlotLabels->Callout["Expressions",{1/2,1,2}],ImageSize->Large,LabelStyle->12,PlotTheme->"Minimal"]

ContourPlot, DensityPlot

f[z_]:=(z^2+1)/(z^3+1)
zeros=ReIm[z]/.Solve[(z^2+1)==0,z]
poles=ReIm[z]/.Solve[(z^3+1)==0,z]
ContourPlot[Callout[Abs[f[x+I y]],{"pole","pole","pole","zero","zero"},poles~Join~zeros,],{x,-1.5,1.5},{y,-1.5,1.5},]

Vann Diagram

a=Disk[{0,1}];
b=Disk[{-0.5,0}];
c=Disk[{0.5,0}];

subsets=Subsets[{a,b,c},{1,3}];
subsetscolors=;

RegionPlot[Evaluate[DiscretizeRegion[
RegionDifference[
BooleanRegion[And,#],BooleanRegion[Or,Complement[{a,b,c,EmptyRegion[2]},#]]
]
]&/@subsets],
PlotLabels->Callout[(StringJoin@@@Subsets[{"A","B","C"},{1,3}]),Center],
]

a=Disk[{0,0},{1.5,0.75}];b=Disk[{0,0},2,{-Pi/2,Pi/2}];c=Disk[{0,0},2,{Pi,2Pi}];d=Disk[{0,0},{0.75,1.5}];

subsets=Subsets[{a,b,c,d},{1,4}];
subsetscolors=;

RegionPlot[Evaluate[DiscretizeRegion[
RegionDifference[
BooleanRegion[And,#],
BooleanRegion[Or,Complement[{a,b,c,d,EmptyRegion[2]},#]]
]
]&/@subsets],
PlotLabels->Callout[(StringJoin@@@Subsets[{"A","B","C","D"},{1,4}]),Center],]

Initialization

$PlotTheme={"Presentation","Large","Business"}

ClearAll[ghostfunction];ghostfunction[x_]:=PDF[NormalDistribution[0,2]][x]+0.025PDF[NormalDistribution[-2,0.2]][x]+0.02PDF[NormalDistribution[2.5,0.25]][x];