1. 먼저 XChart 라이브러리를 다운받아서 설치해야 합니다. (다음 글에 내용이 있으니 참고바랍니다.)

2020/03/02 - [자바] - 자바 XChart 를 이용해 자바 차트 그래프 만들기


2. 간단한 Java 실시간 Java 차트 예제

실시간 차트 작성은 XYChart 인스턴스를 통해 하나 이상의 시리즈 오브젝트에 대해 updateXYSeries를 호출하고 차트를 포함하는 JPanel의 다시 그리기를 트리거하는 것만 큼 간단합니다. 예제는 여기에 표시된 repaintChart () 메소드와 함께 SwingWrapper와 revalidate () 및 repaint ()가있는 XChartPanel을 사용하는 방법을 보여줍니다. XChartPanel을 통합하는 자체 Java Swing 애플리케이션이 이미있는 경우에 사용하려고합니다.



import org.knowm.xchart.QuickChart;

import org.knowm.xchart.SwingWrapper;

import org.knowm.xchart.XYChart;

 

/**

* Creates a simple real-time chart

*/

public class SimpleRealTime {

 

  public static void main(String[] args) throws Exception {

 

    double phase = 0;

    double[][] initdata = getSineData(phase);

 

    // Create Chart

    final XYChart chart = QuickChart.getChart("Simple XChart Real-time Demo", "Radians", "Sine", "sine", initdata[0], initdata[1]);

 

    // Show it

    final SwingWrapper<XYChart> sw = new SwingWrapper<XYChart>(chart);

    sw.displayChart();

 

    while (true) {

 

      phase += 2 * Math.PI * 2 / 20.0;

 

      Thread.sleep(100);

 

      final double[][] data = getSineData(phase);

 

      chart.updateXYSeries("sine", data[0], data[1], null);

      sw.repaintChart();

    }

 

  }

 

  private static double[][] getSineData(double phase) {

 

    double[] xData = new double[100];

    double[] yData = new double[100];

    for (int i = 0; i < xData.length; i++) {

      double radians = phase + (2 * Math.PI / xData.length * i);

      xData[i] = radians;

      yData[i] = Math.sin(radians);

    }

    return new double[][] { xData, yData };

  }

}


2. Swing Worker Java 실시간 Java 차트 예제

위의 예에서 차트 데이터 생성은 EventDispatchThread에서 실행되며 반응 형 GUI에는 적합하지 않습니다. 또한 EventDispatchThread는 실시간 차트를 업데이트 할 때마다 100ms 동안 휴면 상태가됩니다. Java Swing 애플리케이션을 빌드하는 올바른 방법과는 거리가 멀지 만 XChart 컴포넌트의 작동 방식을 보여주기위한 목적으로 사용됩니다.

이 예에서는 EventDispatchThread 대신 추가 스레드를 사용하여 데이터 생성을 수행 할 수 있습니다. 이 모범 사례 기술을 사용하면 차트를 백그라운드에서 다시 그리는 시간을 제외하고 차트가 백그라운드에서 진행되는 동안 GUI가 사용자 상호 작용에 응답 할 수 있습니다. SwingWorker 스레드는 EventDispatchThread에서 실행되는 GUI를 업데이트 할 때 복잡한 세부 정보를 처리하는 특수 스레드입니다.

이 예제는 실시간 차트 응용 프로그램을 만드는 일반적인 시나리오를 시뮬레이션합니다. 센서에서 데이터를 읽는 일부 백그라운드 스레드가 있으며 새 데이터를 사용할 수있게되면 라이브 차트를 업데이트하려고합니다. 그러나 때때로 데이터가 얼마나 자주 업데이트되는지 알 수 없습니다. 한 가지 문제는 데이터를 차트를 다시 그리려는 것보다 빠르게 진행되고 있다는 것입니다. 예를 들어 데이터 속도가 화면 새로 고침 빈도보다 빠른 경우 (예 : 초당 24 포인트) 새 단일 데이터 포인트마다 차트를 업데이트하는 것은 의미가 없습니다. 따라서이 예제에서는 동적으로 계산 된 데이터 포인트 당 5ms의 데이터 속도와 초당 24 프레임의 차트 업데이트 속도를 시뮬레이션합니다. 차트 애니메이션이 매끄럽게 보이고 아무런 이유없이 차트를 업데이트하는 데 추가 CPU주기가 낭비되지 않습니다.


import java.util.LinkedList;

import java.util.List;


import javax.swing.SwingWorker;


import org.knowm.xchart.QuickChart;

import org.knowm.xchart.SwingWrapper;

import org.knowm.xchart.XYChart;


/**

 * Creates a real-time chart using SwingWorker

 */

public class SwingWorkerRealTime {


  MySwingWorker mySwingWorker;

  SwingWrapper<XYChart> sw;

  XYChart chart;


  public static void main(String[] args) throws Exception {


    SwingWorkerRealTime swingWorkerRealTime = new SwingWorkerRealTime();

    swingWorkerRealTime.go();

  }


  private void go() {


    // Create Chart

    chart = QuickChart.getChart("SwingWorker XChart Real-time Demo", "Time", "Value", "randomWalk", new double[] { 0 }, new double[] { 0 });

    chart.getStyler().setLegendVisible(false);

    chart.getStyler().setXAxisTicksVisible(false);


    // Show it

    sw = new SwingWrapper<XYChart>(chart);

    sw.displayChart();


    mySwingWorker = new MySwingWorker();

    mySwingWorker.execute();

  }


  private class MySwingWorker extends SwingWorker<Boolean, double[]> {


    LinkedList<Double> fifo = new LinkedList<Double>();


    public MySwingWorker() {


      fifo.add(0.0);

    }


    @Override

    protected Boolean doInBackground() throws Exception {


      while (!isCancelled()) {


        fifo.add(fifo.get(fifo.size() - 1) + Math.random() - .5);

        if (fifo.size() > 500) {

          fifo.removeFirst();

        }


        double[] array = new double[fifo.size()];

        for (int i = 0; i < fifo.size(); i++) {

          array[i] = fifo.get(i);

        }

        publish(array);


        try {

          Thread.sleep(5);

        } catch (InterruptedException e) {

          // eat it. caught when interrupt is called

          System.out.println("MySwingWorker shut down.");

        }


      }


      return true;

    }


    @Override

    protected void process(List<double[]> chunks) {


      System.out.println("number of chunks: " + chunks.size());


      double[] mostRecentDataSet = chunks.get(chunks.size() - 1);


      chart.updateXYSeries("randomWalk", null, mostRecentDataSet, null);

      sw.repaintChart();


      long start = System.currentTimeMillis();

      long duration = System.currentTimeMillis() - start;

      try {

        Thread.sleep(40 - duration); // 40 ms ==> 25fps

        // Thread.sleep(400 - duration); // 40 ms ==> 2.5fps

      } catch (InterruptedException e) {

      }


    }

  }

}




+ Recent posts