MGitWriteSparkline dialog `MGitWriteSparkline` is an example of a file writer for the iTools system. It creates a PNG file representing a [sparkline](http://en.wikipedia.org/wiki/Sparkline) for vector data. Sparklines are intense, word-like graphics like Boulder temperature highs 55. Readers and writers are some of the simplest components to add to an iTool and a good place to start learning how to create custom iTools.

In order to run this demo, you will need the the [`MGitWriteSparkline` class](http://michaelgalloy.com/demos/itools/mgitwritesparkline__define.pro) ([doc](http://michaelgalloy.com/demos/itools/mgitwritesparkline__define.html)), the [calling program](http://michaelgalloy.com/demos/itools/mg_sparkwriter_demo.pro) ([doc](http://michaelgalloy.com/demos/itools/mg_sparkwriter_demo.html)), and the [original sparklines routine](https://github.com/mgalloy/mglib/tree/master/src/vis/lineplots/sparklines/mg_sparkline.pro) ([doc](http://michaelgalloy.com/lib/sparklines/mg_sparkline.html) and see [this article](http://michaelgalloy.com/2006/04/19/sparklines-implementation.html) about the sparklines routine).

### The calling program ###

The calling program, `MG_SPARKWRITER_DEMO`, is fairly simple.

iplot, randomu(seed, 50)
id = itGetCurrent(tool=oplot)
oplot->registerFileWriter, 'Sparkline writer', 'MGitWriteSparkline', $
description='PNG representation of a sparkline'

It creates an iPlot with some random data, gets the object reference for the iPlot, and registers the file writer with it.

### Methods of MGitWriteSparkline ###

I'll list all the methods of `MGitWriteSparkline` with simple descriptions. Most of these methods will be straightforward to write for those with experience with how properties work in the iTools or object graphics systems.

function mgitwritesparkline::init, _ref_extra=e
pro mgitwritesparkline::cleanup

The `init` method is responsible for registering and initializing properties of the class. This will be discussed in the properties section below. The `cleanup` method just calls the parent `IDLitWriter::cleanup` method since we don't allocate any resources that need to be freed.

pro mgitwritesparkline::getProperty, width=width, height=height, $
color=color, transparent_background=transparent_background, $
background=background, use_range_band=use_range_band, $
band_color=band_color, endpoint_color=endpoint_color, $
_ref_extra=e
pro mgitwritesparkline::setProperty, width=width, height=height, $
color=color, transparent_background=transparent_background, $
background=background, use_range_band=use_range_band, $
band_color=band_color, endpoint_color=endpoint_color, $
_ref_extra=e

In the `init`, `setProperty`, and `getProperty` methods make sure to pass along keywords not expicitly declared to their corresponding `IDLitWriter` methods. We'll discuss how to deal with the properties and their attributes in more detail in a section below.

function mgitwritesparkline::setData, oPlotData

This method is special for `IDLitWriter` subclasses and it is where the real work is done. We'll discuss it in more detail in a section below.

### Properties of `MGitWriteSparkline` ###

A property is created in the `init` method with `registerProperty`. The name of the property is the positional parameter argument while the `NAME` gives a human readable version. An optional second position parameter gives the data type of the property. If not present then one of the type keywords must be used. Here, the `COLOR` keyword indicates the type. Also, the `SENSITIVE` keyword indicates the user interface should not allow this property to be modified. (The aspects of the property here corresponding to these keywords are called *attributes*.)

self->registerProperty, 'background', name='Background', $
description='Background color of the plot', $
/color, sensitive=0

Later, in the `getProperty` method, a straightforward test using `ARG_PRESENT` indicates whether the stored value should be passed back. Here we have stored each property in an instance variable of the same name in the object.

if (arg_present(background)) then background = self.background

The `setProperty` method is more complicated because the value of the `TRANSPARENT_BACKGROUND` property indicates whether the `BACKGROUND` property is needed (and hence if it can be set in the user interface). The relevant part for our property `BACKGROUND` is:

if (n_elements(transparent_background) gt 0) then begin
self.transparent_background = transparent_background
self->setPropertyAttribute, 'background', $
sensitive=~transparent_background
endif
if (n_elements(background) gt 0) then self.background = background

We use the `setPropertyAttribute` method to change attributes like `SENSITIVE` or `HIDE`.

### `MGitWriteSparkline::setData` method ###

Finally, the `setData` method is responsible for getting an iTools data object and creating the output file. The filename of this file is found by using the `getFilename` method:

filename = self->getFilename()
if (filename eq '') then return, 0

The return value for this function is a status code: 0 for failure, 1 for success.

if (~obj_valid(oPlotData)) then begin
self->errorMessage, ['Invalid plot data object'], title='Error', $
severity=2
return, 0
endif

The `oPlotData` parameter is an iTools data object containing the data to be written (i.e. selected by the user in the writing dialog). Here, only type IDLVECTOR data can be used to create a sparkline.

odata = oPlotData->getByType('IDLVECTOR', count=nplots)
if (nplots eq 0) then begin
self->errorMessage, ['Invalid data provided to file writer'], $
title='Error', /severity
endif

The `odata`> return value of the `getByType` method could contain an array of data objects. Here, we'll only consider the first one, pulling the data out of it with the `getData` method.

odata = odata[0]
result = odata->getData(y)
if (result eq 0) then begin
self->errorMessage, ['Error retrieving plot data'], $
title='Error', severity=2
endif

The `y` variable now holds the data to be written by the `mg_sparkline` routine.

mg_sparkline, filename, y, xsize=self.width, ysize=self.height, $
color=self.color, $
background=keyword_set(self.transparent_background) $
? undefined $
: self.background, $
band_color=keyword_set(self.use_range_band) $
? self.band_color $
: undefined, $
endpoint_color=self.endpoint_color

The `undefined` variable is actually undefined, i.e. `n_elements(undefined) eq 0`. It is needed here to indicate that we are not passing a value to a particular keyword.

return, 1B

Finally, return `1B` to indicate success.