[英]JUNG - Large graph visualization
我目前正在開發一種使用圖和Java JUNG圖可視化庫來可視化宏基因組學數據的工具。
當顯示大約1000個節點時,我會遇到一個延遲,這是通過移動攝像機或拖動某些節點來實現的。
有沒有可以用來改善這種情況的技巧? 我讀了一些關於將窗口分為幾部分的內容,並且只適用於正在顯示的面板的一部分,但是我不明白這一點。
謝謝。
該問題可能被認為過於籠統,因為優化的自由度太多了。 如果不是重復的話,那么至少存在一些相關的問題( 改進JUNG圖的呈現 , JUNG無法顯示大圖?或其他)。
但是,我會在這里嘗試回答:
通常,使用JUNG,您可以輕松地並用幾行代碼來創建一個具有令人印象深刻的默認功能(交互)和許多功能的漂亮圖形。 在這方面,JUNG並非主要針對繪制具有1000個頂點的圖形。 相反,它的目的是很好地繪制具有數十個(或幾百個)頂點和邊的圖形。
(實際上,從理論上以信息可視化的角度來看,繪制具有> 1000個頂點的圖形幾乎毫無意義。至少,如果沒有過度的縮放和平移,您將無法從圖形中直觀地提取任何信息。 )
當您要繪制具有許多頂點和許多邊的圖形時,可以使用一些選項來提高性能。 (您沒有說出邊的數量。在很多情況下,這是最昂貴的東西!)。
根據我的經驗,提高渲染性能的最重要的事情就是...
嚴重的是,這確實很昂貴。 在榮格,這可以做到
visualizationViewer.getRenderingHints().remove(
RenderingHints.KEY_ANTIALIASING)
除此之外,還有許多提高性能的選項,但是,當然,它們全都取決於您要犧牲哪種視覺功能。 下面的示例顯示了一個具有2500個頂點和5000個邊的圖形。 默認情況下,它非常慢。 improvePerformance
方法包含有關如何使可視化速度更快的幾個選項。 即使僅禁用抗鋸齒功能,在我的機器(速度較慢)上,性能還是可以接受的。
根據評論進行編輯/擴展:
import java.awt.Dimension;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.apache.commons.collections15.Predicate;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.Context;
import edu.uci.ics.jung.graph.util.Pair;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.EdgeShape;
import edu.uci.ics.jung.visualization.renderers.BasicEdgeRenderer;
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
public class JungPerformance
{
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);
Graph<String, String> g = createGraph();
Dimension size = new Dimension(800,800);
VisualizationViewer<String, String> vv =
new VisualizationViewer<String, String>(
new FRLayout<String, String>(g, size));
DefaultModalGraphMouse<String, Double> graphMouse =
new DefaultModalGraphMouse<String, Double>();
vv.setGraphMouse(graphMouse);
improvePerformance(vv);
f.getContentPane().add(vv);
f.setSize(size);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// This method summarizes several options for improving the painting
// performance. Enable or disable them depending on which visual features
// you want to sacrifice for the higher performance.
private static <V, E> void improvePerformance(
VisualizationViewer<V, E> vv)
{
// Probably the most important step for the pure rendering performance:
// Disable anti-aliasing
vv.getRenderingHints().remove(RenderingHints.KEY_ANTIALIASING);
// Skip vertices that are not inside the visible area.
doNotPaintInvisibleVertices(vv);
// May be helpful for performance in general, but not appropriate
// when there are multiple edges between a pair of nodes: Draw
// the edges not as curves, but as straight lines:
vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line<V,E>());
// May be helpful for painting performance: Omit the arrow heads
// of directed edges
Predicate<Context<Graph<V, E>, E>> edgeArrowPredicate =
new Predicate<Context<Graph<V,E>,E>>()
{
@Override
public boolean evaluate(Context<Graph<V, E>, E> arg0)
{
return false;
}
};
vv.getRenderContext().setEdgeArrowPredicate(edgeArrowPredicate);
}
// Skip all vertices that are not in the visible area.
// NOTE: See notes at the end of this method!
private static <V, E> void doNotPaintInvisibleVertices(
VisualizationViewer<V, E> vv)
{
Predicate<Context<Graph<V, E>, V>> vertexIncludePredicate =
new Predicate<Context<Graph<V,E>,V>>()
{
Dimension size = new Dimension();
@Override
public boolean evaluate(Context<Graph<V, E>, V> c)
{
vv.getSize(size);
Point2D point = vv.getGraphLayout().transform(c.element);
Point2D transformed =
vv.getRenderContext().getMultiLayerTransformer()
.transform(point);
if (transformed.getX() < 0 || transformed.getX() > size.width)
{
return false;
}
if (transformed.getY() < 0 || transformed.getY() > size.height)
{
return false;
}
return true;
}
};
vv.getRenderContext().setVertexIncludePredicate(vertexIncludePredicate);
// NOTE: By default, edges will NOT be included in the visualization
// when ONE of their vertices is NOT included in the visualization.
// This may look a bit odd when zooming and panning over the graph.
// Calling the following method will cause the edges to be skipped
// ONLY when BOTH their vertices are NOT included in the visualization,
// which may look nicer and more intuitive
doPaintEdgesAtLeastOneVertexIsVisible(vv);
}
// See note at end of "doNotPaintInvisibleVertices"
private static <V, E> void doPaintEdgesAtLeastOneVertexIsVisible(
VisualizationViewer<V, E> vv)
{
vv.getRenderer().setEdgeRenderer(new BasicEdgeRenderer<V, E>()
{
@Override
public void paintEdge(RenderContext<V,E> rc, Layout<V, E> layout, E e)
{
GraphicsDecorator g2d = rc.getGraphicsContext();
Graph<V,E> graph = layout.getGraph();
if (!rc.getEdgeIncludePredicate().evaluate(
Context.<Graph<V,E>,E>getInstance(graph,e)))
return;
Pair<V> endpoints = graph.getEndpoints(e);
V v1 = endpoints.getFirst();
V v2 = endpoints.getSecond();
if (!rc.getVertexIncludePredicate().evaluate(
Context.<Graph<V,E>,V>getInstance(graph,v1)) &&
!rc.getVertexIncludePredicate().evaluate(
Context.<Graph<V,E>,V>getInstance(graph,v2)))
return;
Stroke new_stroke = rc.getEdgeStrokeTransformer().transform(e);
Stroke old_stroke = g2d.getStroke();
if (new_stroke != null)
g2d.setStroke(new_stroke);
drawSimpleEdge(rc, layout, e);
// restore paint and stroke
if (new_stroke != null)
g2d.setStroke(old_stroke);
}
});
}
public static Graph<String, String> createGraph()
{
Random random = new Random(0);
int numVertices = 2500;
int numEdges = 5000;
Graph<String, String> g = new DirectedSparseGraph<String, String>();
for (int i=0; i<numVertices; i++)
{
g.addVertex("v"+i);
}
for (int i=0; i<numEdges; i++)
{
int v0 = random.nextInt(numVertices);
int v1 = random.nextInt(numVertices);
g.addEdge("e"+i, "v"+v0, "v"+v1);
}
return g;
}
}
@ Marco13的答案很好。 我將補充(作為JUNG的作者之一),JUNG當前在可視化縮放方面的主要缺陷是缺乏良好的空間數據結構。 結果,對於較大的圖形,力導向布局和交互式可視化都可能非常慢。
在某個時候,我們將解決這個問題(歡迎補丁:))。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.