czwartek, 1 grudnia 2011

Malowanie wykresów za pomocą JFreeChart cz. 2

Ostatnim razem we wpisie Malowanie wykresów za pomocą JFreeChart cz. 1 pokazałem jak przygotować prosty wykres za pomocą biblioteki JFreeChart. Teraz chciałbym rozszerzyć przykład, poprzez pokazanie, jak dodać do wykresu własną skalę kolorów.

Aby to zrobić musimy stworzyć klasę implementującą interfejs PaintScale. Definiuje on dwie metody: getLowerBound() i getUpperBound(). Powinny one zwracać odpowiednio dolną i górną granicę skali. Trzecią i najważniejszą metodą jest getPaint(). Zwraca ona obiekt typu Paint. Początkowo chwilę się zastanawiałem, co to za twór, co sobą reprezentuje i jak go utworzyć…

Na szczęście klasa Color z tej samej biblioteki implementuje ten interfejs. Dzięki temu możemy w naszej implementacji zwrócić odpowiedni kolor. Poniżej przykładowa implementacja.

public class ColorPaintScale implements PaintScale {
    private static final Color[] colors = {
            new Color(36, 35, 105),
            new Color(0, 6, 252),
            new Color(0, 134, 250),
            new Color(9, 251, 242),
            new Color(135, 252, 112),
            new Color(254, 241, 3),
            new Color(255, 117, 0),
            new Color(244, 0, 1),
            new Color(104, 21, 21),
    };

    private int lowerBound = 0;
    private int upperBound = 100;

    public ColorPaintScale(int lowerBound, int upperBound) {
        this.lowerBound = lowerBound;
        this.upperBound = upperBound;
    }

    public double getLowerBound() {
        return lowerBound;
    }

    public double getUpperBound() {
        return upperBound;
    }

    public Paint getPaint(double v) {
        double divisor = (upperBound - lowerBound) / colors.length;
        int index = (int) ((v - lowerBound) / divisor);
        if (index < 0) {
            return colors[0];
        }
        if (index >= colors.length) {
            return colors[colors.length - 1];
        }
        return colors[index];
    }
}

W powyższej klasie na początku definiujemy sobie kolory, jakie mają być wyświetlane na naszej skali. W liniach 14 i 15 definiujemy dolną i górną wartość naszej skali. Pola te są inicjowane w konstruktorze. Następnie mamy gettery dla tych pól (zdefiniowane w interfejsie) i metodę getPaint() do zwracania odpowiedniego koloru z dostępnej skali.

Gdy już mamy naszą klasę odpowiedzialną za skalę, przekazujemy ją do obiektu renderer’a:

PaintScale scale = new ColorPaintScale(0, 10);
XYBlockRenderer renderer = new XYBlockRenderer();
renderer.setPaintScale(scale);

Poniższy kod można zastosować w ostatnim przykładzie z poprzedniego postu. Kod i efekt poniżej:

public JPanel chartWithScale() {
    DefaultXYZDataset xyzDataset = new DefaultXYZDataset();
    double[][] series01 = new double[][]{{1}, {1}, {5}};
    double[][] series02 = new double[][]{{2, 5}, {3, 4}, {7, 9}};
    xyzDataset.addSeries("Series01", series01);
    xyzDataset.addSeries("Series02", series02);

    NumberAxis domainAxis = new NumberAxis("X Label");
    domainAxis.setRange(0, 10);

    NumberAxis valueAxis = new NumberAxis("Y Label");
    valueAxis.setRange(0, 7);

    PaintScale scale = new ColorPaintScale(0, 10);
    XYBlockRenderer renderer = new XYBlockRenderer();
    renderer.setPaintScale(scale);

    XYPlot plot = new XYPlot(xyzDataset, domainAxis, 
            valueAxis, renderer);

    JFreeChart chart = new JFreeChart("title", plot);

    return new ChartPanel(chart);
}



Ok, pola zostały pomalowane na kolorowo, ale dalej nie widzimy skali. Aby to zrobić musimy mieć utworzony już obiekt typu Chart, gdyż do niego będzie dodawać "podtytuł". Napiszmy zatem do tego osobną metodę:

private void addPaintScaleToChart(PaintScale scale, JFreeChart chart) {
    NumberAxis numberAxisPaintScale = new NumberAxis("Skala");
    numberAxisPaintScale.setTickLabelFont(new Font("Dialog", 0, 7));

    PaintScaleLegend paintScaleLegend = new PaintScaleLegend(scale, 
            numberAxisPaintScale);
    paintScaleLegend.setAxisOffset(5D);
    paintScaleLegend.setMargin(new RectangleInsets(5D, 5D, 5D, 5D));
    paintScaleLegend.setPadding(new RectangleInsets(10D, 10D, 
            10D, 10D));
    paintScaleLegend.setFrame(new BlockBorder(Color.RED));
    paintScaleLegend.setStripWidth(10D);
    paintScaleLegend.setPosition(RectangleEdge.RIGHT);
    chart.addSubtitle(paintScaleLegend);
}

I ją wywołajmy po utworzeniu obiektu chart. Efekt poniżej:



Na początku przedstawianej metody addPaintScaleToChart() tworzymy skalę i ustawiamy jej czcionkę. Jakbyśmy chcieli się pozbyć czarnych poziomych i pionowych kreseczek pomiędzy liczbami a kolorami, możemy wywołać poniższe dwie metody:

numberAxisPaintScale.setAxisLinePaint(Color.white);
numberAxisPaintScale.setTickMarkPaint(Color.white);

Następnie tworzymy legendę i ustalamy kilka właściwości. Za pomocą setAxisOffset() ustawiamy odległość pomiędzy podziałką a kolorową skalą. Poprzez setMargin() ustawiamy otoczenie naszej skali na panelu z wykresem. Nazwa argumentu sugeruje działanie podobne do Swingowych (czy też AWTowych) Insets, aczkolwiek klasy te są ze sobą nie powiązane. Za pomocą setPadding() ustawiamy odstęp we wnętrzu naszej skali, tzn. odległości kolorowej skali od brzegu legendy.

Dalej ustawiamy kolor obramowania, szerokość kolorków i pozycję względem wykresu. Na koniec dodajemy naszą legendę do wykresu za pomocą addSubtitle().

To chyba tyle w temacie biblioteki JFreeChart. Na razie nie planuję dalszej zabawy z nią, a w kolejce czekają następne tematy do ogarnięcia.

Brak komentarzy:

Prześlij komentarz