package prefuse.action.assignment;
import java.util.Map;
import prefuse.Constants;
import prefuse.data.tuple.TupleSet;
import prefuse.util.DataLib;
import prefuse.visual.VisualItem;
/**
* <p>
* Assignment Action that assigns shape values for a group of items based upon
* a data field. Shape values are simple integer codes that indicate to
* appropriate renderer instances what shape should be drawn. The default
* list of shape values is included in the {@link prefuse.Constants} class,
* all beginning with the prefix <code>SHAPE</code>. Of course, clients can
* always create their own shape codes that are handled by a custom Renderer.
* </p>
*
* <p>The data field will be assumed to be nominal, and shapes will
* be assigned to unique values in the order they are encountered. Note that
* if the number of unique values is greater than
* {@link prefuse.Constants#SHAPE_COUNT} (when no palette is given) or
* the length of a specified palette, then duplicate shapes will start
* being assigned.</p>
*
* <p>This Action only sets the shape field of the VisualItem. For this value
* to have an effect, a renderer instance that takes this shape value
* into account must be used (e.g., {@link prefuse.render.ShapeRenderer}).
* </p>
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public class DataShapeAction extends ShapeAction {
protected static final int NO_SHAPE = Integer.MIN_VALUE;
protected String m_dataField;
protected int[] m_palette;
protected Map m_ordinalMap;
/**
* Create a new DataShapeAction.
* @param group the data group to process
* @param field the data field to base shape assignments on
*/
public DataShapeAction(String group, String field) {
super(group, NO_SHAPE);
m_dataField = field;
}
/**
* Create a new DataShapeAction.
* @param group the data group to process
* @param field the data field to base shape assignments on
* @param palette a palette of shape values to use for the encoding.
* By default, shape values are assumed to be one of the integer SHAPE
* codes included in the {@link prefuse.Constants} class.
*/
public DataShapeAction(String group, String field, int[] palette) {
super(group, NO_SHAPE);
m_dataField = field;
m_palette = palette;
}
// ------------------------------------------------------------------------
/**
* Returns the data field used to encode shape values.
* @return the data field that is mapped to shape values
*/
public String getDataField() {
return m_dataField;
}
/**
* Set the data field used to encode shape values.
* @param field the data field to map to shape values
*/
public void setDataField(String field) {
m_dataField = field;
}
/**
* This operation is not supported by the DataShapeAction type.
* Calling this method will result in a thrown exception.
* @see prefuse.action.assignment.ShapeAction#setDefaultShape(int)
* @throws UnsupportedOperationException
*/
public void setDefaultShape(int defaultShape) {
throw new UnsupportedOperationException();
}
// ------------------------------------------------------------------------
/**
* @see prefuse.action.EncoderAction#setup()
*/
protected void setup() {
TupleSet ts = m_vis.getGroup(m_group);
m_ordinalMap = DataLib.ordinalMap(ts, m_dataField);
}
/**
* @see prefuse.action.assignment.ShapeAction#getShape(prefuse.visual.VisualItem)
*/
public int getShape(VisualItem item) {
// check for any cascaded rules first
int shape = super.getShape(item);
if ( shape != NO_SHAPE ) {
return shape;
}
// otherwise perform data-driven assignment
Object v = item.get(m_dataField);
int idx = ((Integer)m_ordinalMap.get(v)).intValue();
if ( m_palette == null ) {
return idx % Constants.SHAPE_COUNT;
} else {
return m_palette[idx % m_palette.length];
}
}
} // end of class DataShapeAction