当前位置: 首页 > 知识库问答 >
问题:

使用JavaFX图表API绘制图表图像

谷梁迪
2023-03-14

我只想从JavaFX图表API生成一个图表图像。我不想显示应用程序窗口,也不想启动应用程序(如果没有必要)。

public class LineChartSample extends Application {
    private List<Integer> data;

    @Override public void start(Stage stage) {
        stage.setTitle("Line Chart Sample");
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        xAxis.setLabel("Month");       

        final LineChart<String,Number> lineChart = 
                new LineChart<String,Number>(xAxis,yAxis);

        lineChart.setTitle("Stock Monitoring, 2010");

        XYChart.Series series = new XYChart.Series();
        series.setName("My portfolio");

        series.getData().add(new XYChart.Data("Jan", 23));
        series.getData().add(new XYChart.Data("Feb", 14));        

        Scene scene  = new Scene(lineChart,800,600);
        lineChart.getData().add(series);

        WritableImage image = scene.snapshot(null);
        ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", chartFile);

        //stage.setScene(scene);
        //stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

   public setData(List<Integer> data) {this.data = data;}
}

在start方法内部,我实际上需要访问外部数据以构建系列数据,但是似乎没有办法从start方法访问外部数据,如果我将数据存储在成员变量data内部,则当开始叫做。我其实不在乎舞台和场景对象,只要图表图像可以渲染,我应该如何解决问题?我想建立一个可以用输入数据调用的API,用数据绘制图表,并返回文件。

public File toLineChart(List<Integer> data) {
...
}

共有2个答案

东方俊材
2023-03-14

从命令行:

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.chart.*;
import javafx.scene.Group;
import javafx.scene.image.WritableImage;
import javax.imageio.ImageIO;

public class PieChartSample extends Application {

    private static String[] arguments; 

    @Override public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Imported Fruits");
        stage.setWidth(500);
        stage.setHeight(500);

        ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();

//               
        final PieChart chart = new PieChart(pieChartData);
        chart.setTitle("Imported Fruits");
        for(int i = 0; i < arguments.length; i+=2)
        {
            System.out.println(arguments[i] + " " + arguments[i+1]);
            chart.getData().add(new PieChart.Data(arguments[i], Double.parseDouble(arguments[i+1])));
        }

        ((Group) scene.getRoot()).getChildren().add(chart);

        saveAsPng(scene);
        System.out.println("Done!");
        System.exit(0);
        //stage.setScene(scene);
        //stage.show();
    }

    public static void main(String[] args) {
        arguments = args;
        launch(args);
    }

    static void saveAsPng(Scene scene){
        try 
        {
            WritableImage image = scene.snapshot(null);

            File file = new File("tempPieChart.png");

            ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);
        } 
        catch (IOException ex) 
        {
            Logger.getLogger(PieChartSample.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
}

下一步:清理并构建您的程序。然后:在dist文件夹中找到jar文件,然后:将命令提示符导航到jar所在的dist文件夹。然后运行:java-jar-PieChartSample。罐装香蕉14橘子20葡萄15

结果:与您的样本位于同一文件夹中。jar文件

王骏
2023-03-14

您不需要显示阶段,但节点必须附加到场景。从快照的文档中

注意:为了使CSS和布局能够正常工作,节点必须是场景的一部分(场景可以附加到舞台,但不需要)。

修改场景的一个限制是,它必须发生在JavaFX应用程序线程上,前提是必须初始化JavaFX工具箱。

初始化可以通过扩展应用程序类来完成,其中启动方法将为您完成初始化,或者作为一种解决方法,您可以在Swing事件调度程序线程上创建一个新的JFXPanel实例。

如果您正在扩展Application,并且您在start方法中执行某些代码,则确保此代码将在JavaFX Application Thread上执行,否则您可以使用Platform.run稍后(...)块从不同的线程调用,以确保相同。

下面是一个可能的例子:

类提供了一个静态方法来将图表绘制到文件中,如果创建成功或不成功,则返回Filenull

在这个方法中,JavaFX Toolkit通过在Swing EDT上创建一个JFXPanel来初始化,然后完成图表创建JavaFX Application Thread。方法中使用两个布尔值来存储操作已经完成和成功。

在完成标志切换为true之前,该方法不会返回。

注意:这只是一个(有效的)例子,可以改进很多。

public class JavaFXPlotter {

    public static File toLineChart(String title, String seriesName, List<Integer> times, List<Integer> data) {

        File chartFile = new File("D:\\charttest.png");

        // results: {completed, successful}
        Boolean[] results = new Boolean[] { false, false };

        SwingUtilities.invokeLater(() -> {

            // Initialize FX Toolkit
            new JFXPanel();

            Platform.runLater(() -> {
                final NumberAxis xAxis = new NumberAxis();
                final NumberAxis yAxis = new NumberAxis();

                final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);

                lineChart.setTitle(title);

                XYChart.Series<Number, Number> series = new XYChart.Series<>();
                series.setName(seriesName);

                for (int i = 0; i < times.size(); i++)
                    series.getData().add(new XYChart.Data<Number, Number>(times.get(i), data.get(i)));

                lineChart.getData().add(series);

                Scene scene = new Scene(lineChart, 800, 600);

                WritableImage image = scene.snapshot(null);

                try {
                    ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", chartFile);
                    results[1] = true;
                } catch (Exception e) {
                    results[0] = true;
                } finally {
                    results[0] = true;
                }
            });
        });

        while (!results[0]) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return (results[1]) ? chartFile : null;
    }


}

以及可能的用法

List<Integer> times = Arrays.asList(new Integer[] { 0, 1, 2, 3, 4, 5 });
List<Integer> data = Arrays.asList(new Integer[] { 4, 1, 5, 3, 0, 7 });

File lineChart = JavaFXPlotter.toLineChart("Sample", "Some sample data", times, data);

if (lineChart != null)
    System.out.println("Image generation is done! Path: " + lineChart.getAbsolutePath());
else
    System.out.println("File creation failed!");

System.exit(0);

以及生成的图片(charttest.png)

 类似资料:
  • 问题内容: 如果它是单独的JSON文件,如何检索和使用Google图表数据集?我尝试了jQuery getJSON,但无法正常工作。Google Viz应该使用JSON绘制条形图有本地的Google API方法吗?还是可以找到一种使用jQuery的方法以及如何使用?谢谢 问题答案: 作品。 查找的输出以使用正确的结构。 因此,如果服务器上有一个getjson.php脚本返回正确格式的json,则可

  • 问题内容: 如何在JSF中的网页中绘制动态图?人们建议Google Chart Api 我想要可以离线工作的东西 问题答案: 嘿,我在搜寻网后找到了问题的答案。Apache myFaces有一个tr:chart组件可以解决我的问题:)

  • 安装方法 pip install matplotlib 绘制一元函数图像y=ax+b 创建single_variable.py,内容如下: # coding:utf-8 import sys reload(sys) sys.setdefaultencoding( "utf-8" ) import matplotlib.pyplot as plt import numpy as np plt.f

  • 问题内容: 我正在尝试使用Java的Graphics2D在屏幕上绘制图像。这是我正在使用的代码。我想看到图像在屏幕上稳定移动。目前,我可以看到图像,但是除非调整窗口大小,否则图像不会移动,在这种情况下,图像确实会移动。我已经勾勒出以下课程。 传递给Tester的Component对象是以下类: 我确保此类仅添加了一个精灵。Sprite类大致如下: 但是,我在屏幕上仅看到固定的Bowser图像。除非

  • 我不能把我的头围绕轴参数,它包含什么以及如何使用它来制作子情节。 如果有人能解释一下下面的例子,我将不胜感激 更具体地说,以下是我理解的部分(至少我认为我理解) plt。子图返回一个元组,该元组包含图形和轴对象(链接) enumerate()返回一个元组,其中包含功能的索引及其名称(链接) df。绘图使用列名将数据放在图中的子绘图上 这是我不明白的 轴对象包含什么?同样,基于留档和这个答案,我意识

  • 我的程序有问题。我想在提供数据后绘制图表(方程的系数)。 我会得到greaftul的帮助。 当我删除上面的@fxml注释并编译代码时,我得到了以下错误: 另外,我将onaction=“drawchart”更改为onaction=“chart”,现在我可以看到高亮显示的通信:“不能将javafx.scene.control.LineChart设置为chart”