Поделиться через


Tutorial: Charting with Gnuplot from F#

Applies to: Functional Programming

Authors: Tomas Petricek and Jon Skeet

Referenced Image

Get this book in Print, PDF, ePub and Kindle at manning.com. Use code “MSDN37b” to save 37%.

Summary: This tutorial shows how to create charts using gnuplot from F#. It demonstrates how to call gnuplot directly and how to use a simple open-source F# wrapper.

This topic contains the following sections.

  • Using Gnuplot for F# Charting
  • Calling Gnuplot Directly
  • Introducing a Gnuplot Wrapper for F#
  • Creating an Advanced Chart
  • Summary
  • Additional Resources
  • See Also

This article is associated with Real World Functional Programming: With Examples in F# and C# by Tomas Petricek with Jon Skeet from Manning Publications (ISBN 9781933988924, copyright Manning Publications 2009, all rights reserved). No part of these chapters may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.

Using Gnuplot for F# Charting

Gnuplot is a cross-platform and open source tool for creating charts. It can be downloaded from a website referenced at the end of this article. Calling gnuplot from F# may be interesting when using F# in a cross-platform environment. It can be also attractive for developers with existing gnuplot skills. Gnuplot runs as a separate process that can be controlled using commands. This tutorial demonstrates how to call gnuplot directly and it briefly looks at wrappers that provide a more natural interface for F#. You will learn how to:

  • Send commands directly to the gnuplot process (running in the background)

  • Create charts using a cross-platform F# wrapper for gnuplot

  • Configure chart styles and show multiple data series in a single chart

The first section starts by looking at the direct way of using gnuplot. It uses standard techniques that .NET provides for starting a process and communicating with it using the standard input.

Calling Gnuplot Directly

The gnuplot application can be controlled using the Process class from the System.Diagnostics namespace. The class can start the process and write to its standard input stream. It can also monitor the standard and error output of the gnuplot process to receive notifications when an invalid command is used, but this tutorial omit this feature to make the example code simpler. Once the process is started, it is possible to give it all the usual commands that can be written at the gnuplot command prompt. The following listing shows a basic example that draws a graph of two functions:

open System
open System.Diagnostics

let gp =  
  new ProcessStartInfo
    (FileName = "gnuplot", UseShellExecute = false, 
     CreateNoWindow = true, RedirectStandardInput = true) 
  |> Process.Start

// Draw graph of two simple functions
gp.StandardInput.WriteLine "plot sin(x) + sin(3*x), -x"  

The snippet first constructs an instance of the ProcessStartInfo, which defines the parameters that are used to start the process. Most importantly, the initialization sets the file name that should be run. This can be either a full path to the executable or just a file name when gnuplot directory is included in the PATH variable. To create a process that can accept the standard input from the calling script or program, it is necessary to set the RedirectStandardInput property to true. This also requires setting the UseShellExecute option to false. The remaining option specifies that no window should be created for the process.

The Process.Start method returns a Process object that can be used for controlling gnuplot. Sending commands is done using the StandardInput property. Writing a line to the standard input corresponds to entering a single command. The example above sends the process the “plot” command with two functions as arguments. Figure 1 shows the output as it looks when executed on Mono. The default gnuplot configuration is to use the X11 terminal, which means that it opens the chart as a new window.

Figure 1. A graph showing simple linear and trigonometric functions

Referenced Image

Plotting a graph of a function may be useful in some cases. When using F# for explorative programming, a more common scenario is to create charts from data that were obtained earlier. The gnuplot program can be used in this scenario too. It can load data from an external file or from the standard console input. Unless the data source is extremely large, it is easier to use the second approach. Passing the data directly to the input avoids the need to create a temporary data file.

To specify data through standard input, the script needs to specify '-' as the name of the input when calling the “plot” command. The gnuplot process will start reading the input data immediately after the “plot” command is executed. More information about the gnuplot syntax can be found in the documentation (referenced at the end of the article). The following example shows how to create a simple histogram chart with randomly generated values:

// Change style and start plotting a histogram
gp.StandardInput.WriteLine "set style fs solid"
gp.StandardInput.WriteLine "plot '-' lc 6 with histogram"

// Provide data for the plot
let rnd = new Random()
for v in 1 .. 10 do
  gp.StandardInput.WriteLine(rnd.Next())
gp.StandardInput.WriteLine "e"  

The snippet starts by sending a command that changes the visual style of the chart. The command instructs gnuplot to fill rectangles drawn as part of the histogram chart so that it appears as a usual column or a bar chart. The second command tells gnuplot to draw data that will be entered on the standard input using the histogram chart with a line color set to a predefined color number 6.

After calling the “plot” command, gnuplot expects the data for the plot. The sample dataset consists only of a single series, so the script writes a single numeric value per line. The for loop generates 10 random numbers and writes them to the standard input of gnuplot using the WriteLine method. The method is overloaded, so it converts the numeric value automatically to a string. Once the data is generated, the input is terminated using a special command “e”. After that, the chart displayed in the figure below should appear, and the gnuplot process is ready to handle further commands.

Figure 2. A column chart showing data provided by an F# script

Referenced Image

The image can be also saved into a file using the command set term png. This instructs gnuplot to generate a chart in the PNG format. The desired file name can be set using the set output <file-name> command. When the script finishes working with gnuplot, it is also a good idea to end the process so that it doesn’t stay loaded in memory. This can be done by sending the quit command or by calling the Kill method of the Process object.

Introducing a Gnuplot Wrapper for F#

Using the gnuplot process directly from F# is quite straightforward, but it doesn’t fit with the usual F# programming style. To use gnuplot in a more usual style, it is possible to use an open source wrapper that is available in the F# Cross Platform project. The wrapper is available as an F# file that can be loaded in F# Interactive or included other projects. Once the file is loaded, gnuplot process can be started by creating an instance of the GnuPlot class (from the namespace FSharp.GnuPlot):

// Load the F# wrapper for gnuplot
#load "gnuplot.fs"
open FSharp.GnuPlot

// Generate histogram chart with random values
let gp = new GnuPlot()
gp.Plot(Series.Histogram [ for i in 0 .. 10 -> float(rnd.Next()) ]) 

The most important method provided by the GnuPlot type is the Plot method. The method can be called in several different ways. In the example above, it is given a Series object that represents a histogram. The method can also be called with a string argument, which is used to draw graph of a function. For example, sine function can be plotted using gp.Plot("sin(x)").

The Series object represents a single data series that should be drawn on the chart. The above example creates a Histogram type of series and gives it a single argument which is a randomly generated list of numeric values. The example plots a single data series with the default settings of gnuplot. However, the F# wrapper provides a comfortable way for setting many of the common properties.

Creating an Advanced Chart

This section looks at a more complicated example of calling gnuplot using the F# wrapper. The example combines three types of data series in a single chart—a series generated as a graph of a function, a column chart, and a line chart. Moreover, the example also specifies various properties of both the entire chart as well as individual data series.

This section explores another overload of the Plot method. It takes a list of data series that can be generated using static members of the Series type (such as Series.Histogram from the previous section). It is also possible to create a data series directly using the chart type name used in gnuplot. All overloads of the Plot method take numerous named parameters that allow specifying global properties of the chart such as range, style, and titles. The methods for creating a series also provide several named parameters to configure the individual series.

The following example first generates three data series and sets their titles, colors, and line weight. Then, it passes the list of data series to the Plot method and also configures the view area of the chart using a named parameter range:

// Data for line and column charts
let ds1 = [1.0; 5.0; 3.0; 2.0]
let ds2 = [2.0; 4.0; 3.0; 3.0]

// Create a list of chart data series
let charts = 
  [ Series.Lines
      ( ds1, title="Estimate", lineColor=Color.OliveDrab, weight=3)
    Series.Histogram
      ( ds2, title="Data", fill=Solid, lineColor=Color.SteelBlue) 
    Series.Function
      ( "sin(x*3) + 3", lineColor=Color.Goldenrod, 
        title="Sinus", weight=3) ]

// Plot all 3 charts into an area with the specified range
gp.Plot(charts, range = Range.[ -0.5 .. , .. 6.0 ])

When creating a data series using Lines or Histogram method, the only required argument (passed as the first one) is the source of data. When creating a function, the required parameter is an expression (passed as a string) that should be plotted. Additional arguments that are provided above include title to set the annotation for the data series, lineColor to specify the color of the item, and weight. The resulting chart is shown in Figure 3.

Figure 3. A gnuplot chart combining three data series

Referenced Image

One aspect of the previous example that deserves an explanation is the specification of the plot area using the range named parameter. By default, gnuplot calculates the minimum and maximum for both of the axes automatically. It is possible to specify all of the limit values of the range, but sometimes it is useful to specify just some of the values. For example, the snippet above explicitly provides just the minimum value for the x-axis and the maximum value for the y-axis. The syntax that makes this possible in F# is called slices. The gnuplot wrapper uses the Range value (as in the previous example) to specify some or all of the four edge values. When specifying the range for only one of the axes, it is possible to use values RangeX and RangeY and use an expression like RangeY.[ .. 9.5 ].

Another important method provided by the gnuplot wrapper is the Set method. It provides a way to specify parameters for plotting for an entire gnuplot session. Most of the parameters can also be passed to the Plot method, but, in that case, they are reverted back to the default setting after plotting. It is also possible to run a command that is not directly exposed by the wrapper using the SendCommand method. It takes a string and sends it directly to gnuplot. The following example shows how to set a plot title directly and how to set the output terminal to a PNG file using the Set method:

// Set terminal to a PNG and specify output file
gp.Set(output=Png("C:\temp\plot.png"))

// Add title by calling gnuplot directly
gp.SendCommand("set title \"Sample chart\"");

Summary

This tutorial looked at working with gnuplot from F# and, in particular, from F# Interactive. It demonstrated two ways of using the gnuplot tool. The first option is to call gnuplot directly using standard .NET objects for starting and communicating with other processes. In this case, commands are written in the format used by gnuplot and sent to gnuplot as strings. This is somewhat inconvenient, especially when generating plots automatically. The second option is to use an F# wrapper for gnuplot. The wrapper provides a more natural F# syntax and supports many gnuplot features directly in a type-checked way.

Additional Resources

The most important advantage of using gnuplot is that it can be used in a cross-platform environment. It is also an established tool, especially in the scientific community. However, F# can access a wide range of other charting tools. The following list provides links to tutorials for other technologies discussed in this section. Consult the overview article for comparison of various options:

To download the code snippets shown in this article, go to https://code.msdn.microsoft.com/Chapter-6-Visualizing-Data-c68a2296

See Also

This article is based on Real World Functional Programming: With Examples in F# and C#. Book chapters related to the content of this article are:

  • Book Chapter 4: “Exploring F# and .NET libraries by example” demonstrates how to create a simple charting application from scratch. This chapter is useful for learning F# programming when focusing on working with data.

  • Book Chapter 12: “Sequence expressions and alternative workflows” explains how to work with in-memory data sets in F# using sequence expressions and higher-order functions.

  • Book Chapter 13: “Asynchronous and data-driven programming” shows how to use asynchronous workflows to obtain data from the internet, how to convert data to a structured format, and how to chart it using Excel.

The following MSDN documents and external resources are related to the topic of this article:

  • gnuplot homepage contains gnuplot source code and binaries for various platforms as well as additional resources.

  • Official gnuplot documentation contains a comprehensive reference on using gnuplot. Note that only some functionality is currently exposed by the F# wrapper, but you can add new features by following the existing pattern.

  • F# cross-platform packages and samples (CodePlex) is an open-source project that includes a wrapper for creating gnuplot charts from F#. You're welcome to contribute your extensions to the F# wrapper.

  • Process.Start Method (ProcessStartInfo) describes how to start and control processes on .NET. We used this method to start gnuplot, so that we could send commands to it from F#.

Previous article: Tutorial: Charting with Excel from F#

Next article: How to: Create Standard Charts in F#