Hover Text and Formatting in F#
How to use hover text and formatting in F# with Plotly.
Plotly is known for its graphing libraries, but it's also a broader ecosystem for building interactive data apps, AI data analysis tools, and deploying and hosting Dash apps. Explore the full set of tools and platforms designed to help turn data into action. Discover Plotly.
Note: We are retiring documentation for R, MATLAB, Julia, and F#. Learn more about this change here.
#r "nuget: Newtonsoft.Json, 12.0.3"
#r "nuget: Plotly.NET, 2.0.0-preview.9"
#r "nuget: Plotly.NET.Interactive, 2.0.0-preview.9"
#r "nuget: FSharp.Data"
Hover Labels¶
One of the most deceptively-powerful features of interactive visualization using Plotly.NET is the ability for the user to reveal more information about a data point by moving their mouse cursor over the point and having a hover label appear.
open Plotly.NET
let x = [for i in 0..10 -> i]
let y = [for i in x -> i*2]
let labels = [for i in x -> "Text "+ string i]
Chart.Point(x,y,Labels=labels)
Customizing Hover Mode¶
There are three hover modes available in Plotly.NET. The default setting is Layout.HoverMode='Closest', wherein a single hover label appears for the point directly underneath the cursor.
open Plotly.NET
let x = [for i in 0..10 -> i]
let y1 = [for i in x -> 2.0*Math.Cos(float i)]
let y2 = [for i in x -> 5.0*Math.Sin(float i)]
let labels = [for i in x -> "Text "+ string i]
[
Chart.Line(x,y1,Labels=labels,ShowMarkers=true);
Chart.Line(x,y2,Labels=labels,ShowMarkers=true);
]
|> Chart.combine
|> Chart.withLayout(Layout.init(HoverMode=StyleParam.HoverMode.Closest))
HoverMode X or Y¶
If Layout.HoverMode='X' (or 'Y'), a single hover label appears per trace, for points at the same x (or y) value as the cursor. If multiple points in a given trace exist at the same coordinate, only one will get a hover label. In the line plot below we have forced markers to appear, to make it clearer what can be hovered over:
open FSharp.Data
let csv = CsvFile.Load("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv")
let Oceania = Seq.filter (fun (row:CsvRow) -> row.GetColumn("continent") = "Oceania") csv.Rows
|> Seq.groupBy (fun c -> c.GetColumn("country"))
[for country,countryDetails in Oceania ->
let x = countryDetails |> Seq.map (fun x -> x.GetColumn("year"))
let y = countryDetails |> Seq.map (fun x -> x.GetColumn("lifeExp"))
Chart.Line(x,y,Name=country,ShowMarkers=true)]
|> Chart.combine
|> Chart.withLayout(Layout.init(HoverMode=StyleParam.HoverMode.X))
|> Chart.withTitle("LayoutMode.HoverMode='X'")
HoverMode = XUnified (Will Be Implemented)¶
Customizing Hover Label Appearance¶
Hover Label color and font can be set through Layout.HoverLabel attribute as shown below
open FSharp.Data
open Plotly.NET.LayoutObjects
let csv = CsvFile.Load("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv")
let Oceania = Seq.filter (fun (row:CsvRow) -> row.GetColumn("continent") = "Oceania") csv.Rows
|> Seq.groupBy (fun c -> c.GetColumn("country"))
let hoverLabel = Hoverlabel.init(BgColor=Color.fromString "white",
Font=Font.init(Size=16.,Family=StyleParam.FontFamily.Custom "Rockwell"))
[for country,countryDetails in Oceania ->
let x = countryDetails |> Seq.map (fun x -> x.GetColumn("year"))
let y = countryDetails |> Seq.map (fun x -> x.GetColumn("lifeExp"))
Chart.Line(x,y,Name=country,ShowMarkers=true)]
|> Chart.combine
|> Chart.withLayout(Layout.init(Hoverlabel=hoverLabel))
|> Chart.withTitle("LayoutMode.HoverMode='X'")
Customizing hover text with a HoverTemplate¶
To customize the tooltip on your graph you can use the HoverTemplate attribute of corresponding TraceStyle (i.e Trace2DStyle,TraceDomainStyle etc), which is a template string used for rendering the information that appear on hoverbox. This template string can include variables in %{variable} format, numbers in d3-format's syntax, and date in d3-time-format's syntax. In the example below, the empty
Note that a HoverTemplate customizes the tooltip text, while a TextTemplate customizes the text that appears on your chart.
Set the horizontal alignment of the text within tooltip with Hoverlabel.Align.
let hoverLabel = Hoverlabel.init(BgColor=Color.fromString "white",
Align=StyleParam.Align.Right)
let hoverTemplate = "<i>Price</i>: $%{y:.2f}"+
"<br><b>X</b>: %{x}<br>"+
"<b>%{text}</b>";
let text = [for i in 1..5 -> $"Custom text {i+1}"]
let chart1 = Chart.Line(x=[1..5],
y = [2.02825;1.63728;6.83839;4.8485;4.73463],
ShowMarkers=true, ShowLegend=false)
|> GenericChart.mapTrace (Trace2DStyle.Scatter(HoverTemplate=hoverTemplate,MultiText=text))
let chart2 = Chart.Line(x=[1..5],
y = [3.02825;2.63728;4.83839;3.8485;1.73463],
ShowMarkers=true, ShowLegend=false)
|> GenericChart.mapTrace (Trace2DStyle.Scatter(HoverTemplate="Price: %{y:$.2f}<extra></extra>"))
[chart1;chart2]
|> Chart.combine
|> Chart.withLayout(Layout.init(Hoverlabel=hoverLabel))
|> Chart.withTitle("Set hover text with HoverTemplate")
open Plotly.NET
Chart.Pie(values=[2.; 5.; 3.; 2.5],Name="",
Labels = ["R"; "Python"; "Java Script"; "Matlab"])
|> GenericChart.mapTrace(TraceDomainStyle.Pie(Text=["TextA"; "TextB"; "TextC"; "TextD"],
HoverTemplate="%{label}: <br>Popularity: %{percent} </br> %{text}"))
Hover Templates with Mixtures of Period data¶
When displaying periodic data with mixed-sized periods (i.e. quarterly and monthly) in conjunction with x or x unified hovermodes and using hovertemplate, the XHoverFormat attribute can be used to control how each period's X value is displayed, and the special %{xother} hover-template directive can be used to control how the X value is displayed for points that do not share the exact X coordinate with the point that is being hovered on. %{xother} will return an empty string when the X value is the one being hovered on, otherwise it will return (%{x}). The special %{xother}, %{xother} and %{xother} variations will display with spaces before, after or around the parentheses, respectively.
open Plotly.NET.LayoutObjects
let chart1 = Chart.Column([1000; 1500; 1700],["2020-01-01"; "2020-04-01"; "2020-07-01"])
|> GenericChart.mapTrace(Trace2DStyle.Bar(XPeriod="M3",
XPeriodAlignment=StyleParam.PeriodAlignment.Middle,
XHoverFormat="Q%q",
HoverTemplate = "%{y}%{_xother}"))
let x=["2020-01-01"; "2020-02-01"; "2020-03-01";
"2020-04-01"; "2020-05-01"; "2020-06-01";
"2020-07-01"; "2020-08-01"; "2020-09-01"]
let y=[1100;1050;1200;1300;1400;1700;1500;1400;1600]
let chart2 =Chart.Line(x=x,y=y,ShowMarkers=true)
|> GenericChart.mapTrace(Trace2DStyle.Scatter(XPeriod="M1",
XPeriodAlignment=StyleParam.PeriodAlignment.Middle,
XHoverFormat="Q%q",
HoverTemplate = "%{y}%{_xother}"))
let layout = //Workaround
let tmp = new Layout()
tmp?hovermode <- "x unified"
tmp
[chart1;chart2]
|> Chart.combine
|> Chart.withLayout(layout)
Advanced Hover Template¶
The following example shows how to format a hover template.
open Plotly.NET.TraceObjects
open Plotly.NET.LayoutObjects
let csv = CsvFile.Load("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv")
let continentNames = ["Africa"; "Americas";"Asia"; "Europe"; "Oceania"]
let contientGrouping = csv.Rows |> Seq.groupBy (fun row -> row.GetColumn("continent"))
let hoverTemplate = "<b>%{text}</b><br><br>" +
"GDP per Capita: %{x:$,.0f}<br>" +
"Life Expectation: %{y:.0%}<br>" +
"Population: %{marker.size:,}" +
"<extra></extra>"
let rand = new Random()
[for continent,countryList in contientGrouping ->
let x = [for (row:CsvRow) in countryList -> row.GetColumn("gdpPercap")]
let y = [for (row:CsvRow) in countryList -> row.GetColumn("lifeExp")]
let size = [for (row:CsvRow) in countryList -> int <| rand.NextDouble()*300. ]
let text = countryList |> Seq.map (fun c -> c.GetColumn("continent"))
Chart.Scatter(x,y,StyleParam.Mode.Markers,Name=continent)
|> Chart.withMarkerStyle(MultiSize=size,SizeMode=StyleParam.MarkerSizeMode.Area,SizeRef=10)
|> GenericChart.mapTrace(Trace2DStyle.Scatter(HoverTemplate=hoverTemplate,MultiText=text))]
|> Chart.combine
|> Chart.withXAxis(LinearAxis.init(AxisType=StyleParam.AxisType.Log))
Adding other data to the hover with CustomData and a HoverTemplate¶
You can then use CustomData inside a HoverTemplate to display the value of CustomData.
open System
let rand = new Random()
let hoverTemplate ="<b>y:%{y:.3f}</b><br> custom:%{customdata:.3f}}"
let customdata = [|for i in 1..5 -> rand.NextDouble()|]
Chart.Line(x=[1..5],
y = [2.02825;1.63728;6.83839;4.8485;4.73463],
ShowMarkers=true, ShowLegend=false)
|> GenericChart.mapTrace (Trace2DStyle.Scatter(HoverTemplate=hoverTemplate,CustomData=customdata))
Setting the Hover Template in Mapbox Maps (Missing Abstraction)¶
// let cityNames = [
// "Montreal"; "Toronto"; "Vancouver"; "Calgary"; "Edmonton";
// "Ottawa"; "Halifax"; "Victoria"; "Winnepeg"; "Regina"
// ]
// let hoverTemplate = "<b>%{marker.symbol} </b><br><br>" +
// "longitude: %{lon}<br>" +
// "latitude: %{lat}<br>"
// Chart.ScatterMapbox(longitudes=[-75; -80; -50],
// latitudes=[45; 20; -20],
// mode=StyleParam.Mode.Lines_Markers_Text)
// |> Chart.withMarker(Marker.init(Size=20))
// |> GenericChart.mapTrace (TraceMapboxStyle.ScatterMapbox())
// |> Chart.withMapbox(
// Mapbox.init(Style=StyleParam.MapboxStyle.OpenStreetMap,
// Zoom=1.,
// Center=(-84.6,30.45)
// )
// )
Spike lines¶
Plotly.NET supports "spike lines" which link a point to the axis on hover, and can be configured per axis.
open FSharp.Data
let csv = CsvFile.Load("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv")
let Oceania = Seq.filter (fun (row:CsvRow) -> row.GetColumn("continent") = "Oceania") csv.Rows
|> Seq.groupBy (fun c -> c.GetColumn("country"))
[for country,countryDetails in Oceania ->
let x = countryDetails |> Seq.map (fun x -> x.GetColumn("year"))
let y = countryDetails |> Seq.map (fun x -> x.GetColumn("lifeExp"))
Chart.Line(x,y,Name=country,ShowMarkers=true)]
|> Chart.combine
|> Chart.withXAxis(LinearAxis.init(ShowSpikes=true))
|> Chart.withYAxis(LinearAxis.init(ShowSpikes=true))
|> Chart.withTitle("Spike lines active")