创建缩略图的正确方法是什么? [英] What is the right way to create thumbnail charts?

查看:160
本文介绍了创建缩略图的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 JScrollPane 创建一些数据的缩略图,但我遇到了性能问题。此示例包含大约100个缩略图,每个缩略图包含5000个样本。当我尝试向下滚动并多次向上滚动时,滚动发生延迟,CPU负载增加,应用程序内存使用量达到500 Mb以上。



是否有如何在不减少数据的情况下避免此性能问题?



  import java.awt.Color; 
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.Random;

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

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ThermometerPlot;
import org.jfree.data.general.DefaultValueDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

公共类ThumbnailChartsTest扩展JPanel {
private static final int W = 200;
private static final int H = W;
private static final int N = 5000;
private static final随机随机= new Random();

private static ChartPanel createPane(){
final XYSeries series = new XYSeries(Data);
for(int i = 0; i< random.nextInt(N)+ N; i ++){
series.add(i,random.nextGaussian());
}
XYSeriesCollection dataset = new XYSeriesCollection(series);

JFreeChart chart = ChartFactory.createXYLineChart(Random,Domain,
Range,数据集,PlotOrientation.VERTICAL,false,false,false);
返回新的ChartPanel(图表,W,H,W,H,W,H,
false,true,true,true,true,true);
}

public static void main(final String [] args){

EventQueue.invokeLater(new Runnable(){

@Override
public void run(){
JFrame f = new JFrame(Test);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel( );
panel.setLayout(new GridLayout(0,4));
for(int i = 0; i< 100; i ++){
panel.add(createPane());
}

JScrollPane scrollPane = new JScrollPane(面板,
JScrollPane.VERTICAL_SCROLLBAR_​​ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_​​NEVER);
f.add(scrollPane);

f.pack();
f.setVisible(true);
}
});

}
}

编辑:我无法理解一件事:为什么在这种情况下内存使用量仍然非常巨大!请看这个插图。





加法:
我认为存在一些误解。



堆大小通过监视器visualVM

启动applet堆大小后只有125 Mb,很酷。
然后我开始测试:多次滚动和调整大小,越来越多 - 上下,上下,更小的帧和更大的帧。堆积大小超过500 Mb!我认为这种情况不正常。



加法#2



Real -world示例:



我的数据大小只有2 Mb,用90个图表表示(每个2个系列),一个系列包含3000个元素。我已经通过滑块实现了更改数字列。



但这个小数据堆大小超过1.5 GB!





这在某些操作后发生,更改数字列,例如
对于我的CPU(核心2双核2.2GHz),每个绘图表需要大约4秒的时间!由于这个大延迟,很难控制滑块。



更新:



I已经实现了将我的数据下采样到每个缩略图的100个样本。
现在它肯定更快,但仍存在巨大堆大小的问题。在图片上,一个超过700Mb,这不是一个记录。我很沮丧。

解决方案

使用


启动applet后,它不大,小于200 Mb,但滚动后,调整大小等内存使用量达到600 Mb以上。为什么?


一个典型的

  import java.awt.Component; 
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

/ **
* @see https://stackoverflow.com/a/40445144/230513
* /
公共类ChartTable {

private static final Random R = new Random();
private static final int N = 5000;
private static final int W = 200;
private static final int H = W;

private void display(){
JFrame f = new JFrame(ChartTable);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultTableModel model = new DefaultTableModel(
new String [] {,,,},0){
@Override
public Class<?> ; getColumnClass(int columnIndex){
return ChartPanel.class;
}
};
for(int r = 0; r< 25; r ++){
ChartPanel [] row = new ChartPanel [4];
for(int c = 0; c< row.length; c ++){
final XYSeries series = new XYSeries(Data);
int n = R.nextInt(N);
for(int i = 0; i< n; i ++){
series.add(i,R.nextGaussian());
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
JFreeChart chart = ChartFactory.createXYLineChart(
Random+ series.getItemCount(),Domain,Range,dataset);
ChartPanel chartPanel = new ChartPanel(图表){
@Override
public Dimension getPreferredSize(){
return new Dimension(W,H);
}
};
row [c] = chartPanel;
}
model.addRow(row);
}
JTable table = new JTable(model){
@Override
public Dimension getPreferredScrollableViewportSize(){
return new Dimension(4 * W,2 * H) ;
}
};
table.setDefaultRenderer(ChartPanel.class,new ChartRenderer());
table.setRowHeight(W);
f.add(new JScrollPane(table));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}

私有静态类ChartRenderer实现TableCellRenderer {

@Override
public Component getTableCellRendererComponent(
JTable table,Object value,boolean isSelected ,
boolean hasFocus,int row,int column){
return(ChartPanel)value;
}
}

public static void main(String [] args){
EventQueue.invokeLater(new ChartTable():: display);
}
}


I'm trying to create a chart of thumbnails of some data with using JScrollPane, but I encounter performance difficulties. This example has about 100 thumbnails charts with 5000 samples in each one. When I'm trying to scroll down and back to up multiple times, scrolling occurs with delay, CPU load increasing, application memory usage reaches over 500 Mb.

Is there a way to avoid this performance problem without reducing my data?

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.Random;

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

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ThermometerPlot;
import org.jfree.data.general.DefaultValueDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class ThumbnailChartsTest extends JPanel {
private static final int W = 200;
private static final int H = W;
private static final int N = 5000;
private static final Random random = new Random();

private static ChartPanel createPane() {
    final XYSeries series = new XYSeries("Data");
    for (int i = 0; i < random.nextInt(N) + N; i++) {
        series.add(i, random.nextGaussian());
    }
    XYSeriesCollection dataset = new XYSeriesCollection(series);

    JFreeChart chart = ChartFactory.createXYLineChart("Random", "Domain",
        "Range", dataset, PlotOrientation.VERTICAL, false, false, false);
    return new ChartPanel(chart, W, H, W, H, W, H,
            false, true, true, true, true, true);
}

public static void main(final String[] args) {

    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            JFrame f = new JFrame("Test");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JPanel panel = new JPanel();
            panel.setLayout(new GridLayout(0, 4));
            for (int i=0; i<100; i++){
                panel.add(createPane());
            }

            JScrollPane scrollPane = new JScrollPane(panel,
                    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                    JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            f.add(scrollPane);

            f.pack();
            f.setVisible(true);
        }
    });

}
}

Edit: I can't understand one thing: Why in this case memory usage still very huge! Please look at this illustration.

Addition: I think there is some misunderstanding.

Heap size by monitor visualVM After starting applet heap size is only 125 Mb, it's cool. But then I'm starting testing: scrolling and resizing multiple times, more and more -- up and down, up and down, smaller frame and bigger frame. Heap size growing up over 500 Mb! I suppose this situation isn't normal.

Addition #2

Real-world example:

My data has size about only 2 Mb and represented in 90 charts(2 series in each one), one series contain 3000 elements. I've implemented changing number columns by slider.

But for this small data heap size growing up over 1.5 GB!

This happens after some actions, changing number columns e.g. For my CPU(core 2 duo 2.2GHz) every drawing table takes time about 4 sec! With this big delay it's hard to control slider.

update:

I've implemented downsampling my data to 100 samples per thumbnail chart. Now It's definitely faster, but problem with HUGE heap size still there. On the picture the one is above 700Mb, and it's not a record. I'm frustrated.

解决方案

Use the flyweight pattern to render only visible charts. The approach, used by JTable renderers, is outlined here and shown in the ChartRenderer seen below. For illustration, the dataset is recreated each time a cell is revealed; scroll, resize and switch applications to see the effect. While such rendering scales well into the tens of thousands of cells, each chart still renders N data points. You can limit the number of visible cells in the implementation of the Scrollable method, getPreferredScrollableViewportSize(), as shown below.

How to reduce memory usage to small values?

There is no general answer, but several strategies may prove helpful:

  • Compose charts as early in program initialization as possible, rather than at the time they are rendered; the updated example below constructs a TableModel of ChartPanel instances; the ChartRenderer is correspondingly simpler.

  • Charts having more than a few thousand points are effectively unreadable; consider truncating large datasets and displaying the full data only in response to a ListSelectionEvent, illustrated here.

  • Platform activity monitors may be misleading; profile to verify actual results.

After starting applet it's not big, less than 200 Mb, but after scrolling, resizing etc. memory usage reaches values more than 600 Mb. Why?

A typical profiler view of the code below shows only moderate usage and the expected free/used ratio after scrolling and garbage collection; your results may vary.

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

/**
 * @see https://stackoverflow.com/a/40445144/230513
 */
public class ChartTable {

    private static final Random R = new Random();
    private static final int N = 5000;
    private static final int W = 200;
    private static final int H = W;

    private void display() {
        JFrame f = new JFrame("ChartTable");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        DefaultTableModel model = new DefaultTableModel(
            new String[]{"", "", "", ""}, 0) {
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                return ChartPanel.class;
            }
        };
        for (int r = 0; r < 25; r++) {
            ChartPanel[] row = new ChartPanel[4];
            for (int c = 0; c < row.length; c++) {
                final XYSeries series = new XYSeries("Data");
                int n = R.nextInt(N);
                for (int i = 0; i < n; i++) {
                    series.add(i, R.nextGaussian());
                }
                XYSeriesCollection dataset = new XYSeriesCollection(series);
                JFreeChart chart = ChartFactory.createXYLineChart(
                    "Random " + series.getItemCount(), "Domain", "Range", dataset);
                ChartPanel chartPanel = new ChartPanel(chart) {
                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(W, H);
                    }
                };
                row[c] = chartPanel;
            }
            model.addRow(row);
        }
        JTable table = new JTable(model) {
            @Override
            public Dimension getPreferredScrollableViewportSize() {
                return new Dimension(4 * W, 2 * H);
            }
        };
        table.setDefaultRenderer(ChartPanel.class, new ChartRenderer());
        table.setRowHeight(W);
        f.add(new JScrollPane(table));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static class ChartRenderer implements TableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(
            JTable table, Object value, boolean isSelected,
            boolean hasFocus, int row, int column) {
            return (ChartPanel) value;
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new ChartTable()::display);
    }
}

这篇关于创建缩略图的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆