Как применить пользовательский макет в графике JUNG?

У меня есть следующие три набора целых чисел, как следующие:

set0 = {1} //this will always be a singleton set.
set1 = {2, 3, 4, 5}
set2 = {6, 7}

У меня есть граф, у которого есть ребра, которые либо от set1 до set2 ИЛИ от set2 до set3, таким образом формируя четкую древовидную иерархию вершин.

 Set0 -- Set1  -- Set2

Чтобы отобразить этот древовидный график, я создал DelegateForest а также TreeLayout

package Test;

import java.util.HashSet;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.JPanel;

import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.TreeLayout;
import edu.uci.ics.jung.graph.DelegateForest;
import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;

class Main{
    public static void main(String[] args){

    Set<Integer> set0 = new HashSet<Integer>();
    Set<Integer> set1 = new HashSet<Integer>();
    Set<Integer> set2 = new HashSet<Integer>();

    set0.add(1);

    set1.add(2);
    set1.add(3);
    set1.add(4);
    set1.add(5);

    set2.add(6);
    set2.add(7);

    JFrame frame = new JFrame();
    frame.add(createGraphPanel(set0, set1, set2));
    frame.pack();
    frame.setVisible(true);


    }

    private static JPanel createGraphPanel( Set<Integer> setZero, Set<Integer> firstSet, Set<Integer> secondSet) {
            // create a graph
            Graph<Integer, String> graph = new DelegateForest<Integer, String>();

                Integer vertex1 = setZero.iterator().next();
            for (Integer i : firstSet) {
                graph.addEdge(vertex1+"-"+i, vertex1, i);
            }

            Layout<Integer, String> layout = new TreeLayout<Integer, String>((Forest<Integer, String>) graph);
            VisualizationViewer<Integer, String> vv = new  VisualizationViewer<Integer,String>(layout);

            vv.getRenderContext().setVertexLabelTransformer(
                    new ToStringLabeller<Integer>());

            return vv;
        }
    }

Тем не менее, график, который я получил (в настоящее время содержит только set1 и set2) выглядит следующим образом

Я хотел бы сделать пару вещей с этим графиком:

  1. Вместо того, чтобы узлы текли сверху вниз, я бы хотел, чтобы они текли слева направо. (Что-то вроде поворота на 90 градусов)
  2. В настоящее время алгоритм компоновки гарантирует отсутствие перекрытия, что расширяет узлы для set2 линейным образом. Если set2 огромен, он выходит за пределы панели. Я не против перекрытия и хотел бы, чтобы эти узлы выглядели близко друг к другу как кластер с частичным перекрытием.

Как я могу достичь двух требований?

2 ответа

Решение

Я расширил класс TreeLayout и поменял местами все переменные x / y. Это должно отобразить дерево горизонтально. Однако вам нужно будет добавить собственный код, чтобы предотвратить размещение вершин в строке (возможно, используйте ограничивающий прямоугольник и начинайте сверху, как только вы пройдете мимо него).

public class HorizontalOverlappingTreeLayout<V, E> extends TreeLayout<V, E> {

    public static void main(String[] args) {
        Set<Integer> set0 = new HashSet<Integer>();
        Set<Integer> set1 = new HashSet<Integer>();
        Set<Integer> set2 = new HashSet<Integer>();
        set0.add(1);
        set1.add(2);
        set1.add(3);
        set1.add(4);
        set1.add(5);
        set2.add(6);
        set2.add(7);

        JPanel panel = new JPanel();
        Graph<Integer, String> graph = new DelegateForest<Integer, String>();
        Integer vertex1 = set0.iterator().next();
        for (Integer i : set1) {
            graph.addEdge(vertex1 + "-" + i, vertex1, i);
        }

        Layout<Integer, String> layout = new HorizontalOverlappingTreeLayout<Integer, String>(
                (Forest<Integer, String>) graph);
        VisualizationViewer<Integer, String> vv = new VisualizationViewer<Integer, String>(layout);
        vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Integer>());
        panel.add(vv);

        JFrame frame = new JFrame();
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }

    public HorizontalOverlappingTreeLayout(Forest<V, E> g) {
        super(g);
    }

    @Override
    protected void buildTree() {
        this.m_currentPoint = new Point(0, 20);
        Collection<V> roots = TreeUtils.getRoots(graph);
        if (roots.size() > 0 && graph != null) {
            calculateDimensionY(roots);
            for (V v : roots) {
                calculateDimensionY(v);
                m_currentPoint.y += this.basePositions.get(v) / 2 + this.distY;
                buildTree(v, this.m_currentPoint.y);
            }
        }
        // TODO: removed code here
    }

    @Override
    protected void buildTree(V v, int y) {
        if (!alreadyDone.contains(v)) {
            alreadyDone.add(v);

            // go one level further down
            this.m_currentPoint.x += this.distX;
            this.m_currentPoint.y = y;

            this.setCurrentPositionFor(v);

            int sizeYofCurrent = basePositions.get(v);

            int lastY = y - sizeYofCurrent / 2;

            int sizeYofChild;
            int startYofChild;

            for (V element : graph.getSuccessors(v)) {
                sizeYofChild = this.basePositions.get(element);
                startYofChild = lastY + sizeYofChild / 2;
                buildTree(element, startYofChild);
                lastY = lastY + sizeYofChild + distY;
            }
            this.m_currentPoint.x -= this.distX;
        }
    }

    private int calculateDimensionY(V v) {
        int size = 0;
        int childrenNum = graph.getSuccessors(v).size();

        if (childrenNum != 0) {
            for (V element : graph.getSuccessors(v)) {
                size += calculateDimensionY(element) + distY;
            }
        }
        size = Math.max(0, size - distY);
        basePositions.put(v, size);

        return size;
    }

    private int calculateDimensionY(Collection<V> roots) {
        int size = 0;
        for (V v : roots) {
            int childrenNum = graph.getSuccessors(v).size();

            if (childrenNum != 0) {
                for (V element : graph.getSuccessors(v)) {
                    size += calculateDimensionY(element) + distY;
                }
            }
            size = Math.max(0, size - distY);
            basePositions.put(v, size);
        }

        return size;
    }

}

Чтобы ответить на проблему (1): есть демо (L2RTreeLayoutDemo), которое делает это.

Чтобы ответить на задачу (2): измените интервал x и / или y в макете; это устанавливается в конструкторе.

Другие вопросы по тегам