Udostępnij za pośrednictwem


FSharpChart new release available (version 0.55)

The new version of FSharp.Chart (formely FSharpChart) can now be found on GitHib at: https://fsharp.github.io/FSharp.Charting/

If you have been using FSharpChart you will have seen some recent activities around documentation. I am happy to say that a new code drop has been made available. This release deals with some minor bug fixes and restructures the code download, hopefully making it easier to navigate, in addition to the following changes:

  • Defines a default font for all charts and chart properties
  • Provides Style helpers to make it easier to define Labels, Fonts, etc.
  • Provides a mechanism for specifying global, chart, and type defaults (some of which are defined)
  • Provides a mechanism for DataPoint tooltips and sets a default for each chart type

First and foremost as a reminder the code can be downloaded from here:

https://code.msdn.microsoft.com/FSharpChart-b59073f5

Before drilling down into the code changes it is worth mentioning the new code structure. Hopefully this will make it simpler in navigating the source and samples. The folders and file contents for the download are:

  • bin: Contains a compiled DLL for FSharpChart; called MSDN.FSharpChart.dll
  • scripts: Contains the FSharpChart.fsx script file
  • source\fsharpchart: Contains all the source files for FSharpChart
  • source\generator: Contains some fsx files used to generate the original source code
    • The Generator.Script.fsx file can be used to create a single FSharpChart.fsx file from all the individual source control files
  • samples\scripts: Contains some sample script files that demonstrate creating various charts
  • samples\winforms: Contains a WinForms application that displays a chart and demonstrates how to change properties at runtime
  • samples\wpf: Contains a WPF application that display a chart using Interop
Default Font

As some folks have expressed a desire to have charts rendered using more modern fonts, the code now contains a default font:

let DefaultFont =
    new Font("Calibri", 9.0f, FontStyle.Regular)

Style Helpers

When defining a Font the normal definition is as follows:

new Font("Calibri", 9.0f, FontStyle.Regular)

However, with the definition of a default Font it makes sense to allow one to define a new Font where one expresses the differences to the default Font. Thus a StyleHelper method has been provided allowing one to write:

StyleHelper.Font(FontSize=12.0f)

Within the provided FSharpChart samples there are often times where one has to define a LabelStyle, Title, or Legend. These elements all support fonts to be defined. To simplify this process a series of StyleHelper methods are available where one can also just express the Font characteristic that differs from the default. The definition for these helpers is:

type StyleHelper =

    static member LabelStyle
        ( ?Angle, ?Color, ?Format, ?Interval, ?IntervalOffset, ?IntervalOffsetType,
          ?IntervalType, ?IsEndLabelVisible, ?IsStaggered, ?TruncatedLabels,
          ?FontName:string, ?FontFamily:FontFamily, ?FontStyle:FontStyle, ?FontSize:float32)

    static member Legend
        ( ?Title, ?Background, ?Alignment, ?Docking, ?InsideArea,
          ?FontName:string, ?FontFamily:FontFamily, ?FontStyle:FontStyle, ?FontSize:float32)

    static member Title
        ( ?Text, ?TextStyle, ?Background, ?Color, ?BorderColor, ?BorderWidth, ?BorderDashStyle,
          ?TextOrientation, ?Alignment, ?Docking, ?InsideArea,
          ?FontName:string, ?FontFamily:FontFamily, ?FontStyle:FontStyle, ?FontSize:float32)

    static member Font(?FamilyName:string, ?FontFamily:FontFamily, ?FontStyle:FontStyle, ?FontSize:float32)

This allows code such as:

chart.Title <- StyleHelper.Title("Chart Sin/Cosine", FontSize = 12.0f, FontStyle = FontStyle.Bold)
chart.Legend <- StyleHelper.Legend(InsideArea = false, Alignment = StringAlignment.Center, Docking = Docking.Top, FontName = "Arial Narrow")

Hopefully folks this is an easier syntax for Titles, Legends, LabelStyles, and Fonts.

Charting Defaults

In allowing the modification of all chart Font properties to use the newly defined default a mechanism was defined that allowed any chart property to be overridden with a default. Thus the code now supports the ability to specify a default value for any property which can be restricted to either a particular type (such as Series or Label) or to a particular chart type.

To demonstrate this I have defined a few simple properties that folks have requested:

// Type used for defining defaults
type internal ChartStyleDefault =
    { ChartType:Charting.SeriesChartType option; ParentType:Type option; PropertyName:string; PropertyDefault:obj }

// Definition of defaults for the chart
let internal PropertyDefaults =
    [ // Define type specific defaults
      { ChartStyleDefault.ChartType = None; ParentType = Some(typeof<Charting.LabelStyle>); PropertyName="Font"; PropertyDefault=(box (new Font("Arial Narrow", 10.0f, FontStyle.Regular))) }
      { ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Line); ParentType = Some(typeof<Charting.Series>); PropertyName="BorderWidth"; PropertyDefault=(box 2) }
      // Define global defaults
      { ChartStyleDefault.ChartType = None; ParentType = None; PropertyName="Font"; PropertyDefault=(box DefaultFont) } ]

Hopefully this will allow folks to customize FSharpChart with a set of defaults that render charts with desirable visuals.

DataPoint ToolTips

Last but not least ToolTip’s have now been defined for DataPoint’s on a chart. 

image

Support for these ToolTips are provided in several ways.

Firstly these ToolTips are enabled by default with a specific default ToolTip being defined for each chart type:

{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Line); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Spline); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Bar); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Column); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Area); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.StackedBar); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.StackedColumn); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.StackedArea); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.StackedBar100); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.StackedColumn100); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.StackedArea100); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.SplineArea); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Range); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, High=#VALY1, Low=#VALY2") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.RangeBar); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "Y=#VALX, High=#VALY1, Low=#VALY2") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.RangeColumn); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, High=#VALY1, Low=#VALY2") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.SplineRange); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, High=#VALY1, Low=#VALY2") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Point); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.PointAndFigure); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, High=#VALY1, Low=#VALY2") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.ThreeLineBreak); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.StepLine); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Pie); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Doughnut); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.BoxPlot); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "Lower Whisker=#VALY1, Upper Whisker=#VALY2, Lower Box=#VALY3, Upper Box=#VALY4") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Candlestick); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "High=#VALY1, Low=#VALY2, Open=#VALY3, Close=#VALY4") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Stock); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "High=#VALY1, Low=#VALY2, Open=#VALY3, Close=#VALY4") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Renko); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Bubble); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VALY1, Size=#VALY2") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.ErrorBar); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VALY1, Lower=#VALY2, Upper=#VALY3") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Funnel); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Pyramid); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Kagi); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "X=#VALX, Y=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Polar); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "Angle=#VALX, Distance=#VAL") }
{ ChartStyleDefault.ChartType = Some(Charting.SeriesChartType.Radar); ParentType = Some(typeof<Charting.Series>); PropertyName="ToolTip"; PropertyDefault=(box "Point=#VALX, Distance=#VAL") }

This ability is supported through the Series ToolTip property. A good set of documentation is available in the charting Technical Reference:

https://msdn.microsoft.com/en-us/library/dd456726.aspx 

The Keywords section covers the syntax for the property and the Chart Types section defines what values can and should be used.

Finally, the DataPoint properties for a Series can now be specified using the WithSeries.DataPoint method:

FSharpChart.Line [ for f in 1.0 .. 0.1 .. 10.0 -> f, sin f ]
|> FSharpChart.WithSeries.DataPoint(ToolTip = "(#VALX{#0.000}, #VAL{#,##0.000;-#,##0.000})")

The supported properties that can be defined are Label, LabelToolTip, and ToolTip.

In Conclusion

Hopefully folks will find these enhancements useful; the ToolTip support having been a highly requested feature. As always please do let me know if there are features that you would like to be included in FSharpChart.