I've done this for my bachelorthesis, I did it like this (it's not perfect, but it might help you):
(I removed some unimportant methods/functions from the code below. It's mainly to illustrate how I visualized it. You can replace the GRectangle class by a simple java.awt.Point for example.)
The initialization method gives you an example of how you can find the maximum and minimum value of the data so you know how to transform your datavalues => coordinates.
public class DotVisualisation extends Visualisation {
private ArrayList<GRectangle> m_points;
private Comparable[] m_data;
private Comparable m_maxValue;
private Comparable m_minValue;
private int MAX_HEIGHT; // max height in pixels of visualization
/**
* Creates a new DotVisualisation.<br>
* <br>
* This class is a runnable JComponent that will visualize data as a function.
* The visualisation will plot the data with X and Y coordinates on the window.
* The X coordinate of the point is index of the dataelement.
* The Y coordinate of the point is relative to the value of the dataelement.<br>
* <br>
* This visualisation should be used for medium and large arrays.
*
* @author David Nysten
*/
public DotVisualisation()
{
m_points = new ArrayList<GRectangle>();
MAX_HEIGHT = 150;
}
/**
* Returns the maximum supported dimension by this visualisation.
*
* @return The supported dimension.
*/
public static int getSupportedDimension()
{
return 1;
}
@Override
public Dimension getMaximumSize()
{
return getPreferredSize();
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(m_points.size() + 2, MAX_HEIGHT + 6);
}
@Override
public Dimension getMinimumSize()
{
return getPreferredSize();
}
@Override
public void paintComponent(Graphics g)
{
for(int i = 0; i < m_points.size(); ++i)
m_points.get(i).paintComponent(g);
}
private void swap(int index, int index2) { // See below }
private void initialise()
{
findMinimum();
findMaximum();
m_points.clear();
double multiplier;
int x = 0, y = 0, h;
for(int i = 0; i < m_data.length; ++i)
{
if(m_data[i].compareTo(-1) <= 0)
h = 0;
else
{
Integer value = (Integer) m_data[i];
Integer min = (Integer) m_minValue;
Integer diff = (Integer) m_maxValue - min;
multiplier = MAX_HEIGHT / diff.doubleValue();
h = (int) ((value - min) * multiplier);
}
y = (int) (MAX_HEIGHT - h);
GRectangle r = new GRectangle(x, y, 1, 1); // 1, 1 = width and height
r.setColor(Color.BLACK);
m_points.add(r);
++x;
}
}
private void findMaximum()
{
Comparable max = null;
if(m_data.length > 0)
{
max = m_data[0];
for(int i = 1; i < m_data.length; ++i)
if(m_data[i].compareTo(max) > 0)
max = m_data[i];
}
m_maxValue = max;
}
private void findMinimum()
{
Comparable min = null;
if(m_data.length > 0)
{
min = m_data[0];
for(int i = 1; i < m_data.length; ++i)
if(m_data[i].compareTo(min) < 0)
min = m_data[i];
}
m_minValue = min;
}
}
Take this into account:
Visualizing integers between 0 and 150 on a height of 150 pixels is straightforward. Visualizing a set of integers between the values 565 and 3544545 on a height of 150 is a bit less so.
PS: The code uses the index of the element in the inputarray as the X-coordinate.
PS: The class keeps a reference to the inputarray (m_data variable) but that's ofcourse not needed, you only need it to initialize your points.
PS: My "Visualization" class which is extended by all visualizations, is basicly a JPanel.
PS: The code above is written for positive integers, so will probably need some extra coding to handle negative integers aswell ;).
Then to visualize the actions of the algorithm, I used the observer pattern. The algorithm, for example bubblesort, looked like this:
for(int i = 0; i < size(); ++i)
for(int j = 1; j < size(); ++j)
if(greaterThan(j - 1, j))
swap(j - 1, j);
Where the function swap was defined as follows (simplified version again):
protected void swap(int index1, int index2)
{
if(index1 != index2)
{
incrementSwap(); // counting swaps and visualizing counter
m_command.clear();
m_command.setAction(Action.SWAP);
m_command.addParameter(index1);
m_command.addParameter(index2);
setChanged();
notifyObservers(m_command);
E temp = m_data[index1];
m_data[index1] = m_data[index2];
m_data[index2] = temp;
}
}
Where I notified my observers (visualizations) that a swap occured on index1 and index2. The m_command variable is an instance of the Command-class (wrote it myself) which is just a wrapper for the information needed by the visualization. Which is: the action that occured and the relevant information (indices for a swap-action for example).
So in the visualization i swapped the GRectangles on those indices aswell as their X-coordinates;
private void swap(int index, int index2)
{
if(index == index2)
return;
GRectangle r1 = m_points.get(index);
GRectangle r2 = m_points.get(index2);
int tempX = r1.getX();
r1.setLocation(r2.getX(), r1.getY());
r2.setLocation(tempX, r2.getY());
m_points.set(index, r2);
m_points.set(index2, r1);
}
You can add lines like this:
try {
Thread.sleep(100);
} catch(InterruptedException ignore) {}
to let a thread sleep 100ms before continueing. This might come in handy if it's getting visualized too fast.
So for an array with random integers it might look like this:
![enter image description here]()
And after sorting:
(Ofcourse it's not a straight line because the values in the inputarray were generated at random in this case)
![enter image description here]()
So if you have to - like I had to - allow multiple algorithms to work with the same visualization, I can recommend you to separate the visualization class and the algorithm class and work with an observer pattern to let the visualization update whenever an action occurs (set, swap, ...).
And then you can create something like this for comparisons;
http://i445.photobucket.com/albums/qq179/ultddave/DotVisualizationMany_zps63269d2a.png
http://i445.photobucket.com/albums/qq179/ultddave/DotVisualizationMany2_zps65e96fa9.png
Good luck!