2013-10-09 34 views
3

當嘗試構建包含可更新的LineChartAreaChart的應用程序時,我發現奇怪的行爲 - 可能是由於應用程序邏輯中的錯誤?x軸上的JavaFX LineChart/AreaChart排序值錯誤(CategoryAxis)

目標是當單擊按鈕「生成」時填入數據或更新圖表。用戶必須輸入圖表的開始時間和結束時間,此外還必須選擇一個時間間隔/天/周(通過使用RadioGroup)。

創建初始圖表沒有任何問題。重新生成圖表也能正常工作,但只要數據點在前面的圖表中不存在即可。如果兩個圖表(舊的和更新的)都包含具有相同x值的數據點,則排序不再上升。

實施例:

執行與 開始日期:2013年1月9日 結束日期:2013年9月25日 間隔:周

在x軸上的值:

2013年9月1日/ 2013年9月8日/ 15.09.2013/22.09.2013

單擊「天數」RadioButton重新生成圖表得出x軸上的以下值:

2013年9月1日/ 2013年8月9日/ 2013年9月15日/ 2013年9月22日/ 2013年2月9日/ 2013年3月9日/ 2013年4月9日/ ...

(值應該是2013年9月1日/ 2013年2月9日/ 2013年3月9日/ ...)

這已經在第一張圖顯示出,並在第二個圖表太所有值,在新圖表的開始進行排序(而不是按升序排列)

這裏的(initializeTimeline方法的代碼僅用於測試目的(當然可以優化;))):

public class ChartDesignController implements Initializable { 
@FXML 
private AreaChart chartOne; 
@FXML 
private TextField startDate; 
@FXML 
private TextField endDate; 
@FXML 
private RadioButton radioHours; 
@FXML 
private RadioButton radioDays; 
@FXML 
private RadioButton radioWeeks; 
@FXML 
private ToggleGroup timeUnit; 
@FXML 
private Label msgBox; 

@FXML 
private void generateGraph(ActionEvent event) { 
    String timeUnit = getTimeUnit(); 
    Series s = initializeTimeline(startDate.getText(), endDate.getText(), timeUnit); 
    chartOne.getData().setAll(s); 
} 

private String getTimeUnit() { 
    String timeUnitForQuery = "DD"; 
    RadioButton selectedRadio = (RadioButton) timeUnit.getSelectedToggle(); 
    if (selectedRadio == radioHours) { 
     //System.out.println("RadioHours was selected"); 
     timeUnitForQuery = "HH24"; 
    } 
    if (selectedRadio == radioDays) { 
     //System.out.println("RadioDays was selected"); 
     timeUnitForQuery = "DD"; 
    } 
    if (selectedRadio == radioWeeks) { 
     //System.out.println("RadioWeeks was selected"); 
     timeUnitForQuery = "IW"; 
    } 
    //System.out.println("Time unit changed"); 
    return timeUnitForQuery; 
} 

@Override 
public void initialize(URL url, ResourceBundle rb) { 
} 

private Series initializeTimeline(String startTime, String endTime, String timeUnit) { 
    msgBox.setText(""); 
    long delta; 
    int nrOfTicks = 0; 
    Data<String, Integer> dp; 
    Series s = new Series(); 
    ArrayList<Data<String, Integer>> dataPoints = new ArrayList(); 
    SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy"); 
    Date startDate = new Date(); 
    Date endDate = new Date(); 
    GregorianCalendar startTimeGC = new GregorianCalendar(); 
    GregorianCalendar endTimeGC = new GregorianCalendar(); 
    if (timeUnit.equalsIgnoreCase("HH24")) { 
     sdf = new SimpleDateFormat("dd.MM.yyyy HH"); 
    } 
    try { 
     startDate = sdf.parse(startTime); 
     endDate = sdf.parse(endTime); 
    } catch (ParseException ex) { 
     msgBox.setText(ex.getMessage() + "\n" + "Format expected: " + sdf.toPattern()); 
    } 
    startTimeGC.setTimeInMillis(startDate.getTime()); 
    endTimeGC.setTimeInMillis(endDate.getTime()); 
    delta = endTimeGC.getTimeInMillis() - startTimeGC.getTimeInMillis(); 
    if (timeUnit.equalsIgnoreCase("HH24")) { 
     nrOfTicks = (int) (delta/1000/60/60) + 1; 
    } else if (timeUnit.equalsIgnoreCase("DD")) { 
     nrOfTicks = (int) (delta/1000/60/60/24) + 1; 
    } else if (timeUnit.equalsIgnoreCase("IW")) { 
     nrOfTicks = (int) (delta/1000/60/60/24/7) + 1; 
    } 
    for (int i = 0; i < nrOfTicks; i++) { 
     dp = new Data(sdf.format(startTimeGC.getTime()), 0); 
     dataPoints.add(dp); 
     if (timeUnit.equalsIgnoreCase("HH24")) { 
      startTimeGC.add(GregorianCalendar.HOUR_OF_DAY, 1); 
     } else if (timeUnit.equalsIgnoreCase("DD")) { 
      startTimeGC.add(GregorianCalendar.DAY_OF_MONTH, 1); 
     } else if (timeUnit.equalsIgnoreCase("IW")) { 
      startTimeGC.add(GregorianCalendar.WEEK_OF_YEAR, 1);; 
     } 
    } 
    dataPoints.sort(new DataComparator()); 
    s.setData(FXCollections.observableList(dataPoints)); 
    return s; 
} 
} 

下面,DataComparator它負責排序dataPoints的字母順序根據其x值:

public class DataComparator implements Comparator<Data> { 
@Override 
public int compare(Data d1, Data d2) { 
    String d1Xval = (String) d1.getXValue(); 
    String d2Xval = (String) d2.getXValue(); 
    return d1Xval.compareTo(d2Xval); 
    } 
} 

當調試程序值在ArrayListdataPoints正確排序。

任何想法爲什麼價值排序不正確,然後在圖表X軸,以防他們已經出現在舊圖表?

將非常感謝幫助這個「問題」。

+0

答案你有沒有發現這方面的任何解決方案? – AloneInTheDark

回答

3

我只想說,我得到(幾乎)與線圖相同的問題!

我從數據庫中加載一些數據以顯示在折線圖中。數據僅表示一個月的總和。

當我加載數據「USER1」一切都看起來不錯: Chart 1 with clear data.

但是,當我與我的第二個用戶加載數據,它看起來像這樣: Chart 2 with strange data.

我真的不能弄清楚爲什麼會這樣,是因爲我而從數據庫中選擇這樣的數據進行排序:

...NTING.CUSTOMER = '"+Customer+"' GROUP BY MONTH ORDER BY MONTH ASC; 

所以......這就是我能說的......我對數據進行排序,而它取從數據庫,對於一個用戶它的工作,對於另一個它不!它真的讓我大失所望!

我剛剛在有人推薦下載JRE和JDK 8的「Early Access Version」的地方發現了一篇文章 - 但在我看來,我不會推薦這種高效系統!

希望任何人都能得到解決這個難題的解決方案!

就在任何人都憤怒之前,這不是答案 - 我知道!

但我認爲收集儘可能多的信息似乎也是解決方案的一部分。

由於(有時奇怪的特權 - stackoverflow偏好)我不能評論,直到我得到了更高的聲譽值!

我不想問一個新問題,而這已經在這裏討論了!

希望這是好的...

電賀

+0

你能找到這個奇怪的bug的解決方案嗎? – AloneInTheDark

+0

我發現somethig很奇怪,如果你將categoryaxis改爲自定義值(例如「hello」+ i),那麼你的數據總是排序爲true。 – AloneInTheDark

4

我有同樣的問題。無論我如何設置繪圖,通過用新數據點重新繪製,排序總是會變得混亂。唯一的解決方法是使用java 1.8。

這是最新的fx,2.2.51-b13。必須使用fx8早期訪問版本。

2

我也遇到過類似的問題與線型圖試圖添加日期點和調試時我想通了什麼:

我添加了一個系列的對象,其containes 3日分ObservableList:
2014年1月1日,
02.01.2014,
02.02.2014
和y軸的兩倍。

(到目前爲止,折線圖顯示爲應該)。

在此之後,我添加了與日期點的第二個系列對象:
01.01.2014,
02.01.2014,
03.02.2014。

又一次:折線圖起作用。

如果我先添加系列的對象,我的線型圖將顯示X軸值如下:
2014年1月1日
2014年2月1日
2014年3月2日
02.02。 2014
以錯誤的順序破壞我的線圖。

在路上試圖找到一個解決方案,我想出了一個「處理方法」:
添加含有可觀察名單有助於將在稍後使用其他系列的對象爲第一系列Object的所有日期值Series對象。
可以「隱藏」的「平均值」或這樣的,但 我不與它真的很高興,雖然,但它的作品的方式在這裏顯示圖表以正確的順序至少

我的第一篇文章,只是試圖幫助至少得到一個解決方案,因爲我登陸這裏尋找同樣的問題。

+0

我只添加一個系列對象,如果點數增加,則更有可能破壞折線圖。當你選擇一個日期時,我有一個組合框,它清除了系列並重新加載了新值。當我嘗試加載系列超過2次時,值被錯誤地排序。我真的不知道有什麼問題... – AloneInTheDark

+0

檢查下面的答案。 – AloneInTheDark

+0

@AloneInTheDark感謝您的臨時解決方案。也許我嘗試過的方式,可能會幫助其他人(淹死)的線圖。 – KnusperPudding

0

我發現了一個「臨時」解決方案。

series.getData().add(new BarChart.Data<>(rs.getString(1)+" "+i,rs.getDouble(2))); 

添加一個i變量,它與數據增加,從而防止數據被破壞。

另一種解決方案是使用JDK 8

0

這是一種解決方法,每次重新創建整個圖形,它不是最乾淨的方式,但它的作品。之前的系列添加到圖表,只需要調用 graph.getData().clear()然後graph.layout();,得到了 Recreate bar chart without it remembering data