public void update(final FrameStatistics stats) {
	    
	    List<Long> statsThisUpdate = new ArrayList<Long>();
	    
	    for (InputStatistics is : stats.getInputStats()) {
	        InfoBox infoBox = infoBoxes.get(is.getId());
	        if (infoBox == null) {
	            infoBox = new InfoBox();
	            infoBoxes.put(is.getId(), infoBox);
	            inputsColumn.addItem(infoBox);
	        }
	        infoBox.updateStats(is);
	        statsThisUpdate.add(is.getId());
	    }

	    for (LayerStatistics ls : stats.getLayerStats()) {
	        InfoBox infoBox = infoBoxes.get(ls.getId());
	        if (infoBox == null) {
	            infoBox = new InfoBox();
	            
	            if (ls.getInputStat() != null) {
	                InfoBox feeder = infoBoxes.get(ls.getInputStat().getId());
	                infoBox.pointsTo = feeder;
	            }
	            
	            infoBoxes.put(ls.getId(), infoBox);
	            
	            // XXX assumes flat hierarchy under root layer
	            if (ls.isRootLayer()) {
	                rootLayerColumn.addItem(infoBox);
	                infoBox.display.setIconScale(3f);
	            } else {
	                layersColumn.addItem(infoBox);
	            }
	        }
	        infoBox.updateStats(ls);
	        statsThisUpdate.add(ls.getId());
	    }

	    for (OutputStatistics os : stats.getOutputStats()) {
	        InfoBox infoBox = infoBoxes.get(os.getId());
	        if (infoBox == null) {
	            infoBox = new InfoBox();
	            infoBoxes.put(os.getId(), infoBox);
	            outputsColumn.addItem(infoBox);
	        }
	        infoBox.updateStats(os);
	        statsThisUpdate.add(os.getId());
	    }

	    // reap unused infoboxes
        infoBoxes.keySet().retainAll(statsThisUpdate);
        
        inputsColumn.retainAll(infoBoxes.values());
        layersColumn.retainAll(infoBoxes.values());
        rootLayerColumn.retainAll(infoBoxes.values());
        outputsColumn.retainAll(infoBoxes.values());
	}