Whereas the ArrayFire library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing, ArrayFire's <a href="https://github.com/arrayfire/forge">Forge</a> library attempts to provide an equally powerful and performant methods to visualize data stored on accelerators (most often GPUs) using an OpenGL context. By default, ArrayFire ships with the Forge visualization library built in . Unless you or your system administrator have installed the "no-graphics" version, ArrayFire already includes everything you need to use Forge.

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.
<h1><a id="setup" class="anchor"></a>Setup</h1>
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>
<h1><a id="render_func" class="anchor"></a>Rendering Functions</h1>
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.
<h3><a id="Image_38"></a>Image</h3>
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.
<h3><a id="Plot_63"></a>Plot</h3>
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>
<h3><a id="Scatter_88"></a>Scatter</h3>
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>
<h3><a id="Plot3_118"></a>Plot3</h3>
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>
<h3><a id="Histogram_140"></a>Histogram</h3>
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>
<h3><a id="Scatter3_162"></a>Scatter3</h3>
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>
<h3><a id="Surface_195"></a>Surface</h3>
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>
<h2><a id="Conclusion_216"></a>Conclusion</h2>
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.