The ArrayFire library attempts to make high-performance computing as easy as possible for scientists and engineers. Because many tasks need to be visualized, ArrayFire also provides a high-level interface to our <a href="https://github.com/arrayfire/forge">Forge visualization library</a>. In today's "<a href="http://sandbox.arrayfire.com/tag/learning-arrayfire-from-scratch/">Learning ArrayFire from scratch</a>" post we present an overview of ArrayFire's visualization functionality and demonstrate how to use Forge to display data contained in af::array objects.

<!--more-->

The Forge library is a general-purpose visualization tool for data stored on the GPU or related accelerator devices. By default, ArrayFire ships with Forge built in. However; if you or your system administrator installed the "no-graphics" version of ArrayFire, Forge won't be included.

ArrayFire provides several wrapper functions that simplify Forge's interface when used with <a class="el" title="A multi dimensional data container. " href="classaf_1_1array.htm">af::array</a> objects. These functions primarily perform interop tasks including visualization range setting, copying data into OpenGL data structures, and generating an OpenGL window for display.
<h4><a id="setup" class="anchor"></a>Setup</h4>
Before we can use Forge, we must create an window containing an OpenGL context. Creating an instance of the<code><a class="el" title="Window object to render af::arrays. " href="classaf_1_1Window.htm">af::Window</a></code> class will accomplish both of these tasks. Note, at present Forge must create and manage its own OpenGL context; however, we hope to change this in a future release. Once the window is created, you can use Forge's drawing functions to visualize your data. Here is a basic example of how to create a window, set its title, and enter into a drawing loop:
<div class="fragment">
<div class="line">
<pre class="lang:default decode:true ">const static int width = 512, height = 512;
af::Window window(width, height, "2D plot example title");
 
do{
 
//drawing functions here
 
} while( !window.close() );</pre>
</div>
</div>
<h4><a id="render_func" class="anchor"></a>Rendering Functions</h4>
As included in ArrayFire 3.3, Forge provides the following plotting capabilities:
<table class="doxtable">
<tbody>
<tr>
<th>Function</th>
<th>Description</th>
</tr>
<tr>
<td><a class="el" title="Renders the input array as a histogram to the window. " href="group__gfx__func__draw.htm#gafd7d94aa8f5fd37fee0662a4906a38d7">af::Window::hist()</a></td>
<td>Creates a histogram plot from input data and bins</td>
</tr>
<tr>
<td><a class="el" title="Renders the input array as an image to the window. " href="group__gfx__func__draw.htm#gaed174450be6db4dfa5ef65b7baccbe57">af::Window::image()</a></td>
<td>Display an image</td>
</tr>
<tr>
<td><a class="el" title="Renders the input arrays as a 2D plot to the window. " href="group__gfx__func__draw.htm#ga8e01736df3d805a5488c609e2573818b">af::Window::plot()</a></td>
<td>2D Line plot</td>
</tr>
<tr>
<td><a class="el" title="Renders the input array as an 3d line plot to the window. " href="group__gfx__func__draw.htm#ga8e04ec129034e9fe769f3e6b14cd087f">af::Window::plot3()</a></td>
<td>3D line plot</td>
</tr>
<tr>
<td><a class="el" title="Renders the input arrays as a 2D scatter-plot to the window. " href="group__gfx__func__draw.htm#ga73406db589e5090c051baae0af175df9">af::Window::scatter()</a></td>
<td>2D scatter plot</td>
</tr>
<tr>
<td><a class="el" title="Renders the input arrays as a 3D scatter-plot to the window. " href="group__gfx__func__draw.htm#ga3bbfbe1b60741a259d2146b3ab50ace3">af::Window::scatter3()</a></td>
<td>3D scatter plot</td>
</tr>
<tr>
<td><a class="el" title="Renders the input arrays as a 3D surface plot to the window. " href="group__gfx__func__draw.htm#ga1cdb8c3205d70d8feaddd8c30245393f">af::Window::surface()</a></td>
<td>Visualize a 3D surface</td>
</tr>
</tbody>
</table>
Full documentation on all plotting functions can be found in the <a class="el" href="group__gfx__func__draw.htm">rendering functions</a> portion of the documentation.
<h5><a id="Image_38"></a>Image</h5>
The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.
Let’s see this on a static noise example:
<pre><code class="language-{.cpp}">array img = constant(0, width, height);   //make a black image
array random = randu(width, height);      //make random [0,1] distribution

window.image(img);</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png"><img class="aligncenter size-medium wp-image-8710" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png" alt="Forge image plot of noise" width="262" height="300" /></a>

Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:
<pre><code class="language-{.cpp}">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution
window.image( img.as(u8) );</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png"><img class="aligncenter size-medium wp-image-8708" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png" alt="Forge image plot of color noise" width="262" height="300" /></a>

Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range
[0, 255]. The type-handling properties are consistent for all Forge drawing functions.
<h5><a id="Plot_63"></a>Plot</h5>
The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:
<pre><code class="language-{.cpp}">array X = seq(-af::Pi, af::Pi, 0.01);
array Y = sin(X);
window.plot(X, Y);</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png"><img class="aligncenter size-medium wp-image-8714" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png" alt="Forge 2d line plot of sin() function" width="296" height="300" /></a>
The plot function has the signature:

<code><strong>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</strong></code>

Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:
<pre><code class="language-{.cpp}">array t = seq(0, 100, 0.01);
array X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));
array Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));
window.plot(X, Y);</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png"><img class="aligncenter size-medium wp-image-8707" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png" alt="" width="290" height="300" /></a>
<h5><a id="Scatter_88"></a>Scatter</h5>
The af::Window::scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:
<pre><code class="language-{.cpp}">array X = seq(-af::Pi, af::Pi, 0.01);
array noise = randn(X.dims(0)) /3.0f;
array Y = sin(X) + noise;
window.scatter(X, Y);</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png"><img class="aligncenter size-medium wp-image-8715" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png" alt="Forge 2d scatter plot" width="300" height="228" /></a>

The scatter function has the signature:

<code><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT, const char * const title = NULL);</strong></code>

The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.
It can take on the values of:
<pre><code class="language-{.cpp}">enum af::markerType {
    AF_MARKER_POINT
    AF_MARKER_CIRCLE
    AF_MARKER_SQUARE
    AF_MARKER_TRIANGLE
    AF_MARKER_CROSS
    AF_MARKER_PLUS
    AF_MARKER_STAR
};</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png"><img class="aligncenter size-full wp-image-8709" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png" alt="Different types of markers in Forge." width="1846" height="326" /></a>
<h5><a id="Plot3_118"></a>Plot3</h5>
The af::Window::plot3() function will plot a curve in 3d-space.
Its signature is:

<code><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></code>

The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.
<pre><code class="language-{.cpp}">array Z = seq(0.1f, 10.f, 0.01);
array Y = sin(10 * Z) / Z;
array X = cos(10 * Z) / Z;

array Pts = join(1, X, Y, Z);
//Pts can be passed in as a matrix in the from n x 3, 3 x n
//or in the flattened xyz-triplet array with size 3n x 1
window.plot3(Pts);
//both of the following are equally valid
//window.plot3(transpose(Pts));
//window.plot3(flat(Pts));</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png"><img class="aligncenter size-medium wp-image-8716" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png" alt="Forge 3d line plot" width="300" height="211" /></a>
<h5><a id="Histogram_140"></a>Histogram</h5>
The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.
<pre><code class="language-{.cpp}">const int BINS = 128; SAMPLES = 9162;
array norm = randn(SAMPLES);
array hist_arr = histogram(norm, BINS);

win.hist(hist_arr, 0, BINS);</code></pre>
In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:

<code><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></code>

<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png"><img class="aligncenter size-medium wp-image-8711" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png" alt="Forge histogram plot" width="300" height="256" /></a>
<h5><a id="Scatter3_162"></a>Scatter3</h5>
The af::Window::scatter3() function visualizes an array as a 3d-scatter plot.
Its signature is:

<code><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></code>

The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.

<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png"><img class="aligncenter size-medium wp-image-8712" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png" alt="Forge 3d scatter plot" width="300" height="208" /></a>
<pre><code class="language-{.cpp}">array X = randn(300);
array Y = randn(300);
array Z = randn(300);

array Pts = join(1, X, Y, Z);
window.scatter3(Pts);</code></pre>
The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:
<pre><code class="language-{.cpp}">enum af::markerType {
    AF_MARKER_POINT
    AF_MARKER_CIRCLE
    AF_MARKER_SQUARE
    AF_MARKER_TRIANGLE
    AF_MARKER_CROSS
    AF_MARKER_PLUS
    AF_MARKER_STAR
};</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png"><img class="aligncenter size-full wp-image-8709" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png" alt="Different types of markers in Forge." width="1846" height="326" /></a>
<h5><a id="Surface_195"></a>Surface</h5>
The af::Window::surface() function will plot af::arrays as a 3d surface.
<pre><code class="language-{.cpp}">array Z = randu(21, 21);
window.surface(Z, "Random Surface");    //equal to next function call
//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, "Random Surface");</code></pre>
<a href="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png"><img class="aligncenter size-medium wp-image-8713" src="http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png" alt="Forge 3d surface() plot" width="300" height="269" /></a>
There are two overloads for the af::Window::surface() function:

<code><strong>void surface (const array &amp; S, const char * const title )</strong>
// Accepts a 2d matrix with the z values of the surface</code>

<code><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>
// accepts additional vectors that define the x,y coordinates for the surface points.</code>

The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:
<ol>
 	<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>
 	<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>
</ol>
<h4><a id="Conclusion_216"></a>Conclusion</h4>
There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.