001: package prefuse.action.filter;
002:
003: import java.util.Iterator;
004:
005: import prefuse.Constants;
006: import prefuse.Visualization;
007: import prefuse.action.GroupAction;
008: import prefuse.data.Graph;
009: import prefuse.data.expression.Predicate;
010: import prefuse.data.tuple.TupleSet;
011: import prefuse.data.util.BreadthFirstIterator;
012: import prefuse.data.util.FilterIterator;
013: import prefuse.util.PrefuseLib;
014: import prefuse.visual.VisualItem;
015: import prefuse.visual.expression.InGroupPredicate;
016:
017: /**
018: * Filter Action that sets visible all items within a specified graph distance
019: * from a set of focus items; all other items will be set to invisible.
020: *
021: * @author <a href="http://jheer.org">jeffrey heer</a>
022: */
023: public class GraphDistanceFilter extends GroupAction {
024:
025: protected int m_distance;
026: protected String m_sources;
027: protected Predicate m_groupP;
028: protected BreadthFirstIterator m_bfs;
029:
030: /**
031: * Create a new GraphDistanceFilter that processes the given data group
032: * and uses a graph distance of 1. By default, the
033: * {@link prefuse.Visualization#FOCUS_ITEMS} group will be used as the
034: * source nodes from which to measure the distance.
035: * @param group the group to process. This group should resolve to a
036: * Graph instance, otherwise exceptions will be thrown when this
037: * Action is run.
038: */
039: public GraphDistanceFilter(String group) {
040: this (group, 1);
041: }
042:
043: /**
044: * Create a new GraphDistanceFilter that processes the given data group
045: * and uses the given graph distance. By default, the
046: * {@link prefuse.Visualization#FOCUS_ITEMS} group will be used as the
047: * source nodes from which to measure the distance.
048: * @param group the group to process. This group should resolve to a
049: * Graph instance, otherwise exceptions will be thrown when this
050: * Action is run.
051: * @param distance the graph distance within which items will be
052: * visible.
053: */
054: public GraphDistanceFilter(String group, int distance) {
055: this (group, Visualization.FOCUS_ITEMS, distance);
056: }
057:
058: /**
059: * Create a new GraphDistanceFilter that processes the given data group
060: * and uses the given graph distance.
061: * @param group the group to process. This group should resolve to a
062: * Graph instance, otherwise exceptions will be thrown when this
063: * Action is run.
064: * @param sources the group to use as source nodes for measuring
065: * graph distance.
066: * @param distance the graph distance within which items will be
067: * visible.
068: */
069: public GraphDistanceFilter(String group, String sources,
070: int distance) {
071: super (group);
072: m_sources = sources;
073: m_distance = distance;
074: m_groupP = new InGroupPredicate(PrefuseLib.getGroupName(group,
075: Graph.NODES));
076: m_bfs = new BreadthFirstIterator();
077: }
078:
079: /**
080: * Return the graph distance threshold used by this filter.
081: * @return the graph distance threshold
082: */
083: public int getDistance() {
084: return m_distance;
085: }
086:
087: /**
088: * Set the graph distance threshold used by this filter.
089: * @param distance the graph distance threshold to use
090: */
091: public void setDistance(int distance) {
092: m_distance = distance;
093: }
094:
095: /**
096: * Get the name of the group to use as source nodes for measuring
097: * graph distance. These form the roots from which the graph distance
098: * is measured.
099: * @return the source data group
100: */
101: public String getSources() {
102: return m_sources;
103: }
104:
105: /**
106: * Set the name of the group to use as source nodes for measuring
107: * graph distance. These form the roots from which the graph distance
108: * is measured.
109: * @param sources the source data group
110: */
111: public void setSources(String sources) {
112: m_sources = sources;
113: }
114:
115: /**
116: * @see prefuse.action.GroupAction#run(double)
117: */
118: public void run(double frac) {
119: // mark the items
120: Iterator items = m_vis.visibleItems(m_group);
121: while (items.hasNext()) {
122: VisualItem item = (VisualItem) items.next();
123: item.setDOI(Constants.MINIMUM_DOI);
124: }
125:
126: // set up the graph traversal
127: TupleSet src = m_vis.getGroup(m_sources);
128: Iterator srcs = new FilterIterator(src.tuples(), m_groupP);
129: m_bfs.init(srcs, m_distance, Constants.NODE_AND_EDGE_TRAVERSAL);
130:
131: // traverse the graph
132: while (m_bfs.hasNext()) {
133: VisualItem item = (VisualItem) m_bfs.next();
134: int d = m_bfs.getDepth(item);
135: PrefuseLib.updateVisible(item, true);
136: item.setDOI(-d);
137: item.setExpanded(d < m_distance);
138: }
139:
140: // mark unreached items
141: items = m_vis.visibleItems(m_group);
142: while (items.hasNext()) {
143: VisualItem item = (VisualItem) items.next();
144: if (item.getDOI() == Constants.MINIMUM_DOI) {
145: PrefuseLib.updateVisible(item, false);
146: item.setExpanded(false);
147: }
148: }
149: }
150:
151: } // end of class GraphDistanceFilter
|