Interactive Highlighting

Min-Hsuan Peng	, Wolfram

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

ABSTRACT

Interactive highlighting in visualizations was introduced in version 13.3. In this talk, we will take a closer look at the framework. The goal is to familiarize you with the framework and provide a reference for customization.

You must have seen it in V13.3

By default, automatic highlighting is turned on.

Plot[Evaluate@Table[BesselJ[n,x],{n,1,4}],{x,0,8}]

But do you know how to make these?

Row[{Plot[Evaluate@Table[BesselJ[n,x],{n,1,4}],{x,0,5},PlotHighlighting->{
{"XYDroplines",<|"Style"->Directive[Dashed,Thickness[0.005]]|>},
{"XYAxisLabels",<|Appearance->"Line",LabelStyle->{18},LeaderSize->None,
CalloutMarker->"CirclePoint",CalloutStyle->Directive[Thickness[0.005]]|>}
},Frame->True,ImageSize->450],Plot[{Highlighted[x Sin[1/x],None],Abs[x],-Abs[x]},{x,-1/2,1/2},PlotStyle->{Red,Directive[Dashed,Gray],Directive[Dashed,Gray]},
PlotHighlighting->"XSlice",ImageSize->450]},Spacer[100]]

Row[{ParametricPlot[{{u Cos[u],2u Sin[u]},{2 u Cos[u],u Sin[u]}},{u,Pi,4Pi},
PlotHighlighting->{
{"Crosshairs",<|"Style"->AbsoluteThickness[1]|>},
{"XYLabel",<|Appearance->"Line",LabelStyle->{18},LeaderSize->{{20,Automatic,Automatic},{10,Automatic}},
CalloutMarker->{"Arrow",20},CalloutStyle->Directive[Thickness[0.005]]|>}
},ImageSize->450],ListPlot[Table[{ElementData[z,"AbsoluteBoilingPoint"],ElementData[z,"VaporizationHeat"]},{z,118}],
PlotHighlighting->{
{"NearestPoint",<|"Style"->Red|>},
{"XYLabel",
<|
CalloutMarker->{"Circle",20},
Appearance->"SlantedLabel",
LeaderSize->20,
Frame->True,
LabelStyle->20
|>
}
},ImageSize->450]},Spacer[100]]

Interface

PlotHighlighting

An option for point & curve visualizations

Take advantage of the auto-completion menu for PlotHighlighting:

Framed[,FrameStyle->Directive[Thickness[5],LightGray]]

ParametricPlot[{Cos[u],Sin[u]},{u,0,2Pi},PlotHighlighting->"XSlice"]

Syntax for adding options:

ParametricPlot[{Cos[u],Sin[u]},{u,0,2Pi},PlotHighlighting->{"XYDroplines",<|"Style"->Dashed|>}]

Highlighted

Data/function wrapper

Allows you to specify individual highlighting rather than applying it to the entire plot

Plot[{x Sin[1/x],Abs[x],-Abs[x]},{x,-1/2,1/2},PlotStyle->{Red,Directive[Dashed,Gray],Directive[Dashed,Gray]},
PlotHighlighting->"XSlice"
]

Plot[{Highlighted[x Sin[1/x],"XSlice"],Abs[x],-Abs[x]},{x,-1/2,1/2},PlotStyle->{Red,Directive[Dashed,Gray],Directive[Dashed,Gray]}
]

Or to disable the highlighting on a specific input

Plot[{Highlighted[x Sin[1/x],None],Abs[x],-Abs[x]},{x,-1/2,1/2},PlotStyle->{Red,Directive[Dashed,Gray],Directive[Dashed,Gray]},
PlotHighlighting->"XSlice"
]

This is how ProbabilityPlot does it by default:

data=RandomVariate[NormalDistribution[1,2],100];

ProbabilityPlot[data]

Components

When we were developing the tool, we realized there were numerous highlighting behaviors. Instead of assigning a few dozen new names, we decided to provide components that you can combine to create the appropriate highlight for your unique application.

The components can be broken down to:

Style*

Plot[Evaluate[Table[BesselJ[n,x],{n,1,5}]],{x,0,9},
PlotStyle->Directive[AbsoluteThickness[3],LightGray],PlotHighlighting->Directive[Red,Haloing[LightGray,5,10]],
PlotLabels->Automatic]

Point

The mechanism for finding the point you want to highlight.

IndicatedPoint

finding the point closest to the cursor within a radius

data=Table[{CountryData[c,"BirthRateFraction"],CountryData[c,"LifeExpectancy"]},{c,CountryData["Countries"]}];

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->{"IndicatedPoint",<|"Style"->Directive[PointSize[0.02],Red]|>}]

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},10]],{3}],
Mesh->All,
PlotHighlighting->{"IndicatedPoint",<|"Style"->Directive[AbsolutePointSize[15],Red]|>}]

Change the halo style:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},10]],{3}],
PlotHighlighting->{
"IndicatedPoint",
<|"Style"->
{
Directive[AbsolutePointSize[15],Red],Directive[AbsolutePointSize[25],Blue]
}|>
}]

NearestPoint

draw a ball at the point closest to the cursor

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->{"NearestPoint",<|"Style"->Directive[PointSize[0.02],Red]|>}]

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},25]],{3}],
PlotHighlighting->{"NearestPoint",<|"Style"->Directive[PointSize[0.02],Red]|>}]

XNearestPoint

draw a ball at the point or points closest to the cursor in the x direction

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->{"XNearestPoint",<|"Style"->Red|>}]

Multiple line:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},25]],{3}],
PlotHighlighting->{"XNearestPoint",<|"Style"->Directive[PointSize[0.02],Red]|>}]

Single dataset with repeated x positions

ListPlot[RandomInteger[{1,20},{30,2}],
PlotHighlighting->{"XNearestPoint",<|"Style"->Red|>}]

YNearestPoint

draw a ball at the point or points closest to the cursor in the y direction

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->{"YNearestPoint",<|"Style"->Red|>}]

Multiple line:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},25]],{3}],
PlotHighlighting->{"YNearestPoint",<|"Style"->Directive[PointSize[0.02],Red]|>}]

Line

Choices of auxiliary lines.

Crosshairs

free-form cross hairs following the cursor

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"Crosshairs"]

Multiple line:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},10]],{3}],
(*Mesh->All,*)
PlotHighlighting->"Crosshairs"]

XYDroplines

droplines from the cursor to the axes or frames

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"XYDroplines"]

Multiple line:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},10]],{3}],
Mesh->All,
PlotHighlighting->"XYDroplines"]

XLine

vertical line spanning the graphic

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"XLine"]

Multiple line:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},15]],{3}],
Mesh->All,
PlotHighlighting->"XLine"]

YLine

horizontal line spanning the graphic

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"YLine"]

Multiple line:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},15]],{3}],
PlotHighlighting->"YLine"]

XDropline

vertical droplines from the cursor to the axes or frames

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"XDropline"]

Multiple line:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},25]],{3}],
(*Mesh->All,*)
PlotHighlighting->"XDropline"]

YDropline

horizontal droplines from the cursor to the axes or frames

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"YDropline"]

Multiple line:

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},25]],{3}],
PlotHighlighting->"YDropline"]

Label

How to add the notation for the highlighted point.

Takes the advantage of all Callout options

Options[Callout]//Column

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->{"XYLabel",<|CalloutMarker->"CirclePoint"|>}]

XYLabel

label the cursor position

PlotHighlighting->{"XYLabel",<|CalloutMarker->"CirclePoint"|>}

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"XYLabel"]

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},10]],{3}],
(*Mesh->All,*)
PlotHighlighting->"XYLabel"]

XLabel

label the x coordinate of the cursor position

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"XLabel"]

YLabel

label the y coordinate of the cursor position

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"YLabel"]

XYAxisLabels

label the coordinates along the axes or frame

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"XYAxisLabels"]

SeedRandom[3];ListLinePlot[Table[Accumulate[RandomReal[{-1,1},25]],{3}],
PlotHighlighting->"XYAxisLabels"]

XAxisLabel

label the x coordinate along the axis or frame

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"XAxisLabel"]

YAxisLabel

label the y coordinate along the axis or frame

ListPlot[data,
AxesLabel->{"BirthRate","LifeExpectancy"},
PlotHighlighting->"YAxisLabel"]

Presets

We named some popular combinations for convenience

There is always a point, visible or not

The Point method depends on the characteristics of the visualization function

Ball

IndicatedPoint* + XYLabel

highlight the indicated point in a curve

default behavior

function vis highlight interpolated points; data visualization highlight actual points

Function vis highlight interpolated point

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

highlight the indicated point in a curve with droplines to the axes

function vis highlight interpolated points; data visualization highlight actual points

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

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

XSlice

XNearestPoint + XLine + YLabel

highlight all points along a vertical slice

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

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

ListLinePlot[{2,1,4,3},PlotHighlighting->"XSlice"]

ListPlot[RandomReal[1,{30,2}],PlotHighlighting->"XSlice"]

YSlice

YNearestPoint + YLine + XLabel

highlight all points along a horizontal slice

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

Lego building

The framework allows you to build your own highlighting mechanism.

Create your own highlighting

Adjust the presets

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

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

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->{(*"Ball",*)"XNearestPoint",{"YLabel",<|Appearance->"SlantedLabel",LabelStyle->30|>}}]

Another example for XSlice:

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

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->{{"XSlice",<|"Style"->Red|>},{"YAxisLabel",<|RoundingRadius->10|>}}]

Build your own

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->{
{"YNearestPoint",<|"Style"->Directive[AbsolutePointSize[5],Red]|>},
{"XYDroplines",<|"Style"->Directive[Dashed,AbsoluteThickness[3]]|>},
{"XAxisLabel",<|LabelStyle->20,LeaderSize->None,RoundingRadius->10|>}
}]

Static highlighting

Dynamic highlighting enables exploration, while static highlighting helps with explanation.

Placing static highlights

Placed[highlighting, pos]

The automatic positions are determined based on the type of point method used.

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->Placed[{"YNearestPoint","XLabel"},0.1]]

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->Placed[{"XNearestPoint","YLabel"},3]]

To avoid ambiguity, use {x, Automatic} or {Automatic, y}

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->Placed[{"YNearestPoint","XLabel"},{Automatic,0.1}]]

Multiple positions: {pos1, pos2,...}

Plot[Sinc[x],{x,-3Pi,3Pi},PlotHighlighting->Placed[{"XNearestPoint","YLabel","XDropline"},{{-7},{2},{5}}]]

Used in Highlighted

Plot[{Highlighted[x Sin[1/x],Placed["XSlice",{{0.25},{-0.35}}]],Abs[x],-Abs[x]},{x,-1/2,1/2},PlotStyle->{Red,Directive[Dashed,Gray],Directive[Dashed,Gray]}
]

Deployment

Points & Curves

Plot and its family

ListPlot and its family

Plot and ListPlot’s derivatives

Plot, LogPlot, LogLogPlot, LogLinearPlot...
ParametricPlot
ReImPlot, AbsArgPlot, 
ListPlot, DateListPlot, ListLogPlot, ListLogLogPlot, ListLogLinearPlot, DateListLogPlot
ComplexListPlot
ProbabilityPlot...
BodePlot, NyquistPlot
...

Bonus: Callout Appearance

(*markup*)
Callout[data,"label",
LabelStyle->40,
LeaderSize->{{leaderlength,angle,gap},{necklength,angle}},
Appearance->appearance,
CalloutMarker->marker,
Background->backgroundstyle,
FrameMargins->framemargins,
RoundingRadius->radius,
CalloutStyle->Directive[calloutstyle,Thickness[0.01]]]

DynamicModule[{autonangle=True,angle=45,llen=25,nlen=10,nangle=45,gap=5,app="Frame",marker=None,bgrd=White,radius=0,margin=5,calloutstyle=LightGray},Row[{Framed@Dynamic[Graphics[{PointSize[Large],Point[{0,0}],
Charting`LabelMaker[Style["label",40],{0,0},Automatic,LeaderSize->{{llen,angle Degree,gap},{nlen,If[autonangle,Automatic,nangle Degree]}},Appearance->app,CalloutMarker->{marker,15},CalloutStyle->Directive[calloutstyle,Thickness[0.01]],Background->bgrd,RoundingRadius->radius,FrameMargins->margin]
},PlotRange->0.5,ImageSize->400]],Column[{
Labeled[Slider[Dynamic[angle],{0,360}],"angle",Left],
Labeled[Slider[Dynamic[llen],{10,60}],"leader length",Left],
Labeled[Slider[Dynamic[nlen],{0,30}],"neck length",Left],
Labeled[Slider[Dynamic[gap],{0,30}],"leader gap",Left],
Labeled[Slider[Dynamic[radius],{0,30}],"rounding radius",Left],
Labeled[Slider[Dynamic[margin],{0,30}],"frame margins",Left],
Labeled[ColorSlider[Dynamic[bgrd]],"background",Left],
Labeled[ColorSlider[Dynamic[calloutstyle]],"CalloutStyle",Left],
Row@{Labeled[Checkbox[Dynamic[autonangle]],"auto neck angle",Left],
Labeled[Slider[Dynamic[nangle],{0,360},Enabled->Dynamic@Not@autonangle],"neck angle",Left]},
Labeled[PopupMenu[Dynamic[app],{"CurvedLeader","Balloon","LineBalloon","Corners","Frame","Line"}],"appearance",Left],Labeled[PopupMenu[Dynamic[marker],{None,"CirclePoint","Circle","BoxPoint", "Box","Star", "OpenStar","Arrow", "OpenArrow"}],"marker",Left]}]
},"   "]]

Thank you!

PS. How do I change the style of every vis without adding options? 

Use global variable $PlotTheme:

$PlotTheme={"Presentation","Large","Bold","ThickLine","PastelColor"}