2013-08-02 11 views
5

Stosując wykresy JavaFX, potrzebuję odwrócić oś y ułożonego wykresu warstwowego tak, aby dodatnie zero znajdowało się na górze, a dodatnie liczby na osi y. Poniżej znajduje się makieta tego, co próbuję osiągnąć.Wykres z odwróconą osią y

Inverted Y-Axis with positive numbers

Jaki jest najlepszy (czytaj: najkrótszy czas projektowania i wysoką code-ponowne) sposobem osiągnięcia tego celu w JavaFX?

UPDATE

Konwersja danych do liczb ujemnych nie jest rozwiązaniem. Szukam odpowiedzi, które będą działać z liczbami dodatnimi, "nietknięte".

Odpowiedz

2

Możesz użyć zwykłej osi z wartościami ujemnymi, ale dodaj TickLabelFormatter, która będzie usuwać znak minus.

final NumberAxis yAxis = new NumberAxis(-25, 0, 5); 

    yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) { 
     @Override 
     public String toString(Number value) { 
      // note we are printing minus value 
      return String.format("%7.1f", -value.doubleValue()); 
     } 
    }); 

    series1.getData().add(new XYChart.Data("Jan", -1)); 
    series1.getData().add(new XYChart.Data("Feb", -5)); 
    series1.getData().add(new XYChart.Data("Mar", -20)); 
+0

Sugerujesz, że przekonwertuję wszystkie moje dane na liczby ujemne przed użyciem ich na wykresach? – mawcsco

+0

tak. Nie jest to najlepszy sposób, ale znacznie szybszy niż rozszerzanie wykresu o funkcję inwersji. Aby uniknąć bezpośredniej aktualizacji danych, możesz rozszerzyć klasę 'XYChart.Data' o logikę inwersji lub wprowadzić metodę narzędzia, która doda do wykresu odwrócone liczby. –

0

Nie łatwym rozwiązaniem jest umożliwienie inverse() operację na osiach. Bez łatania klas JRE jest to dość skomplikowane.

Kilka wskazówek, w jaki sposób podejść do tego:

1) przedłużyć ValueAxis lub Axis (NumberAxis jest ostateczna niestety)

2) dodać pole logiczną i inverse() metody do klasy osi

public void inverse() { 
    inversed = !inversed; // boolean property 
    invalidateRange(); 
    requestAxisLayout(); 
} 

3) jeśli rozszerzysz ValueAxis - będziesz musiał skompensować przesunięcie zastosowane przez nadklasę (i przechwycić kod, w którym zmienia się rozmiar osi)

@Override 
public Long getValueForDisplay(double displayPosition) { 
    if (inversed) 
     return super.getValueForDisplay(offset - displayPosition); 
    else 
     return super.getValueForDisplay(displayPosition); 
} 

@Override 
public double getDisplayPosition(Long value) { 
    if (inversed) 
     return offset - super.getDisplayPosition(value); 
    else 
     return super.getDisplayPosition(value); 
} 

4) (najbrzydszy kawałek) odznacz ukryte znaczniki stłumione przez klasę Osi - oryginalna implementacja zależy od domyślnej kolejności znaczników. Nie znalazłem żadnego innego sposobu, który odblokowałby poprzez odbicie. Jest to bardzo kruche.

@Override 
protected void layoutChildren() { 
    final Side side = getSide(); 
    boolean isHorisontal = null == side || side.isHorizontal(); 
    this.offset = isHorisontal ? getWidth() : getHeight(); 
    super.layoutChildren(); 
    if (inversed) { 
     double prevEnd = isHorisontal ? offset + getTickLabelGap() : 0; 
     for (TickMark m : getTickMarks()) { 
      double position = m.getPosition(); 
      try { 
       final Text textNode = (Text) textNodeField.get(m); 
       final Bounds bounds = textNode.getLayoutBounds(); 
       if (0 <= position && position <= offset) 
        if (isHorisontal) { 
         textNode.setVisible(position < prevEnd); 
         prevEnd = position - (bounds.getWidth() + getTickLabelGap()); 
        } else { 
         textNode.setVisible(position > prevEnd); 
         prevEnd = position + (bounds.getHeight() + getTickLabelGap()); 
        } 
      } catch (IllegalAccessException ignored) { 
      } 
     } 
    } 
} 

Oś Y jest odwrócony w tym przykładzie this is how it looks like

0

wykorzystanie właściwości dolne i górne granice osi. The lowerBound musi być wyższy niż upperBound. Oto, jak możesz zrobić to za pomocą fxml:

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<HBox   
    prefHeight="600.0" 
    prefWidth="800.0" 
    xmlns:fx="http://javafx.com/fxml/1">  

    <javafx.scene.chart.LineChart 
     fx:id="chart" > 
     <xAxis > 
      <javafx.scene.chart.NumberAxis 
       label="X Axis" 
       lowerBound="0.01" 
       upperBound="100" 
       tickUnit="10" 
       autoRanging="false" /> 
     </xAxis> 
     <yAxis> 
      <javafx.scene.chart.NumberAxis 
        label="Y Axis" 
        lowerBound="100" 
        upperBound="0.001" 
        tickUnit="10" 
        autoRanging="false" 
       /> 
     </yAxis> 
    </javafx.scene.chart.LineChart>    
</Hbox> 
Powiązane problemy