java - recursive method to draw a dendrogram -
i have draw dendrogram :
but bigger. there option representation of data clustering. stuck recursive method draw dendrogram.
i principle draw method should like
draw(cluster){ if(clusters.haschildren()){ draw(cluster.child1) draw(cluster.child2) } //draw actual cluster here }
but quite stuck @ implementing it.
my method @ moment looks this
drawcluster(cluster, startx, starty){ if(cluster.haschildren()){ drawcluster, cluster.child1(), cluster.child1().getdepth * 30, height - cluster.child2.getwidth * 20) drawcluster, cluster.child2(), cluster.child2().getdepth * 30, height - 20) } if cluster.getdepth() == 0 ) drawline(500 - 30), height, 500) else drawline(500 - (width * 30), height, 500); }
so space have drawing 500 px in width , height total_number_of_leafs * 20 draw line each cluster distances correct. every time start line @ 500px minus depth of cluster times 20.and draw line 500th pixel.
also height supposed maxheight. example when come draw lets cluster (1,2) height in argument 40. , on.
but not working well. stuck on how change values every time call draw method. need pass more variable other x start of line , y?
any appreciated since have deadline catch.
thanks in advance.
painting dendrogram recursively bit tricky.
the leaf nodes not "know" y-position. additionally, no node "directly" know has painted, , how lines should painted connect children: information not available before leaves (or children of each node, respectively) have been painted.
i think iterative solution easier , more flexible. however, here implementation using recursive approach. note simple implementation, (for example) assumes data structure dendrogram binary tree, should in line example posted.
btw: fills available space, , i'd strongly recommend avoid "magic constants" , assumptions pixel size of nodes or painting area in drawline(500 - (width * 30), height, 500)
. if not want compute these size of tree , number of leaf nodes, should at least introduce variables can change more later.
import java.awt.graphics; import java.awt.graphics2d; import java.awt.point; import java.util.arraylist; import java.util.collections; import java.util.list; import javax.swing.jframe; import javax.swing.jpanel; import javax.swing.swingutilities; public class dendrogrampainttest { public static void main(string[] args) { swingutilities.invokelater(new runnable() { @override public void run() { createandshowgui(); } }); } private static void createandshowgui() { jframe f = new jframe(); f.setdefaultcloseoperation(jframe.exit_on_close); dendrogrampaintpanel panel = new dendrogrampaintpanel(); f.getcontentpane().add(panel); f.setsize(1000,800); f.setlocationrelativeto(null); f.setvisible(true); } } class node<t> { private final t contents; private final list<node<t>> children; node(t contents) { this.contents = contents; this.children = collections.emptylist(); } node(node<t> child0, node<t> child1) { this.contents = null; list<node<t>> list = new arraylist<node<t>>(); list.add(child0); list.add(child1); this.children = collections.unmodifiablelist(list); } public t getcontents() { return contents; } public list<node<t>> getchildren() { return collections.unmodifiablelist(children); } } class dendrogrampaintpanel extends jpanel { private static <t> node<t> create(t contents) { return new node<t>(contents); } private static <t> node<t> create(node<t> child0, node<t> child1) { return new node<t>(child0, child1); } private node<string> root; private int leaves; private int levels; private int heightperleaf; private int widthperlevel; private int currenty; private final int margin = 25; dendrogrampaintpanel() { root = create( create( create("10"), create( create("9"), create( create("8"), create("7") ) ) ), create( create( create("6"), create("5") ), create( create("4"), create( create("3"), create( create("2"), create("1") ) ) ) ) ); } private static <t> int countleaves(node<t> node) { list<node<t>> children = node.getchildren(); if (children.size() == 0) { return 1; } node<t> child0 = children.get(0); node<t> child1 = children.get(1); return countleaves(child0) + countleaves(child1); } private static <t> int countlevels(node<t> node) { list<node<t>> children = node.getchildren(); if (children.size() == 0) { return 1; } node<t> child0 = children.get(0); node<t> child1 = children.get(1); return 1+math.max(countlevels(child0), countlevels(child1)); } @override protected void paintcomponent(graphics gr) { super.paintcomponent(gr); graphics2d g = (graphics2d)gr; leaves = countleaves(root); levels = countlevels(root); heightperleaf = (getheight() - margin - margin) / leaves; widthperlevel = (getwidth() - margin - margin)/ levels; currenty = 0; g.translate(margin, margin); draw(g, root, 0); } private <t> point draw(graphics g, node<t> node, int y) { list<node<t>> children = node.getchildren(); if (children.size() == 0) { int x = getwidth() - widthperlevel - 2 * margin; g.drawstring(string.valueof(node.getcontents()), x+8, currenty+8); int resultx = x; int resulty = currenty; currenty += heightperleaf; return new point(resultx, resulty); } if (children.size() >= 2) { node<t> child0 = children.get(0); node<t> child1 = children.get(1); point p0 = draw(g, child0, y); point p1 = draw(g, child1, y+heightperleaf); g.fillrect(p0.x-2, p0.y-2, 4, 4); g.fillrect(p1.x-2, p1.y-2, 4, 4); int dx = widthperlevel; int vx = math.min(p0.x-dx, p1.x-dx); g.drawline(vx, p0.y, p0.x, p0.y); g.drawline(vx, p1.y, p1.x, p1.y); g.drawline(vx, p0.y, vx, p1.y); point p = new point(vx, p0.y+(p1.y - p0.y)/2); return p; } // should never happen return new point(); } }
Comments
Post a Comment