# JFreeChart: nur jeden n-ten Wert auf der X-Achse anzeigen



## Rol (5. Apr 2011)

Ich erzeuge mit JFreeChart einen Balken Chart. Dabei gibt es u.U. sehr viele Balken (Kategorien). Standardmäßig wird wird für jeden Balken ein Label unter der x-Achse gesetzt, was dann zur Foge hat, dass die Beschriftungen ineinanderlaufen und nicht mehr lesbar sind.

Wie erreiche ich, dass nur für jeden n-ten Balken eine Beschriftung gesetzt wird?


----------



## SlaterB (6. Apr 2011)

die Beschriftungen gibst du doch selber, modifiziere deinen Code zur Initialisierung des DataSets,
wobei gleiche Identifer, also String null oder "" oder " " glaube ich nicht so toll sind, ich hatte mir dafür einmal extra eine neue Klasse angelegt, vielleicht geht auch new String(" "); ?
wenn du dahingehend was machst und Probleme hast, dann sag Bescheid, am besten mit Beispielprogramm

oder meinst du wirklich Kategorien statt einzelner Werte? ein Beispielprogramm würde alles eindeutig erklären


----------



## Rol (6. Apr 2011)

SlaterB hat gesagt.:


> die Beschriftungen gibst du doch selber, modifiziere deinen Code zur Initialisierung des DataSets,



Ich erzeuge für jeden Balken einen Datensatz im DataSet mit:

public void addValue(Number value, Comparable rowKey, Comparable columnKey)
also:

```
datasetDays.setValue((daysHisto[i] / 1000000f), "", String.valueOf(i));
```

"String.valueOf(i)" ist also mein "columnKey" und dieser wird (leider) als x-Achenbeschriftung angezeigt.
Kann ich irgendwie den columnKey und die x-Achenbeschriftung getrennt angeben?

(String.valueOf(i) ist die "Nummer" des aktuellen Arrayfeldes, später soll das mal ein Datumswert sein, aber zum testen geht das so)



SlaterB hat gesagt.:


> oder meinst du wirklich Kategorien statt einzelner Werte?



Es ist ein Balkendiagramm das Werte einer täglich stattfindenden Aktion darstellen soll, also ein Balken pro Tag. Bei einem darzustellenden Zeitfenster von ein paar Tagen ist die Beschriftung jedes Balkens o.k., wenn aber ein ganzes Jahr dargestellt werden soll, ist die x-Achensbeschriftung nur noch ein Batzen in sich verschlungener Schrift. Dann sollte z.B. nur jeder 10. Balken beschriftet werden


----------



## SlaterB (6. Apr 2011)

hier
ChartJava
gibt es Beispiel-Klassen für alle Charts,
wäre schön wenn du dir eine aussuchst, mit Schleife viele Dummy-Daten einfügst und das ganze dann postest,
damit ich es auch ausführen und das Problem sehen kann

ich habe selber sowohl mit allgemeinen Kategorien als auch mit Einzelwerten viel experimentiert,
es lohnt sich also wenn mir das ganze verständlich machen würdest


----------



## Rol (7. Apr 2011)

Ich habe "Bar Chart Demo 3" aus Deinem Link jetzt so verändert, dass das dataSet aus einem Array mit 100 Felden (das könnten in echt dann auch ein paar hundert werden) erzeugt wird.


```
//package org.jfree.chart.demo;

import java.awt.Color;
import java.awt.Paint;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.TextAnchor;

/**
 * A bar chart that uses a custom renderer to display different colors within a series.
 * No legend is displayed because there is only one series but the colors are not consistent.
 *
 */
public class BarChartDemo3 extends ApplicationFrame {

    /**
     * A custom renderer that returns a different color for each item in a single series.
     */
    class CustomRenderer extends BarRenderer {

        /** The colors. */
        private Paint[] colors;

        /**
         * Creates a new renderer.
         *
         * @param colors  the colors.
         */
        public CustomRenderer(final Paint[] colors) {
            this.colors = colors;
        }

        /**
         * Returns the paint for an item.  Overrides the default behaviour inherited from
         * AbstractSeriesRenderer.
         *
         * @param row  the series.
         * @param column  the category.
         *
         * @return The item color.
         */
        public Paint getItemPaint(final int row, final int column) {
            return this.colors[column % this.colors.length];
        }
    }
    /**
     * Creates a new demo.
     *
     * @param title  the frame title.
     */
    int[] myArray = new int[365];

    public BarChartDemo3(final String title) {
        super(title);
        fillArray();
        final CategoryDataset dataset = createDataset();
        final JFreeChart chart = createChart(dataset);
        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel);
    }

    private void fillArray() {
        for (int i = 0; i < 365; i++) {
            myArray[i] = (int) Math.round(Math.random() * 100);
        }
    }

    /**
     * Creates a sample dataset.
     *
     * @return a sample dataset.
     */
    private CategoryDataset createDataset() {
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        int[] myArray = new int[100];
        for (int i = 0; i < 100; i++) {
            myArray[i] = (int) Math.round(Math.random() * 100);
        }

        for (int i = 0; i < myArray.length; i++) {
            dataset.addValue((myArray[i] / 1000000f), "", String.valueOf(i));
        }
        return dataset;
    }

    /**
     * Creates a sample chart.
     *
     * @param dataset  the dataset.
     *
     * @return a sample chart.
     */
    private JFreeChart createChart(final CategoryDataset dataset) {

        final JFreeChart chart = ChartFactory.createBarChart(
                "Bar Chart Demo 3", // chart title
                "Date", // domain axis label
                "Value", // range axis label
                dataset, // data
                PlotOrientation.VERTICAL, // the plot orientation
                false, // include legend
                true,
                false);

        chart.setBackgroundPaint(Color.lightGray);

        // get a reference to the plot for further customisation...
        final CategoryPlot plot = chart.getCategoryPlot();
        plot.setNoDataMessage("NO DATA!");

        // change the margin at the top of the range axis...
        final ValueAxis rangeAxis = plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setLowerMargin(0.15);
        rangeAxis.setUpperMargin(0.15);

        return chart;

    }

    /**
     * Starting point for the demonstration application.
     *
     * @param args  ignored.
     */
    public static void main(final String[] args) {

        final BarChartDemo3 demo = new BarChartDemo3("Bar Chart Demo 3");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);

    }
}
```

Man sieht wie die Beschriftung der x-Achse unleserlich ineinander läuft. Das könnte man verhindern in dem man nur jeden n-ten (vielleicht 10-100-ten) Balken beschriftet. Und genau das bekomme ich nicht hin...


----------



## SlaterB (7. Apr 2011)

der normale Weg wäre

```
for (int i = 0; i < myArray.length; i++)  {
            String id = "";
            if (i % 10 == 0) id = String.valueOf(i);
            dataset.addValue((myArray[i] / 1000000f), "", id);
        }
```
einfach die id überwiegend auf "" stellen,

leider gefällt JFreeChart das nicht bzw. macht duchaus auch Sinn, jeder Value ist durch seinen Identifer bestimmt,
mehrmals "" ist immer derselbe Eintrag,

ich habe mir dafür eine Extra-Klasse geschrieben, die trotz gleichen Inhalt bei compare nicht 0 zurückgibt,
intern wird noch eine eindeutige nummer vergeben und nach dieser nachrangig sortiert,
damit die compareTo-Rückgabe nicht völlig willkürlich ist, vielleicht unnötig


```
class IdentiferWrapper
    implements Comparable<IdentiferWrapper>
{
    private static int count;
    private int number;
    private Comparable identifer;

    public IdentiferWrapper(Comparable identifer)
    {
        this.identifer = identifer;
        this.number = count++;
    }

    public String toString()
    {
        return this.identifer.toString();
    }

    public int compareTo(IdentiferWrapper o)
    {
        if (this == o)
        {
            return 0;
        }
        int c = this.identifer.compareTo(o.identifer);
        if (c == 0)
        {
            return this.number - o.number;
        }
        return c;
    }
}
```
dann new IdentiferWrapper(id) statt id einfügen

------

Problem könnte noch sein, dass selbst die wenigen Labels nur als .. dargestellt werden,
das hier müsste dagegen helfen:


```
CategoryAxis domainAxis = plot.getDomainAxis();
        double factor = 0;
        CategoryLabelPositions pos = CategoryLabelPositions.createUpRotationLabelPositions(factor);
        domainAxis.setCategoryLabelPositions(pos);
```
mit einem anderen factor als 0 werden die Labels schräg dargestellt, auch recht praktisch, im kleinen Bereich bis PI/2 sinnvoll


----------

