在演示JavaFX 2.0圖表API之前,第一個代碼清單顯示了示例中要使用的數據的配置。 在更現實的情況下,我將從數據存儲中獲取此數據,但是在這種情況下,我只是直接將其直接包含在源代碼中,以方便示例訪問。 盡管此代碼本身與JavaFX 2.0圖表并沒有內在的聯系,但還是有一些有趣的事情。 該代碼在數字文字中使用了Java 7的下劃線,從而使讀取數據中使用的樣本狀態的地域大小和總體更加容易。 該代碼清單還使用了Guava的ImmutableMap類(在上一篇文章中介紹了 )。
配置示例數據的代碼
/** Simple U.S. state representation. */private enum State{ALASKA("Alaska"),CALIFORNIA("California"),COLORADO("Colorado"),NEW_YORK("New York"),RHODE_ISLAND("Rhode Island"),TEXAS("Texas"),WYOMING("Wyoming");private String stateName;State(final String newStateName){this.stateName = newStateName;}}/** Simple Movie representation. */private enum Movie{STAR_WARS("Star Wars"),EMPIRE_STRIKES_BACK("The Empire Strikes Back"),RAIDERS_OF_THE_LOST_ARK("Raiders of the Lost Ark"),INCEPTION("Inception"),CHRISTMAS_VACATION("Christmas Vacation"),CHRISTMAS_VACATION_2("Christmas Vacation 2"),FLETCH("Fletch");private String movieName;Movie(final String newMovieName){this.movieName = newMovieName;}}/** Mapping of state name to area of state measured in kilometers. */private final static Map<String, Long> statesLandSizeKm;/** Mapping of state name to estimated number of people living in that state. */private final static Map<String, Long> statesPopulation;/** Normal audience movie ratings on Rotten Tomatoes. */private final static Map<String, Double> movieRatingsNormal;/** Critics movie ratings on Rotten Tomatoes. */private final static Map<String, Double> movieRatingsCritics;/** Dustin's movie ratings. */private final static Map<String, Double> movieRatingsDustin;/** Maximum population to be shown on bar charts of states' populations. */private final static long POPULATION_RANGE_MAXIMUM = 40_000_000L;/** Maximum land area (km) to be shown on bar charts of states' land areas. */private final static long LAND_AREA_KM_MAXIMUM = 1_800_000L;/** Maximum movie rating to be shown on bar charts. */private final static double MOVIE_RATING_MAXIMUM = 10.0;/** Width of chart. */private final static int CHART_WIDTH = 750;/** Height of chart. */private final static int CHART_HEIGHT = 600;/** Width of chart for Movie Ratings. */private final static int MOVIE_CHART_WIDTH = CHART_WIDTH + 350;/* Initialize final static variables. */static{statesLandSizeKm =ImmutableMap.<String, Long>builder().put(State.ALASKA.stateName, 1_717_854L).put(State.CALIFORNIA.stateName, 423_970L).put(State.COLORADO.stateName, 269_601L).put(State.NEW_YORK.stateName, 141_299L).put(State.RHODE_ISLAND.stateName, 4_002L).put(State.TEXAS.stateName, 695_621L).put(State.WYOMING.stateName, 253_336L).build();statesPopulation =ImmutableMap.<String, Long>builder().put(State.ALASKA.stateName, 722_718L).put(State.CALIFORNIA.stateName, 37_691_912L).put(State.COLORADO.stateName, 5_116_769L).put(State.NEW_YORK.stateName, 19_465_197L).put(State.RHODE_ISLAND.stateName, 1_051_302L).put(State.TEXAS.stateName, 25_674_681L).put(State.WYOMING.stateName, 568_158L).build();movieRatingsNormal =ImmutableMap.<String, Double>builder().put(Movie.CHRISTMAS_VACATION.movieName, 8.3).put(Movie.CHRISTMAS_VACATION_2.movieName, 1.3).put(Movie.STAR_WARS.movieName, 9.3).put(Movie.EMPIRE_STRIKES_BACK.movieName, 9.4).put(Movie.RAIDERS_OF_THE_LOST_ARK.movieName, 9.3).put(Movie.INCEPTION.movieName, 9.3).put(Movie.FLETCH.movieName, 7.8).build();movieRatingsCritics =ImmutableMap.<String, Double>builder().put(Movie.CHRISTMAS_VACATION.movieName, 6.3).put(Movie.CHRISTMAS_VACATION_2.movieName, 0.0).put(Movie.STAR_WARS.movieName, 9.4).put(Movie.EMPIRE_STRIKES_BACK.movieName, 9.7).put(Movie.RAIDERS_OF_THE_LOST_ARK.movieName, 9.4).put(Movie.INCEPTION.movieName, 8.6).put(Movie.FLETCH.movieName, 7.5).build();movieRatingsDustin =ImmutableMap.<String, Double>builder().put(Movie.CHRISTMAS_VACATION.movieName, 7.0).put(Movie.CHRISTMAS_VACATION_2.movieName, 0.0).put(Movie.STAR_WARS.movieName, 9.5).put(Movie.EMPIRE_STRIKES_BACK.movieName, 10.0).put(Movie.RAIDERS_OF_THE_LOST_ARK.movieName, 10.0).put(Movie.INCEPTION.movieName, 9.0).put(Movie.FLETCH.movieName, 9.0).build(); }
下一個代碼清單演示了示例應用程序的引導。 這包括通常啟動Java應用程序的單行主函數,以及從擴展Application類中重寫的更有趣的start(String [])方法。 此代碼清單還利用Java 7的Strings-on-Strings功能對命令行參數解析進行了快速而又骯臟的實現,以運行特定的圖表生成演示。 該示例演示了傳遞給Application.launch(String ...)的命令行參數可通過Application.getParameters()方法返回給嵌套的Application.Parameters實例的JavaFX應用程序使用。
啟動JavaFX 2.0圖表演示示例的代碼
/*** Start JavaFX application.* * @param stage First stage of JavaFX application.* @throws Exception */@Overridepublic void start(final Stage stage) throws Exception{final Parameters parameters = getParameters(); // command-line argsfinal List<String> args = parameters.getUnnamed();final String firstArgument = !args.isEmpty() ? args.get(0) : "1";final int chartWidth = !firstArgument.equals("4") ? CHART_WIDTH : MOVIE_CHART_WIDTH;stage.setTitle("Building Bar Charts");final Group rootGroup = new Group();final Scene scene = new Scene(rootGroup, chartWidth, CHART_HEIGHT, Color.WHITE);stage.setScene(scene);switch (firstArgument){case "1" :rootGroup.getChildren().add(buildVerticalLandAreaBarChart());break;case "2" :rootGroup.getChildren().add(buildVerticalPopulationBarChart());break;case "3" :rootGroup.getChildren().add(buildHorizontalPopulationBarChart());break;case "4" :rootGroup.getChildren().add(buildVerticalMovieRatingsBarChart());break;case "5" :rootGroup.getChildren().add(buildStatesLandSizePopulationScatterChart());break;default :rootGroup.getChildren().add(buildVerticalLandAreaBarChart());}stage.show();}/*** Main function for demonstrating JavaFX 2.0 bar chart and scatter chart.* * @param arguments Command-line arguments: none expected.*/public static void main(final String[] arguments){Application.launch(arguments);}
通過配置了用于填充圖表的數據并演示了基本的JavaFX應用程序引導,現在該開始研究實際JavaFX 2.0圖表API的使用了。 如上面的代碼所示,第一個選項(“ 1”)導致生成垂直條形圖,該條形圖以公里為單位描述了樣本州的相對土地面積。 接下來顯示該示例執行的方法。
生成州土地面積的垂直條形圖
/*** Build ObservableList of XYChart.Series instances mapping state names to* land areas.* * @return ObservableList of XYChart.Series instances mapping state names to* land areas.*/public ObservableList<XYChart.Series<String,Long>> buildStatesToLandArea(){final ObservableList<XYChart.Data<String,Long>> statesToLandArea =FXCollections.observableArrayList();for (final State state : State.values()){final XYChart.Data<String,Long> stateAreaData =new XYChart.Data<String,Long>(state.stateName, statesLandSizeKm.get(state.stateName));statesToLandArea.add(stateAreaData);}final XYChart.Series<String, Long> landSeries =new XYChart.Series<String, Long>(statesToLandArea);final ObservableList<XYChart.Series<String, Long>> series =FXCollections.observableArrayList();landSeries.setName("State Land Size (km)");series.add(landSeries);return series;}/*** Provides a CategoryAxis instantiated with sample states' names.** @return CategoryAxis with sample states' names.*/public CategoryAxis buildStatesNamesCategoriesAxis(){final ObservableList<String> stateNames = FXCollections.observableArrayList();stateNames.addAll(State.ALASKA.stateName,State.CALIFORNIA.stateName,State.COLORADO.stateName,State.NEW_YORK.stateName,State.RHODE_ISLAND.stateName,State.TEXAS.stateName,State.WYOMING.stateName);final CategoryAxis categoryAxis = new CategoryAxis(stateNames);categoryAxis.setLabel("State");categoryAxis.setMinWidth(CHART_WIDTH);return categoryAxis;}/*** Build vertical bar chart comparing land areas of sample states.* * @return Vertical bar chart comparing land areas of sample states.*/public XYChart buildVerticalLandAreaBarChart(){final ValueAxis landAreaAxis = new NumberAxis(0, LAND_AREA_KM_MAXIMUM, 50_000);final BarChart landAreaBarChart =new BarChart(buildStatesNamesCategoriesAxis(), landAreaAxis, buildStatesToLandArea());landAreaBarChart.setMinWidth(CHART_WIDTH);landAreaBarChart.setMinHeight(CHART_HEIGHT);landAreaBarChart.setTitle("Land Area (in km) of Select U.S. States");return landAreaBarChart;}
上面的代碼片段顯示了我用于生成條形圖的三種方法。 在底部的方法,buildVerticalLandAreaBarChart(),實例化NumberAxis圖表的y軸,并使用該實施ValueAxis在實例化一個條形圖 。 BarChart實例化調用代碼片段中的其他兩個方法來創建帶有狀態名稱的x軸,并準備ObservableList <XYChart.Series <String,Long >>格式的數據以用于圖表生成。 生成的圖表如下所示。

相似的代碼可以生成用于描述樣本狀態總體的相似圖表。 接下來顯示執行此操作的代碼,然后是生成的圖表的屏幕快照。
使用州人口生成垂直條形圖
// method buildStatesNamesCategoriesAxis() was shown in previous code listing/*** Build one or more series of XYChart Data representing state names as 'x'* portion and state populations as 'y' portion. This method is likely to be* used in vertical presentations where state names are desired on the x-axis* and population numbers are desired on the y-axis.* * @return Series of XYChar Data representing state names as 'x' portion and* state populations as 'y' portion.*/public ObservableList<XYChart.Series<String,Long>> buildStatesToPopulation(){final ObservableList<XYChart.Data<String,Long>> statesToPopulation =FXCollections.observableArrayList();for (final State state : State.values()){final XYChart.Data<String,Long> statePopulationData =new XYChart.Data<String,Long>(state.stateName, statesPopulation.get(state.stateName));statesToPopulation.add(statePopulationData);}final XYChart.Series<String, Long> populationSeries =new XYChart.Series<String, Long>(statesToPopulation);final ObservableList<XYChart.Series<String, Long>> series =FXCollections.observableArrayList();populationSeries.setName("State Population");series.add(populationSeries);return series;}/*** Build vertical bar chart comparing populations of sample states.** @return Vertical bar chart comparing populations of sample states.*/public XYChart buildVerticalPopulationBarChart(){final ValueAxis populationAxis = new NumberAxis(0, POPULATION_RANGE_MAXIMUM, 2_000_000);final BarChart populationBarChart =new BarChart(buildStatesNamesCategoriesAxis(), populationAxis, buildStatesToPopulation());populationBarChart.setMinWidth(CHART_WIDTH);populationBarChart.setMinHeight(CHART_HEIGHT);populationBarChart.setTitle("Population of Select U.S. States");return populationBarChart;}

前兩個圖是垂直圖。 下一個示例對其樣本數據使用與上一個示例相同的狀態填充,但是使用水平條形圖而不是垂直圖進行描述。 請注意,使用與前兩個示例相同的方法來生成帶有狀態名稱的軸,但是其結果作為第二個參數傳遞給BarChart構造函數,而不是第一個參數。 BarChart構造函數的順序更改將圖表從垂直更改為水平。 換句話說,在BarChart構造函數中,將CategoryAxis作為第一個參數,將ValueAxis作為第二個參數將導致一個垂直圖表。 切換這兩種類型的Axis的順序會產生一個水平圖。 我還必須切換要繪制的數據的映射順序,以便關鍵部分是填充,而值部分是狀態名稱。 該代碼后跟輸出。
用州人口生成水平條形圖
// method buildStatesNamesCategoriesAxis() was shown in previous code listings/*** Build one or more series of XYChart Data representing population as 'x'* portion and state names as 'y' portion. This method is likely to be used* in horizontal presentations where state names are desired on the y-axis* and population numbers are desired on the x-axis.* * @return Series of XYChar Data representing population as 'x' portion and* state names as 'y' portion.*/public ObservableList<XYChart.Series<Long,String>> buildPopulationToStates(){final ObservableList<XYChart.Data<Long,String>> statesToPopulation =FXCollections.observableArrayList();for (final State state : State.values()){final XYChart.Data<Long,String> statePopulationData =new XYChart.Data<Long,String>(statesPopulation.get(state.stateName), state.stateName);statesToPopulation.add(statePopulationData);}final XYChart.Series<Long, String> populationSeries =new XYChart.Series<Long, String>(statesToPopulation);final ObservableList<XYChart.Series<Long, String>> series =FXCollections.observableArrayList();populationSeries.setName("State Population");series.add(populationSeries);return series;}/*** Build horizontal bar chart comparing populations of sample states.* * @return Horizontal bar chart comparing populations of sample states.*/public XYChart buildHorizontalPopulationBarChart(){final ValueAxis populationAxis = new NumberAxis(0, POPULATION_RANGE_MAXIMUM, 2_000_000);final BarChart populationBarChart =new BarChart(populationAxis, buildStatesNamesCategoriesAxis(), buildPopulationToStates());populationBarChart.setMinWidth(CHART_WIDTH);populationBarChart.setTitle("Population of Select U.S. States");return populationBarChart;}

對于生成條形圖的所有這些示例,我都使用了JavaFX的XYChart 。 事實證明ScatterChart也擴展了XYChart ,因此其用法與BarChart相似。 這種情況( ScatterChart )的最大區別是將存在兩個面向值的軸。 換句話說,每個軸將基于值(x軸的土地面積和y軸的人口數)而不是使用x軸(垂直)或y軸(水平)的州名。 這些類型的圖表通常用于直觀地確定數據之間的相關程度。 接下來顯示生成此代碼的代碼及其生成的輸出。
生成州人口到州土地面積散布圖
/*** Build mapping of land area to population for each state.* * @return Mapping of land area to population for each sample state.*/public ObservableList<XYChart.Series<Long,Long>> buildAreaToPopulation(){final ObservableList<XYChart.Data<Long,Long>> areaToPopulation =FXCollections.observableArrayList();for (final State state : State.values()){final XYChart.Data<Long,Long> areaPopulationData =new XYChart.Data<Long,Long>(statesLandSizeKm.get(state.stateName),statesPopulation.get(state.stateName));areaToPopulation.add(areaPopulationData);}final XYChart.Series<Long, Long> areaPopulationSeries =new XYChart.Series<Long, Long>(areaToPopulation);final ObservableList<XYChart.Series<Long, Long>> series =FXCollections.observableArrayList();areaPopulationSeries.setName("State Land Area and Population");series.add(areaPopulationSeries);return series;}/*** Build a Scatter Chart depicting correlation between land area and population* for each state.* * @return Scatter Chart depicting correlation between land area and population* for each state.*/public XYChart buildStatesLandSizePopulationScatterChart(){final ValueAxis xAxis = new NumberAxis(0, LAND_AREA_KM_MAXIMUM, 50_000);xAxis.setLabel("Land Area (km)");final ValueAxis yAxis = new NumberAxis(0, POPULATION_RANGE_MAXIMUM, 2_000_000);yAxis.setLabel("Population");final ScatterChart xyChart = new ScatterChart(xAxis, yAxis, buildAreaToPopulation());xyChart.setMinHeight(CHART_HEIGHT);return xyChart;}

散點圖有助于直觀地確定一個州的土地面積與其人口之間是否存在任何關聯。 部分是因為阿拉斯加和懷俄明州被包括在樣本狀態集中,所以沒有太多的相關性。 設置JavaFX散點圖樣式還有很多工作要做。
有時在同一條形圖上看到多個序列是很有用的。 為了說明同一條形圖中的多個系列,我將更改所使用的相同數據。 我將不使用狀態及其大小和總體的數據,而是使用原始代碼清單中與電影等級相關的數據。 特別是這里有三個系列:評論家的評分,“正常”聽眾的評分和我自己的評分。 與前面的示例一樣,我首先顯示代碼(最有趣的部分是buildRatingsToMovieTitle()方法) ,然后是輸出。
生成具有多個系列的電影分級條形圖(多個分級組)
/*** Build one or more series of XYChart Data representing movie names as 'x'* portion and movie ratings as 'y' portion. This method is likely to be* used in vertical presentations where movie names are desired on the x-axis* and movie ratings are desired on the y-axis. This method illustrates* multiple series as ratings for both normal audience members and critics* are shown.* * @return Series of XYChar Data representing state movie names as 'x' portion* and movie ratings as 'y' portion.*/public ObservableList<XYChart.Series<String,Double>> buildRatingsToMovieTitle(){final ObservableList<XYChart.Data<String,Double>> normalRatings =FXCollections.observableArrayList();final ObservableList<XYChart.Data<String,Double>> criticRatings =FXCollections.observableArrayList();final ObservableList<XYChart.Data<String,Double>> dustinRatings =FXCollections.observableArrayList();for (final Movie movie : Movie.values()){final XYChart.Data<String,Double> normalRatingsData =new XYChart.Data<String,Double>(movie.movieName, movieRatingsNormal.get(movie.movieName));normalRatings.add(normalRatingsData);final XYChart.Data<String,Double> criticRatingsData =new XYChart.Data<String,Double>(movie.movieName, movieRatingsCritics.get(movie.movieName));criticRatings.add(criticRatingsData);final XYChart.Data<String,Double> dustinRatingsData =new XYChart.Data<String,Double>(movie.movieName, movieRatingsDustin.get(movie.movieName));dustinRatings.add(dustinRatingsData);}final XYChart.Series<String, Double> normalSeries =new XYChart.Series<String, Double>(normalRatings);normalSeries.setName("Normal Audience");final XYChart.Series<String, Double> criticSeries =new XYChart.Series<String, Double>(criticRatings);criticSeries.setName("Critics");final XYChart.Series<String, Double> dustinSeries =new XYChart.Series<String, Double>(dustinRatings);dustinSeries.setName("Dustin");final ObservableList<XYChart.Series<String, Double>> series =FXCollections.observableArrayList();series.add(normalSeries);series.add(criticSeries);series.add(dustinSeries);return series;} /*** Build vertical bar chart comparing movie ratings to demonstrate multiple* series used in a single chart.* * @return Vertical bar chart comparing movie ratings.*/public XYChart buildVerticalMovieRatingsBarChart(){final ValueAxis ratingAxis = new NumberAxis(0, MOVIE_RATING_MAXIMUM, 1.0);final BarChart ratingBarChart =new BarChart(buildMovieRatingsAxis(), ratingAxis, buildRatingsToMovieTitle());ratingBarChart.setMinWidth(MOVIE_CHART_WIDTH);ratingBarChart.setMinHeight(CHART_HEIGHT);ratingBarChart.setTitle("Movie Ratings");return ratingBarChart;}

JavaFX 2.1 beta版包含幾個新圖表,包括StackedBarChart 。 堆疊的條形圖表示多個序列,因此我將調整最后一個示例以使用其中的一個。 堆疊的條形圖將顯示三個評級源中的每一個,每個電影貢獻一個條形,而不像上一個示例那樣,每個電影三個條形。
生成電影分級的StackedBarChart
/*** Build one or more series of XYChart Data representing movie names as 'x'* portion and movie ratings as 'y' portion. This method is likely to be* used in vertical presentations where movie names are desired on the x-axis* and movie ratings are desired on the y-axis. This method illustrates* multiple series as ratings for both normal audience members and critics* are shown.* * @return Series of XYChar Data representing state movie names as 'x' portion* and movie ratings as 'y' portion.*/public ObservableList<XYChart.Series<String,Double>> buildRatingsToMovieTitle(){final ObservableList<XYChart.Data<String,Double>> normalRatings =FXCollections.observableArrayList();final ObservableList<XYChart.Data<String,Double>> criticRatings =FXCollections.observableArrayList();final ObservableList<XYChart.Data<String,Double>> dustinRatings =FXCollections.observableArrayList();for (final Movie movie : Movie.values()){final XYChart.Data<String,Double> normalRatingsData =new XYChart.Data<String,Double>(movie.movieName, movieRatingsNormal.get(movie.movieName));normalRatings.add(normalRatingsData);final XYChart.Data<String,Double> criticRatingsData =new XYChart.Data<String,Double>(movie.movieName, movieRatingsCritics.get(movie.movieName));criticRatings.add(criticRatingsData);final XYChart.Data<String,Double> dustinRatingsData =new XYChart.Data<String,Double>(movie.movieName, movieRatingsDustin.get(movie.movieName));dustinRatings.add(dustinRatingsData);}final XYChart.Series<String, Double> normalSeries =new XYChart.Series<String, Double>(normalRatings);normalSeries.setName("Normal Audience");final XYChart.Series<String, Double> criticSeries =new XYChart.Series<String, Double>(criticRatings);criticSeries.setName("Critics");final XYChart.Series<String, Double> dustinSeries =new XYChart.Series<String, Double>(dustinRatings);dustinSeries.setName("Dustin");final ObservableList<XYChart.Series<String, Double>> series =FXCollections.observableArrayList();series.add(normalSeries);series.add(criticSeries);series.add(dustinSeries);return series;} /*** Build a Stacked Bar Chart depicting total ratings of each movie based on* contributions of three ratings groups.* * @return Stacked Bar Chart depicting three rating groups' contributions* to overall movie rating.*/public XYChart buildStackedMovieRatingsBarChart(){final ValueAxis ratingAxis = new NumberAxis(0, MOVIE_RATING_MAXIMUM*3, 2.5);final StackedBarChart ratingBarChart =new StackedBarChart(buildMovieRatingsAxis(), ratingAxis, buildRatingsToMovieTitle());ratingBarChart.setMinWidth(MOVIE_CHART_WIDTH);ratingBarChart.setMinHeight(CHART_HEIGHT);ratingBarChart.setTitle("Movie Ratings");return ratingBarChart;}

堆疊的條形圖很有用,因為它可以快速查看每部電影的總體綜合評分以及每個評論者組對該總評分的貢獻。
JavaFX 2.0圖表文檔
“ 使用JavaFX圖表”教程涵蓋各種JavaFX 2.0圖表類型(例如餅圖 , 折線圖 , 面積圖 , 氣泡圖 , 散點圖和條形圖)的代碼示例和相應的生成的圖表圖像。 本教程還提供了有關使用CSS設置圖表樣式的部分,以及有關準備圖表數據和生成自定義圖表的信息。
結論
這篇文章演示了如何使用JavaFX圖表包生成條形圖,散點圖和堆積條形圖。 當JavaFX被接受為Java SE SDK的標準部分時,它將為SDK帶來用于生成Java圖表的標準機制。
參考:來自JCG合作伙伴的 JavaFX 2.0條形圖和散點圖(以及JavaFX 2.1 StackedBarCharts) ? 實際事件啟發博客中的達斯汀·馬克思。
翻譯自: https://www.javacodegeeks.com/2012/02/javafx-20-bar-and-scatter-charts-and.html