In this section a NodeView for our node is implemented. In order to display information about the work of this node we display the bins in a histogram, where the height of each bin indicates the number of rows in this bin.
Internal Representation:
A model is required to represent the outcome of our algorithm. Obviously a model representing a bin is appropriate. A bin contains a number of rows and is graphically represented by a rectangle. Therefore, we create this data structure.
public class NumericBin {
private final Set m_containedRowIds;
public NumericBin() {
m_containedRowIds = new HashSet();
}
public void addRowToBin(final DataCell rowId) {
m_containedRowIds.add(rowId);
}
public int getSize() {
return m_containedRowIds.size();
}
To obtain the bins filled with the referring row IDs, an array with empty bins must be passed to the NumericBinnerCellFactory, which adds the row to the referring bin in the getCell method:
@Override
public DataCell getCell(DataRow row) {
DataCell currCell = row.getCell(m_colIndex);
...
int binNr = 0;
for (Double intervalBound : m_intervalUpperBounds) {
if (currValue <= intervalBound) {
m_bins[binNr].addRowToBin(row.getKey().getId());
return new IntCell(binNr);
}
binNr++;
}
...
Drawing Component:
Before we can start to implement the NodeView we have to implement a component that actually draws our bins. For this purpose we create our own JPanel using a quite simple paint method:
public class NumericBinnerViewPanel extends JPanel
...
@Override
public void paint(Graphics g) {
super.paint(g);
if (m_bins != null && m_bins.length > 0) {
int maxNr = 0;
for (int i = 0; i < m_bins.length; i++) {
maxNr = Math.max(m_bins[i].getSize(), maxNr);
}
int width = getWidth();
if (width == 0) {
width = SIZE;
}
int height = getHeight();
if (height == 0) {
height = SIZE;
}
int binWidth = width / m_bins.length;
for (int i = 0; i < m_bins.length; i++) {
int x = i * binWidth;
int binHeight = height;
double sizeFactor = ((double)(maxNr - m_bins[i].getSize())
/ (double)maxNr);
binHeight -= sizeFactor * height;
Rectangle rect = new Rectangle(x, height - binHeight, binWidth,
binHeight);
m_bins[i].setViewRepresentation(rect);
g.setColor(Color.BLACK);
g.fillRect(rect.x, rect.y, rect.width, rect.height);
g.setColor(Color.WHITE);
g.drawRect(rect.x, rect.y, rect.width, rect.height);
}
}
}
NodeView:
Implementation of the NodeView is very simple. In the constructor we create the drawing component (our NumericBinnerViewPanel) using the bins retrieved from the model. We set it as our view content via the setComponent method:
public class NumericBinnerNodeView extends NodeView {
private NumericBinnerViewPanel m_panel;
protected NumericBinnerNodeView(final NodeModel nodeModel) {
super(nodeModel);
NumericBin[] bins = ((NumericBinnerNodeModel)getNodeModel())
.getBinRepresentations();
if (bins != null && bins.length >0) {
m_panel = new NumericBinnerViewPanel(bins);
}
setComponent(m_panel);
}
Note that the panel might be null. If this is the case, the view displays a message that no data is available by default. Another situation might be that the view is open and the model changes (due to a different input, or a different configuration). Then the view has to be updated. This is realized by the modelChanged method in the NodeView: