All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.data2viz.hierarchy.PartitionLayout.kt Maven / Gradle / Ivy

There is a newer version: 0.8.0-RC5
Show newest version
package io.data2viz.hierarchy

import io.data2viz.hierarchy.treemap.treemapDice


class PartitionLayout {

    var round = false
    private var dx = 1.0
    private var dy = 1.0
    var padding = .0

    /**
     * The partition layout produces adjacency diagrams: a space-filling variant of a node-link tree diagram.
     * Rather than drawing a link between parent and child in the hierarchy, nodes are drawn as solid areas
     * (either arcs or rectangles), and their placement relative to other nodes reveals their position in the hierarchy.
     * The size of the nodes encodes a quantitative dimension that would be difficult to show in a node-link diagram.
     *
     * Lays out the specified root hierarchy, assigning the following properties on root and its descendants:
     *  - node.x0 - the left edge of the rectangle
     *  - node.y0 - the top edge of the rectangle
     *  - node.x1 - the right edge of the rectangle
     *  - node.y1 - the bottom edge of the rectangle
     *
     *  You must call root.sum before passing the hierarchy to the partition layout.
     *  You probably also want to call root.sort to order the hierarchy before computing the layout.
     */
    fun  partition(root: Node): TreemapNode {

        // TODO check for sum called

        val rootNode = makeTreemap(root)

        val n = rootNode.height + 1
        rootNode.x0 = padding
        rootNode.y0 = padding
        rootNode.x1 = dx
        rootNode.y1 = dy / n
        rootNode.eachBefore(positionNode(dy, n))

        if (round) rootNode.eachBefore(::roundNode)

        return rootNode
    }

    private fun  positionNode(dy: Double, n: Int):((TreemapNode)->Unit) {
        return { node:TreemapNode ->
            if (node.children.isNotEmpty()) {
                treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
            }
            var x0 = node.x0
            var y0 = node.y0
            var x1 = node.x1 - padding
            var y1 = node.y1 - padding
            if (x1 < x0) {
                x0 = (x0 + x1) / 2
                x1 = x0
            }
            if (y1 < y0) {
                y0 = (y0 + y1) / 2
                y1 = y0
            }
            node.x0 = x0
            node.y0 = y0
            node.x1 = x1
            node.y1 = y1
        }
    }

    fun size(width: Double, height: Double) {
        dx = width
        dy = height
    }

    private fun  makeCluster(root: Node): ClusterNode {
        val rootCluster = ClusterNode(root.data, root.depth, root.height, root.value)
        val nodes = mutableListOf(root)
        val nodesC = mutableListOf(rootCluster)
        while (nodes.isNotEmpty()) {
            val node = nodes.removeAt(nodes.lastIndex)
            val nodeC = nodesC.removeAt(nodesC.lastIndex)
            node.children.forEach { child ->
                val c = ClusterNode(child.data, child.depth, child.height, child.value)
                c.parent = nodeC
                nodeC.children.add(c)
                nodes.add(child)
                nodesC.add(c)
            }
        }
        return rootCluster
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy