Introduction
I believe strongly in plotting the data that I obtain, because plots tell you a story and they don’t mislead you like summary statistics can.
Often I want to plot data the arduino has acquired, but I find existing solutions don’t suit my needs. So I went out and made my own solution which writes a GNUPlot script in response to plot commands. I integrated the library with my general Arduino Toolbox (WDArduinoLib) and am releasing it under the GNU 2.0 License.
Goals
- Professional graphics
- Graphs manually editable after plotting for change colours etc.
- Arduino outputs data that other people can defiantly grab and use (just paste into a cloud based GNUPlot terminal)
- Allow embedded linux system to offload the plotting of graphs from arduino collected data
- Easy straight forward API
- Linux, Windows and Mac compatible.
- Quality API documentation
Features
- Configurable output
- You can use a Serial Port, SD-Card, Telnet, TCP-IP, IrDA, whatever. So long as it derives from the Arduino Print class (ie has Print and Println()) this library can output a graph to it
- Uses GNUPlot as a server to execute the plot script this API outputs.
- GNUPlot is the standard for scientific publication, it outputs presentable graphics ready for both websites, and software manuals.
- GNUPlot has been around forever (1986) and is still actively developed.
- GNUPlot can run on the Raspberry pi, PC, Mac or even online via http://plotshare.com/
- Extensible
- Easily over-rideable classes to add new plot types or different output terminal (eg Matlab)
- Built in quality colour palettes designed for graphing.
- Sample palettes for showing importance, of keeping different coloured categories at the same intensity.
- Spectral palettes , optimised for on-white graphing.
- Colour-blind compatible palettes .
- Can still use arbitrary 24bit RGB colours if you like.
- Unit tested library to support quality software development
- Template driven code designed for maximum data flexibility
- Memory Efficient.
- Use of progmem strings supported throughout.
- Useful, stable data format that does not rely on someone’s pet project still existing in 5 years time.
- All input, including text, is validated.
Examples
This library is simple to use and produces clean results with minimal configuration. I present several basic examples that show the API in use and the results obtained.
Example: Basic Line Graph
Line plots of time series data are probably the most important feature any graphing API targeted for micro-controllers can offer. This code creates such a plot. It demonstrates the use of multiple line styles.
//main GNUPlotLineGraph gnuLinePlotter(&Serial); PlotDampenedSineWaves(gnuLinePlotter); //method void PlotDampenedSineWaves(SerialGraph& plot) { //setup graph plot.newGraph(); plot.enableSaveImageFile(true); plot.setTitle(F("Dampened Sine Wave")); plot.setXAxisName(F("Time (Sec)")); plot.setYAxisName(F("Voltage (V)")); //setup series plot.setSeriesName(0, F("Slow decay")); plot.getLineApperance(0)->setLineStyle(LineStyles::SolidLine); plot.getLineApperance(0)->setLineWidth(4); plot.getLineApperance(0)->setRGB(GraphColorsSchemeBlues::Blue1); plot.setSeriesName(1, F("Medium decay")); plot.getLineApperance(1)->setLineStyle(LineStyles::DashedLine); plot.getLineApperance(1)->setLineWidth(3); plot.getLineApperance(1)->setRGB(GraphColorsSchemeBlues::Blue2); plot.setSeriesName(2, F("Quick decay")); plot.getLineApperance(2)->setLineStyle(LineStyles::DotedLine); plot.getLineApperance(2)->setLineWidth(2); plot.getLineApperance(2)->setRGB(GraphColorsSchemeBlues::Blue3); //plot graph for(int i=0; i<=720; i+=3) { float c = cos(DEG_TO_RAD*(float)i); float y1 = Dampen(i, c, 1, 1.0/360.0); float y2 = Dampen(i, c, 1, 1.0/240.0); float y3 = Dampen(i, c, 1, 1.0/180.0); plot.plotDatumXYn(i, y1, y2, y3); } plot.finishGraph(); }
Example: Plotting Points (Scatter Plot)
A scatter plots, with styles colours and trimmings.
//main GNUPlotPointGraph gnuPointPlotter(&Serial); PlotPointNoise(gnuPointPlotter); //method void PlotPointNoise(SerialGraph& plot) { //setup graph plot.newGraph(); plot.enableSaveImageFile(true); plot.setTitle(F("Sine Waves with Noise")); plot.setXAxisName(F("Time (Sec)")); plot.setYAxisName(F("Voltage (V)")); plot.setShowGrid(true); //setup series plot.setSeriesName(0, F("Pin 1")); plot.getLineApperance(0)->setMarkerStyle(LineMarkers::SquareMarker); plot.getLineApperance(0)->setRGB(0xff0000); plot.setSeriesName(1, F("Pin 2")); plot.getLineApperance(1)->setMarkerStyle(LineMarkers::CrossMarker); plot.getLineApperance(1)->setRGB(0x00ff00); plot.setSeriesName(2, F("Pin 3")); plot.getLineApperance(2)->setMarkerStyle(LineMarkers::CircleMarker); plot.getLineApperance(2)->setRGB(0x0000ff); //plot graph for(int i=0; i<=720; i+=5) { float c = cos(DEG_TO_RAD*(float)i); float y1 = c + Dampen(i, ((float)(random(100)-50)) *0.1, 1, 1.0/240.0); float y2 = c + Dampen(i, ((float)(random(100)-50)) *0.1, 1, 1.0/180.0)-2; float y3 = c + Dampen(i, ((float)(random(100)-50)) *0.1, 1, 1.0/90.0)-4; plot.plotDatumXYn(i, y1, y2, y3); } plot.finishGraph(); }
Example: Plotting Arbitrary Lines
Sometimes your not using time series data, and need to plot lines between arbitrary x/y positions. Many solutions for the arduino breakdown at this point. Here I demonstrate such a plot (based on the logarithmic spiral). Note I am using lines with point markers to show the actual points plotted.
//main GNUPlotLineGraph gnuLinePlotter(&Serial); PlotLogarithmicSpiral(gnuLinePlotter); //method void PlotLogarithmicSpiral(SerialGraph& plot) { //setup graph plot.newGraph(); plot.enableSaveImageFile(true); plot.setTitle(F("Logarithmic Spiral")); //setup series plot.setSeriesName(0, F("Spiral")); plot.getLineApperance(0)->setLineWidth(2); plot.getLineApperance(0)->setMarkerStyle(LineMarkers::SolidCircleMarker); plot.getLineApperance(0)->setRGB(GraphColorsSchemeSpectral::Spectral7); //plot graph float a = 1; float b = 0.1759; for(int i=0; i<(int)(10.0*20.0*M_PI); i+=5) { float t = ((float)i) * 0.1; float rt = a*pow(M_E, b* t); float x = rt*cos(t); float y = rt*sin(t); plot.plotDatumXY(x, y); } plot.finishGraph(); }
Example: Multi Column Bar Graph.
Bar graphs, for histograms and such are easy in this API. The example below shows support for multi column graphs, Note: negative values are also supported. The labels for the X-Axis are plotted as standard x values (the plot command is template driven and can support many different types of data).
//main GNUPlotBarGraph gnuBarPlotter(&Serial); PlotSampleBarGraph(gnuBarPlotter); //method void PlotSampleBarGraph(SerialGraph& plot) { //setup graph plot.newGraph(); plot.enableSaveImageFile(true); plot.setTitle(F("Google Results for Instruments")); plot.setXAxisName(F("Instrument")); plot.setYAxisName(F("# Google Results (millions)")); plot.setShowGrid(true); //setup series plot.setSeriesName(0, F("play")); plot.getLineApperance(0)->setRGB(GraphColorsSchemeOranges::Orange1); plot.setSeriesName(1, F("teach")); plot.getLineApperance(1)->setRGB(GraphColorsSchemeBlues::Blue1); plot.setSeriesName(2, F("like")); plot.getLineApperance(2)->setRGB(GraphColorsSchemeGreens::Green1); plot.setSeriesName(3, F("hate")); plot.getLineApperance(3)->setRGB(GraphColorsSchemeReds::Red1); //plot graph //Dataset compiled by Google-ing "I X the Y" // instrument play teach like hate plot.plotDatumXYn("Piano", 173, 25, 211, 21); plot.plotDatumXYn("Guitar", 163, 22, 193, 27); plot.plotDatumXYn("Violin", 41, 2, 43, 1); plot.plotDatumXYn("Drums", 30, 8, 83, 9); plot.finishGraph(); }
Installation
- Get the library from its github repository.
- See the official guide on how to install libraries https://www.arduino.cc/en/Guide/Libraries
- Run the provided example sketch
- Install GNUPlot v5.0 or later (here).
- Using the com port viewer, copy the output of sketch into GNUPlot.
- Enjoy!
It is very possible to get the output generated by this library to GNUPlot automatically. How you achieve this is up to you.
It is possible to direct the output to a SD card. See the arduino help page on the file class, to create you own file on a SD card. Then pass the open file object in to the constructor for your plotting class (where I used Serial in the examples).
Documentation
Full documentation available here.
License
GNU 2.0
State
Most Features are well tested, but I don’t warrant or accept liability for any of the functionality in any way.
NB: some dynamic memory usage , refrain from using malloc during plotting operations to prevent possible heap fragmentation.
- Dynamic memory usage is a design decision I made weighing pro’s and con’s of the situation.
- Given ‘typical usage’ scenarios of the API it should not cause heap fragmentation.
Road-Map
May happen:
- Second x/y axis support
- Matlab support
- 3d plots
- Spectrogram
- Support for cloud based rendering for graphs
- Sage support
- Thousands separator (right now I could not deploy it because of a bug in the windows version of GNUPlot).
Won’t Happen:
- Real-time visualisation (plenty of other projects to do that already)