KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > action > filter > FisheyeTreeFilter


1 package prefuse.action.filter;
2
3 import java.util.Iterator JavaDoc;
4
5 import prefuse.Constants;
6 import prefuse.Visualization;
7 import prefuse.action.GroupAction;
8 import prefuse.data.Graph;
9 import prefuse.data.Tree;
10 import prefuse.data.expression.Predicate;
11 import prefuse.util.PrefuseLib;
12 import prefuse.visual.EdgeItem;
13 import prefuse.visual.NodeItem;
14 import prefuse.visual.VisualItem;
15 import prefuse.visual.expression.InGroupPredicate;
16
17 /**
18  * <p>Filter Action that computes a fisheye degree-of-interest function over
19  * a tree structure (or the spanning tree of a graph structure). Visibility
20  * and DOI (degree-of-interest) values are set for the nodes in the
21  * structure. This function includes current focus nodes, and includes
22  * neighbors only in a limited window around these foci. The size of this
23  * window is determined by the distance value set for this action. All
24  * ancestors of a focus up to the root of the tree are considered foci as well.
25  * By convention, DOI values start at zero for focus nodes, with decreasing
26  * negative numbers for each hop away from a focus.</p>
27  *
28  * <p>This form of filtering was described by George Furnas as early as 1981.
29  * For more information about Furnas' fisheye view calculation and DOI values,
30  * take a look at G.W. Furnas, "The FISHEYE View: A New Look at Structured
31  * Files," Bell Laboratories Tech. Report, Murray Hill, New Jersey, 1981.
32  * Available online at <a HREF="http://citeseer.nj.nec.com/furnas81fisheye.html">
33  * http://citeseer.nj.nec.com/furnas81fisheye.html</a>.</p>
34  *
35  * @author <a HREF="http://jheer.org">jeffrey heer</a>
36  */

37 public class FisheyeTreeFilter extends GroupAction {
38
39     private String JavaDoc m_sources;
40     private Predicate m_groupP;
41     
42     private int m_threshold;
43     
44     private NodeItem m_root;
45     private double m_divisor;
46     
47     /**
48      * Create a new FisheyeTreeFilter that processes the given group.
49      * @param group the data group to process. This should resolve to
50      * a Graph instance, otherwise exceptions will result when this
51      * Action is run.
52      */

53     public FisheyeTreeFilter(String JavaDoc group) {
54         this(group, 1);
55     }
56
57     /**
58      * Create a new FisheyeTreeFilter that processes the given group.
59      * @param group the data group to process. This should resolve to
60      * a Graph instance, otherwise exceptions will result when this
61      * Action is run.
62      * @param distance the graph distance threshold from high-interest
63      * nodes past which nodes will not be visible nor expanded.
64      */

65     public FisheyeTreeFilter(String JavaDoc group, int distance) {
66         this(group, Visualization.FOCUS_ITEMS, distance);
67     }
68     
69     /**
70      * Create a new FisheyeTreeFilter that processes the given group.
71      * @param group the data group to process. This should resolve to
72      * a Graph instance, otherwise exceptions will result when this
73      * Action is run.
74      * @param sources the group to use as source nodes, representing the
75      * nodes of highest degree-of-interest.
76      * @param distance the graph distance threshold from high-interest
77      * nodes past which nodes will not be visible nor expanded.
78      */

79     public FisheyeTreeFilter(String JavaDoc group, String JavaDoc sources, int distance)
80     {
81         super(group);
82         m_sources = sources;
83         m_threshold = -distance;
84         m_groupP = new InGroupPredicate(
85                 PrefuseLib.getGroupName(group, Graph.NODES));
86     }
87     
88     /**
89      * Get the graph distance threshold used by this filter. This
90      * is the threshold for high-interest nodes, past which nodes will
91      * not be visible nor expanded.
92      * @return the graph distance threshold
93      */

94     public int getDistance() {
95         return -m_threshold;
96     }
97
98     /**
99      * Set the graph distance threshold used by this filter. This
100      * is the threshold for high-interest nodes, past which nodes will
101      * not be visible nor expanded.
102      * @param distance the graph distance threshold to use
103      */

104     public void setDistance(int distance) {
105         m_threshold = -distance;
106     }
107     
108     /**
109      * Get the name of the group to use as source nodes for measuring
110      * graph distance. These form the roots from which the graph distance
111      * is measured.
112      * @return the source data group
113      */

114     public String JavaDoc getSources() {
115         return m_sources;
116     }
117     
118     /**
119      * Set the name of the group to use as source nodes for measuring
120      * graph distance. These form the roots from which the graph distance
121      * is measured.
122      * @param sources the source data group
123      */

124     public void setSources(String JavaDoc sources) {
125         m_sources = sources;
126     }
127     
128     /**
129      * @see prefuse.action.GroupAction#run(double)
130      */

131     public void run(double frac) {
132         Tree tree = ((Graph)m_vis.getGroup(m_group)).getSpanningTree();
133         m_divisor = tree.getNodeCount();
134         m_root = (NodeItem)tree.getRoot();
135         
136         // mark the items
137
Iterator JavaDoc items = m_vis.visibleItems(m_group);
138         while ( items.hasNext() ) {
139             VisualItem item = (VisualItem)items.next();
140             item.setDOI(Constants.MINIMUM_DOI);
141             item.setExpanded(false);
142         }
143         
144         // compute the fisheye over nodes
145
Iterator JavaDoc iter = m_vis.items(m_sources, m_groupP);
146         while ( iter.hasNext() )
147             visitFocus((NodeItem)iter.next(), null);
148         visitFocus(m_root, null);
149
150         // mark unreached items
151
items = m_vis.visibleItems(m_group);
152         while ( items.hasNext() ) {
153             VisualItem item = (VisualItem)items.next();
154             if ( item.getDOI() == Constants.MINIMUM_DOI )
155                 PrefuseLib.updateVisible(item, false);
156         }
157     }
158
159     /**
160      * Visit a focus node.
161      */

162     private void visitFocus(NodeItem n, NodeItem c) {
163         if ( n.getDOI() <= -1 ) {
164             visit(n, c, 0, 0);
165             if ( m_threshold < 0 )
166                 visitDescendants(n, c);
167             visitAncestors(n);
168         }
169     }
170     
171     /**
172      * Visit a specific node and update its degree-of-interest.
173      */

174     private void visit(NodeItem n, NodeItem c, int doi, int ldist) {
175         PrefuseLib.updateVisible(n, true);
176         double localDOI = -ldist / Math.min(1000.0, m_divisor);
177         n.setDOI(doi+localDOI);
178         
179         if ( c != null ) {
180             EdgeItem e = (EdgeItem)c.getParentEdge();
181             e.setDOI(c.getDOI());
182             PrefuseLib.updateVisible(e, true);
183         }
184     }
185     
186     /**
187      * Visit tree ancestors and their other descendants.
188      */

189     private void visitAncestors(NodeItem n) {
190         if ( n == m_root ) return;
191         visitFocus((NodeItem)n.getParent(), n);
192     }
193     
194     /**
195      * Traverse tree descendents.
196      */

197     private void visitDescendants(NodeItem p, NodeItem skip) {
198         int lidx = ( skip == null ? 0 : p.getChildIndex(skip) );
199         
200         Iterator JavaDoc children = p.children();
201         
202         p.setExpanded(children.hasNext());
203         
204         for ( int i=0; children.hasNext(); ++i ) {
205             NodeItem c = (NodeItem)children.next();
206             if ( c == skip ) { continue; }
207             
208             int doi = (int)(p.getDOI()-1);
209             visit(c, c, doi, Math.abs(lidx-i));
210             if ( doi > m_threshold )
211                 visitDescendants(c, null);
212         }
213     }
214     
215 } // end of class FisheyeTreeFilter
216
Popular Tags