2D-Grafik Werteanpassung des DefaultCategoryDatasets vermeiden

Panther7713

Mitglied
Hey,

ich stehe aktuell vor dem Problem, dass ich ein Diagramm erstellen will, welches in der Lage ist verschiedene TimeSeries in Abschnitten wiederzugeben. Bisher habe ich dafür auf einen modifizierten GanttChart zurückgegriffen. Dadurch lies sich folgendes Diagramm bereits erzeugen.
Einfluss%20der%20Werkzeugwechselzeiten.jpg


Allerdings war ich nicht in der Lage die verschiedenen Series auf eine Linie zu positionieren, da der (ich glaube es ist der Renderer) Renderer mir einen Strich durch die Rechnung macht und für jede Series eine eigene horizontale Reihe einführt.
Also dachte ich mir, naja mach ich halt ein StackedBarChart. Das Problem ist nur, dass dort sowie ich eine Series wiederholt nutze, mir (und das vermute ich ebenfalls nur) der DefaultCategoryDataset einen Strich durch die Rechnung macht und einfach lediglich den letzte Wert ausgibt und alle vorherigen Werte überschreibt(In meinem Beispiel wird der Wert 10 ignoriert und für Series 2 lediglich der Wert 1 angezeigt).
Das Ergebnis ziegt sich in folgendem Bild:
StackedBarChart.JPG

Ich vermute, dass ich mir einen eigenen DefaultCategoryDataset schreiben muss, aber ich bin mir auch nicht sicher ob vielleicht der Renderer an allem Schuld ist. Hat jemand damit schonmal Erfahrung gemacht? Beim googlen bin ich bereits mehrfach auf die Fragestellung gestoßen aber diese wurde noch nicht beantwortet.

Java:
import java.awt.Color;
import java.awt.Dimension;
import java.util.LinkedList;
import javax.swing.JPanel;
import org.jfree.chart.*;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;

import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.StackedBarRenderer;

import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.statistics.DefaultMultiValueCategoryDataset;

import org.jfree.data.time.*;

import org.jfree.ui.ApplicationFrame;

/**
 *
 * @author Christoph
 */
public class Arbeitsraumplan extends ApplicationFrame {
    
//Attribute der Klasse Arbeitsraumplan
   
    
    
//Konstruktor der Klasse Arbeitsraumplan    
      //private static final long serialVersionUID = 1L;   
   
    public Arbeitsraumplan(String s)   
    {   
        super(s);   
        JPanel jpanel = createArbeitsraumPanel();   
        jpanel.setPreferredSize(new Dimension(500, 270));   
        setContentPane(jpanel);   
    }   
   
    
   
    private static JFreeChart createChart(CategoryDataset categorydataset)   
    {   
        JFreeChart jfreechart = ChartFactory.createStackedBarChart("Arbeitsraumplan", "Arbeitsräume", "X-Achse", 
                categorydataset, PlotOrientation.HORIZONTAL, true, false, false);   
        jfreechart.setBackgroundPaint(Color.white);   
        CategoryPlot categoryplot = (CategoryPlot)jfreechart.getPlot();   
        categoryplot.setBackgroundPaint(Color.lightGray);   
        categoryplot.setRangeGridlinePaint(Color.white);   
        StackedBarRenderer stackedbarrenderer = (StackedBarRenderer)categoryplot.getRenderer();   
        stackedbarrenderer.setDrawBarOutline(false);   
        //long l = System.currentTimeMillis();   
        stackedbarrenderer.setBase(0);   
        NumberAxis numberaxis = new NumberAxis("Zeit");   
        categoryplot.setRangeAxis(numberaxis);   
        return jfreechart;   
    }   
   
    public static JPanel createArbeitsraumPanel()   
    {   
        JFreeChart jfreechart = createChart(createDataset());   
        return new ChartPanel(jfreechart);   
    }   
   
        
    private static CategoryDataset createDataset()   
    {   
        DefaultCategoryDataset defaultcategorydataset = new DefaultCategoryDataset();   
        //long l = 0x5265c00L;   
        
        
        defaultcategorydataset.addValue(2, "Series 1", "Category 1");   
        
        defaultcategorydataset.addValue(10, "Series 2", "Category 1");   
        defaultcategorydataset.addValue(2, "Series 3", "Category 1");
        defaultcategorydataset.addValue(1, "Series 2", "Category 1");
        defaultcategorydataset.addValue(4, "Series 1", "Category 2");   
        defaultcategorydataset.addValue(5, "Series 2", "Category 2");   
        defaultcategorydataset.addValue(1, "Series 3", "Category 2");
       
        return defaultcategorydataset;   
    }   

    
}
 

Harry Kane

Top Contributor
Wenn ich dich richtig verstanden habe, möchtest du mit einem CategoryDataset pro Column/Row Kombination mehrere Intervalle darstellen. Mit den vorhandenen CategoryDataset interfaces ist das leider nicht möglich.
- Beim einfachen CategoryDataset gibt es nur die Möglichkeit, einen Wert pro Column/Row Kombnination abzufragen.
- Beim IntervalCategoryDataset gibt es nur die Möglichkeit, ein Interval pro Column/Row Kombnination abzufragen (getStartValue(int row, int column) und getEndValue(int row, int column)).
- Beim MultiValueCategoryDataset gibt es die Möglichkeit, mit getValues(int row, int column) pro Column/Row Kombination eine Werteliste abzufragen.
- Was fehlt ist ein MultiIntervalCategoryDataset mit z. B. der Methode getInterval(int row, int column), die z. B. eine Objekt der Klasse org.jfree.data.Range zurückgeben könnte. Ausserdem fehlt ein renderer, der diese ganzen Intervalle aus dem dataset abfragt und auf eine sinnvolle Weise darstellen kann.

Du kannst das, von dem ich vermute dass du es haben möchtest, mit einem XYPlot und einer SymbolAxis erreichen. SymbolAxis ist einer Unterklasse von NumberAxis mit ganzzahligen Abständen zwischen den x-Werten, die anstelle der ganzen Zahlen Strings als tick labes anzeigt.
Hier ist ein Anwendungsbeispiel. Ich hoffe es ist halbwegs selbsterklärend:
Java:
public class XYRaumbelegung extends ApplicationFrame {

  public XYRaumbelegung(final String title) {

     super(title);
     XYIntervalSeriesCollection dataset = new XYIntervalSeriesCollection();
     //6 verschiedene Räume
     int roomCount= 6;
     String[] rooms = new String[roomCount];
     for(int i = 0; i < roomCount; i++){
          rooms[i] = "Raum 0" + i;
     }
     //4 verschiedene Kurse, inkl. "Frei"
     int courseTypes = 4;
     String[] courseNames= new String[]{"Kochen","Rechnen","Sackhüpfen","Frei"};
     int totalCourseCount = 30;
     Random r = new Random();
     //Zeiten, bis wann der entsprechende Raum belegt ist
     double[] startTimes = new double[roomCount];

     //Serien anlegen, in denen die Star- und Endzeiten der Kurse als y-Intervalle und die Räume als x-Werte hinterlegt sind
     XYIntervalSeries[] series = new XYIntervalSeries[courseTypes];
     for(int i = 0; i < courseTypes; i++){
          series[i] = new XYIntervalSeries(courseNames[i]);
          dataset.addSeries(series[i]);
     }

     for(int k = 0; k < totalCourseCount; k++){
          //Per Zufallsgenerator einen Raum raussuchen
          int currentRoom = r.nextInt(roomCount);
          //Per Zufallsgenerator einen Kurs raussuchen
          int currentCourse = r.nextInt(courseTypes);
          //Per Zufallsgenerator die Länge des Kurses bestimmen (1-3 Stunden)
          int time = r.nextInt(3) + 1;
          //Den Raum als x-Wert kodieren, sowie die Länge als Interval ab der für diesen Raum möglichen Startzeit, abzgl 0.1 min am Anfang und Ende
          series[currentCourse].add(currentRoom, currentRoom - 0.3, currentRoom + 0.3, startTimes[currentRoom], startTimes[currentRoom] +0.1, startTimes[currentRoom] + time - 0.1);
          //Die Startzeit für den aktuellen Raum hochsetzen
          startTimes[currentRoom] += time;
     }
     XYBarRenderer renderer = new XYBarRenderer();
     renderer.setUseYInterval(true);
     XYPlot plot = new XYPlot(dataset, new SymbolAxis("Rooms", rooms), new NumberAxis(), renderer);
     plot.setOrientation(PlotOrientation.HORIZONTAL);
     JFreeChart chart = new JFreeChart(plot);
     getContentPane().add(new ChartPanel(chart));

  }

  public static void main(final String[] args) {

     final XYRaumbelegung demo = new XYRaumbelegung("XYRaumbelegung");
     demo.pack();
     RefineryUtilities.centerFrameOnScreen(demo);
     demo.setVisible(true);

  }

}
 

Panther7713

Mitglied
Hey,

erstmal vielen, vielen, vielen Dank für deine Hilfe!!! War echt schon verzweifelt und darauf wäre ich auch nie alleine gekommen.
Es ist genau das, was ich gesucht habe! Habe mich heute dran gemacht alles zu verstehen und langsam läufts. :)

Ich habe noch eine kleine Sache und zwar müssen die Series bei mir nahtlos in einander übergehen. Aktuell werden diese aber manchmal von einem kleinen "Schatten" überlagert (Siehe unteres Bild). Weißt du wie man diesen permanent ausstellt?

XYArbeitsraumbelegung.png


Gruß

Panther
 

Harry Kane

Top Contributor
Verwende die Klassenmethode
Java:
XYBarRenderer.setDefaultShadowsVisible(false);
und wenn du statt der Farbgradienten lieber was einfarbiges möchtest:
Java:
XYBarRenderer.setDefaultBarPainter(new StandardXYBarPainter());

Wenn du diese Methoden auf der Klasse aufrufst, gelten die Einstellungen für alle XYBarRenderer, die nach dem Aufruf der Klassenmehtode erzeugt wurden.
Wenn Du die Einstellungen nur für ein bestimmte Instanz ändern möchtest, verwende
Java:
renderer.setShadowVisible(false);
und
Java:
renderer.setBarPainter(new StandardXYBarPainter());
 

Ähnliche Java Themen


Oben