The SwiftPlot framework is a cross-platform library that lets you plot graphs natively in Swift.
The existing Swift plotting frameworks (such as CorePlot) run only on iOS or Mac.
The idea behind SwiftPlot is to create a cross-platform library that runs on iOS, Mac, Linux and Windows.
SwiftPlot currently uses three rendering backends to generate plots:
Anti-Grain Geometry(AGG) C++ rendering library
A simple SVG Renderer
A Core Graphics renderer with support for macOS, iOS, watchOS and tvOS
To encode the plots as PNG images it uses the lodepng library.
SwiftPlot can also be used in Jupyter Notebooks, with Python interop support for Google Colab.
Examples, demonstrating all the features, have been included with the repository under the Tests/SwiftPlotTests directory. To run the examples, clone the repository, and run the swift test command from the package directory.
Jupyter Notebook examples are under the Notebooks directory.
The resultant images are stored in a directory named output. The Tests folder includes a collection of reference images in the Reference directory.
License
SwiftPlot is licensed under Apache 2.0. View license
How to include the library in your package
Add the library to your projects dependencies in the Package.swift file as shown below.
In order to display the generated plot in the notebook, add this line to a new cell:
%include "EnableJupyterDisplay.swift"
If you wish to display the generated plot in a Google Colab environment, add these lines to a new cell instead:
import Python
%include "EnableIPythonDisplay.swift"
func display(base64EncodedPNG: String) {
let displayImage = Python.import("IPython.display")
let codecs = Python.import("codecs")
let imageData = codecs.decode(Python.bytes(base64EncodedPNG, encoding: "utf8"), encoding: "base64")
displayImage.Image(data: imageData, format: "png").display()
}
Note that because Google Colab doesn’t natively support Swift libraries that produce rich output, we use Swift’s Python interop as a workaround.
How to setup Docker instance for SwiftPlot
For computers running MacOS or Windows, Docker instance is to easy to setup and use swift-jupyter. Please refer SwiftPlot_Docker_setup.md for setup instructions.
Examples
Here are some examples to provide you with a headstart to using this library. Here we will be looking at plots using only the AGGRenderer, but the procedure will remain the same for SVGRenderer.
To use the library in your package, include it as a dependency to your target, in the Package.swift file.
import SwiftPlot
import AGGRenderer
let x:[Float] = [10,100,263,489]
let y:[Float] = [10,120,500,800]
let x1:[Float] = [100,200,361,672]
let y1:[Float] = [150,250,628,800]
var agg_renderer: AGGRenderer = AGGRenderer()
var lineGraph = LineGraph<Float,Float>()
lineGraph.addSeries(x1, y1, label: "Plot 1", color: .lightBlue, axisType: .primaryAxis)
lineGraph.addSeries(x, y, label: "Plot 2", color: .orange, axisType: .secondaryAxis)
lineGraph.plotTitle.title = "SECONDARY AXIS"
lineGraph.plotLabel.xLabel = "X-AXIS"
lineGraph.plotLabel.yLabel = "Y-AXIS"
lineGraph.plotLineThickness = 3.0
lineGraph.drawGraphAndOutput(fileName: filePath+"agg/"+fileName, renderer: agg_renderer)
The series plotted on the secondary axis are drawn dashed.
Displaying plots in Jupyter Notebook
You can display plots in Jupyter Notebook using only the AGGRenderer.
To do so, create the plots as shown in the above examples and instead of using the drawGraphAndOutput function from LineGraph, use the drawGraph function, then get a base64 encoded image from the AGGRenderer and pass it to the display function as showm below:
All the plotting code, utility functions, and necessary types are included in the SwiftPlot module. Each Renderer is implemented as a separate module. Each Renderer must have SwiftPlot as its dependency and must conform to the Renderer protocol defined in Renderer.swift in the SwiftPlot module. Each plot type is a generic that accepts data conforming to a protocol, FloatConvertible. At the moment FloatConvertible supports both Float and Double.
The Renderer protocol defines all the necessary functions that a Renderer needs to implement.
Each Plot must conform to the Plot protocol. At the moment this protocol defines the necessary variablse and functions that each Plot must implement in order to support SubPlots.
You can add series to the plots using their respective functions(addSeries for LineGraph). This is stored in as an array of Series objects. You can set other properties such as plotTitle, plotLabel, plotDimensions, etc. To actually generate the plot you need to call either the drawGraph or drawGraphAndOutput function. This calculates all the parameters necessary to generate the plots such as the coordinates of the border, scaled points to plot, etc. Then it sends over this information to the renderer which has functions to draw primitives like lines, rectangles and text.
In case the Renderer is in C++(here in the case of AGG), a C wrapper is written which is in turn wrapped in Swift.
In order to display the plots in Jupyter notebook, we encode the image(which is in the form of an RGB buffer) to a PNG image in memory and return the encoded image to the Swift code where it is stored as NSData. Then it is encoded to base64 and passed to the display function in swift-jupyter which finally displays the image.
Add a function to plot along with the range of x-coordinates over which to plot, number of samples of the function to take for plotting, a label, and color for the plot
Table of contents
Overview
The SwiftPlot framework is a cross-platform library that lets you plot graphs natively in Swift. The existing Swift plotting frameworks (such as CorePlot) run only on iOS or Mac. The idea behind SwiftPlot is to create a cross-platform library that runs on iOS, Mac, Linux and Windows. SwiftPlot currently uses three rendering backends to generate plots:
To encode the plots as PNG images it uses the lodepng library. SwiftPlot can also be used in Jupyter Notebooks, with Python interop support for Google Colab.
Examples, demonstrating all the features, have been included with the repository under the
Tests/SwiftPlotTests
directory. To run the examples, clone the repository, and run theswift test
command from the package directory.Jupyter Notebook examples are under the
Notebooks
directory.The resultant images are stored in a directory named
output
. TheTests
folder includes a collection of reference images in theReference
directory.License
SwiftPlot is licensed under
Apache 2.0
. View licenseHow to include the library in your package
Add the library to your projects dependencies in the Package.swift file as shown below.
In case you get an error saying that a file ft2build.h is not found, you need to install the freetype development package.
Linux
macOS
If the above method doesn’t work you can also build and install freetype on your own. You can find the source code and build instructions here.
How to include the library in your Jupyter Notebook
Add these lines to the first cell:
In order to display the generated plot in the notebook, add this line to a new cell:
If you wish to display the generated plot in a Google Colab environment, add these lines to a new cell instead:
Note that because Google Colab doesn’t natively support Swift libraries that produce rich output, we use Swift’s Python interop as a workaround.
How to setup Docker instance for SwiftPlot
For computers running MacOS or Windows, Docker instance is to easy to setup and use
swift-jupyter
. Please refer SwiftPlot_Docker_setup.md for setup instructions.Examples
Here are some examples to provide you with a headstart to using this library. Here we will be looking at plots using only the AGGRenderer, but the procedure will remain the same for SVGRenderer. To use the library in your package, include it as a dependency to your target, in the Package.swift file.
More tests can be found in the SwiftPlotTests folder.
Simple Line Graph
Line Graph with multiple series of data
Line Graph with Sub Plots stacked horizontally
Plot functions using LineGraph
Using a secondary axis in LineGraph
The series plotted on the secondary axis are drawn dashed.
Displaying plots in Jupyter Notebook
You can display plots in Jupyter Notebook using only the AGGRenderer. To do so, create the plots as shown in the above examples and instead of using the
drawGraphAndOutput
function from LineGraph, use thedrawGraph
function, then get a base64 encoded image from the AGGRenderer and pass it to the display function as showm below:How does this work
All the plotting code, utility functions, and necessary types are included in the SwiftPlot module. Each Renderer is implemented as a separate module. Each Renderer must have SwiftPlot as its dependency and must conform to the Renderer protocol defined in Renderer.swift in the SwiftPlot module. Each plot type is a generic that accepts data conforming to a protocol, FloatConvertible. At the moment FloatConvertible supports both Float and Double. The Renderer protocol defines all the necessary functions that a Renderer needs to implement. Each Plot must conform to the Plot protocol. At the moment this protocol defines the necessary variablse and functions that each Plot must implement in order to support SubPlots. You can add series to the plots using their respective functions(
addSeries
for LineGraph). This is stored in as an array of Series objects. You can set other properties such as plotTitle, plotLabel, plotDimensions, etc. To actually generate the plot you need to call either thedrawGraph
ordrawGraphAndOutput
function. This calculates all the parameters necessary to generate the plots such as the coordinates of the border, scaled points to plot, etc. Then it sends over this information to the renderer which has functions to draw primitives like lines, rectangles and text. In case the Renderer is in C++(here in the case of AGG), a C wrapper is written which is in turn wrapped in Swift. In order to display the plots in Jupyter notebook, we encode the image(which is in the form of an RGB buffer) to a PNG image in memory and return the encoded image to the Swift code where it is stored as NSData. Then it is encoded to base64 and passed to the display function in swift-jupyter which finally displays the image.Documentation
LineGraph<T: FloatConvertible, U: FloatConvertible>
BarChart<T: LosslessStringConvertible, U: FloatConvertible>
Histogram<T:FloatConvertible>
ScatterPlot<T:FloatConvertible, U:FloatConvertible>
SubPlot
PlotDimensions
Pair<T,U>
PlotLabel
PlotTitle
Color
Built-in Colors can be found here.
PlotLabel
Axis<T,U>
ScatterPlotSeriesOptions
HistogramSeriesOptions
BarGraphSeriesOptions
Base64Encoder
Limitations
Guidelines for Contributors
If you want to contribute to improve this library, please read our guidelines. Feel free to open an issue.
Credits