CombinedDomainXYPlot und dynamisch hinzugefügte subplots: Darstellungsprobleme

SuperFamicom

Aktives Mitglied
Hallo,

ich arbeite momentan an einer Anwendung, in der ich Messreihen vertikal geplottet darstelle. Dabei nutze ich JFreeChart. Die Messreihen unterliegen als subplots einem CombinedDomainXYPlot und können je nach Belieben entweder angezeigt oder versteckt werden. Hierzu folgender Demo-Code:

Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ItemEvent;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisSpace;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.DomainOrder;
import org.jfree.data.general.DatasetChangeListener;
import org.jfree.data.general.DatasetGroup;
import org.jfree.data.xy.AbstractXYDataset;


public class VerticalPlots {         
  
    private final JFrame frame;
  
    private final ChartPanel chartPanel;
  
    private final JPanel checkBoxPanel;
  
    private final JCheckBox checkBox[] = new JCheckBox[5];
  
    private final XYPlot[] subPlot = new XYPlot[5];
  
    private final TestDataset[] dataset = new TestDataset[5];
  
    private final int dataColumnWidth = 42;
  
    private final int depthColumnWidth = 54;
  
    private CombinedDomainXYPlot combinedPlot;
      
                      
    public VerticalPlots() {
        generateAndPopulateDataset();              
      
        checkBoxPanel = new JPanel();
        checkBoxPanel.setBackground(Color.WHITE);
        BoxLayout layout = new BoxLayout(checkBoxPanel, BoxLayout.Y_AXIS);
        checkBoxPanel.setLayout(layout);
        checkBoxPanel.setPreferredSize(new Dimension(130 - depthColumnWidth, 512));
        checkBoxPanel.setMinimumSize(checkBoxPanel.getPreferredSize());
      
        checkBox[0] = new JCheckBox("Plot1");
        checkBox[0].setOpaque(false);
        checkBox[0].addItemListener((ItemEvent e) -> {
            if (e.getSource().equals(checkBox[0])) {
                updateUI();
            }
        });
      
        checkBox[1] = new JCheckBox("Plot2");
        checkBox[1].setOpaque(false);
        checkBox[1].addItemListener((ItemEvent e) -> {
            if (e.getSource().equals(checkBox[1])) {
                updateUI();
            }
        });
      
        checkBox[2] = new JCheckBox("Plot3");
        checkBox[2].setOpaque(false);
        checkBox[2].addItemListener((ItemEvent e) -> {
            if (e.getSource().equals(checkBox[2])) {
                updateUI();
            }
        });
      
        checkBox[3] = new JCheckBox("Plot4");
        checkBox[3].setOpaque(false);
        checkBox[3].addItemListener((ItemEvent e) -> {
            if (e.getSource().equals(checkBox[3])) {
                updateUI();
            }
        });
      
        checkBox[4] = new JCheckBox("Plot5");
        checkBox[4].setOpaque(false);
        checkBox[4].addItemListener((ItemEvent e) -> {
            if (e.getSource().equals(checkBox[4])) {
                updateUI();
            }
        });
      
        checkBoxPanel.add(checkBox[0]);
        checkBoxPanel.add(checkBox[1]);
        checkBoxPanel.add(checkBox[2]);
        checkBoxPanel.add(checkBox[3]);
        checkBoxPanel.add(checkBox[4]);
      
        chartPanel = createChartPanel();
        chartPanel.setPreferredSize(new Dimension(depthColumnWidth, 512));
        chartPanel.setMinimumDrawWidth(0);
      
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.setLocation(512, 240);
        frame.setPreferredSize(new Dimension(depthColumnWidth, 512));
        frame.add(checkBoxPanel, BorderLayout.WEST);
        frame.add(chartPanel, BorderLayout.EAST);
        frame.setResizable(false);
        frame.pack();
        frame.setVisible(true);
    }
  
    public static void main(String[] args) {
        new VerticalPlots();
    }
  
    private ChartPanel createChartPanel() {
      
        NumberAxis sharedDomainAxis = new NumberAxis("Depth (.m)");
        sharedDomainAxis.setInverted(true);
        sharedDomainAxis.setRange(0, 500);
      
        NumberAxis rangeAxis = new NumberAxis();
        rangeAxis.setRange(0, 100);
      
        AxisSpace space = new AxisSpace();
        space.setLeft(depthColumnWidth);
      
        combinedPlot = new CombinedDomainXYPlot(sharedDomainAxis);
        combinedPlot.setFixedDomainAxisSpace(space);
        combinedPlot.setGap(-1);
        combinedPlot.setOrientation(PlotOrientation.HORIZONTAL);
                     
        XYItemRenderer renderer = new StandardXYItemRenderer();
              
        for (int i = 0; i < checkBox.length; i++) {
            subPlot[i] = new XYPlot(dataset[i], null, rangeAxis, renderer);
            subPlot[i].setDataset(0, dataset[i]);
            subPlot[i].setRenderer(0, renderer);
            subPlot[i].setOrientation(PlotOrientation.HORIZONTAL);
            subPlot[i].setRangeAxis(rangeAxis);
            subPlot[i].getRangeAxis().setVisible(false);
            subPlot[i].setOutlinePaint(Color.BLACK);
        }
      
        JFreeChart chart = new JFreeChart(combinedPlot);
        chart.removeLegend();
        chart.setAntiAlias(false);
        chart.setBackgroundPaint(Color.LIGHT_GRAY);
        chart.setBorderVisible(false);      
      
        ChartPanel panel = new ChartPanel(chart);
        panel.setVisible(true);
      
        return panel;
    }
  
    /**
     *
     */
    private void updateUI() {
      
        Dimension dimension = frame.getSize();
        int newHeight = dimension.height;
        int newWidth = checkBoxPanel.getMinimumSize().width + depthColumnWidth;
      
        /* Retrieve all currently shown subplots. */
        CopyOnWriteArrayList<XYPlot> subPlots = new CopyOnWriteArrayList<>(combinedPlot.getSubplots());
                      
        /* Remove all currently shown suplots. */
        subPlots.forEach((plot) -> {
            combinedPlot.remove(plot);
        });
      
        /* Iterate through each checkbox to check whether corresponding subplot is visible; if so, add the subplot to the combined plot. */
        for (int i = 0; i < checkBox.length; i++) {
            if (checkBox[i].isSelected()) {
                combinedPlot.add(subPlot[i]);
                newWidth += dataColumnWidth;
            }
        }
              
        frame.setSize(new Dimension(newWidth, newHeight));
        chartPanel.setPreferredSize(new Dimension(newWidth - checkBoxPanel.getMinimumSize().width, newHeight));
        frame.revalidate();
    }
  
    private void generateAndPopulateDataset() {
        for (int i = 0; i < checkBox.length; i++) {
            dataset[i] = new TestDataset();          
            Random random = new Random();
            for (int j = 0; j <= 500; j++) {
                ((TestDataset) dataset[i]).setYValue(25 + random.nextInt(50), j);
            }
        }
    }      
  
    class TestDataset extends AbstractXYDataset {

        int[] values = new int[501];
      
      
        @Override
        public final Number getX(int series, int item) {
            return getXValue(0, item);
        }

        @Override
        public final double getXValue(int series, int item) {
            return item - 1;
        }

        public final void setYValue(int value, int item) {
            values[item] = value;
        }

        @Override
        public final Number getY(int series, int item) {
            return getYValue(0, item);
        }

        @Override
        public final double getYValue(int series, int item) {
            return values[item];
        }

        @Override
        public final DomainOrder getDomainOrder() { return DomainOrder.ASCENDING; }

        @Override
        public final int getItemCount(int series) { return 500; }

        @Override
        public final int getSeriesCount() { return 1; }

        @Override
        public final Comparable getSeriesKey(int series) { return ""; }

        @Override
        public final int indexOf(Comparable seriesKey) { return 0; }

        @Override
        public final void addChangeListener(DatasetChangeListener listener) {}

        @Override
        public final void removeChangeListener(DatasetChangeListener listener) {}

        @Override
        public final DatasetGroup getGroup() { return null; }

        @Override
        public final void setGroup(DatasetGroup group) {}
    }
}

Beim Checken der CheckBoxen links im weißen Panel wird jeweiliger subplot rechts im grauen Panel im CombinedDomainXYPlot angezeigt. Beim Unchecken wird jeweiliger subplot versteckt.

Folgendes ist zu beobachten und unerwünscht:
  1. Enthält der CombinedDomainXYPlot keine subplots (wie beim Start der Anwendung), ist die Depth-Domaine leicht nach rechts außerhalb des Frames verschoben.
  2. Wird der erste Plot durch eine CheckBox dargestellt, so rutscht zwar die Depth-Domain in die richtige Position, aber der subplot wird schmaler, als mit der Konstante dataColumnWidth vorgegeben, dargestellt.
  3. Werden immer mehr subplots über die CheckBoxen sichtbar gemacht, so nimmt die Breite der einzelnen subplots sukzessive zu.
Folgende Darstellungskriterien sollen erfüllt sein:

A. Die geteilte Domaine (Depth (.m) mit jeweiligen ticks marks und tick labels) im grauen Panel soll standardmäßig immer angezeigt werden, egal ob momentan subplots angezeigt werden oder nicht.
B. Die Depth-Domaine hat immer die gleiche Breite vom linken Rand des grauen Bereichs bis hin zur eigentlichen Achse mit den ticks.
C. Die Breite der subplots soll immer konstant (= dataColumnWidth) sein.​

Da JFreeChart keine richtigen Lösungen für das pixelgenaue Platzieren von subplots ermöglicht, sei mal hier die Frage an den JFreeChart-affinen Teil der Community gerichtet, wie sich die Punkte 1 bis 3 unter Berücksichtigung der Kriterien A bis C bewerkstelligen lässt.

Cheers-
 

Harry Kane

Top Contributor
Du berücksichtigst bei der newWidth nicht die Insets der subplots und des CombinedPlots.
Mache mal folgende Änderungen:
Im Konstruktor von VerticalPlots:
Java:
RectangleInsets ri = combinedPlot.getInsets();
chartPanel.setPreferredSize(new Dimension(depthColumnWidth + (int)(ri.getLeft() + ri.getRight()), 512));
In der updateUI:
Java:
for (int i = 0; i < checkBox.length; i++) {
    if (checkBox[i].isSelected()) {
        combinedPlot.add(subPlot[i]);
        RectangleInsets ri = subPlot[i].getInsets();
        newWidth += ri.getLeft() + ri.getRight();
        newWidth += dataColumnWidth;
    }
}
RectangleInsets ri = combinedPlot.getInsets();
newWidth += ri.getLeft() + ri.getRight();
Du brauchst übrigens nur einen ItemListener, den du allen CheckBoxen hinzufügst. Die tests e.getSource().equals(checkBox[x]) sind überflüssig, weil sowieso immer updateUI aufgerufen wird.
 

SuperFamicom

Aktives Mitglied
Supi, das kommt dem schon näher.
Allerdings beobachte ich, nachdem die ersten 3 CheckBoxen gecheckt wurden, dass beim Checken der 4. CheckBox der subplot breiter wird.


Du brauchst übrigens nur einen ItemListener, den du allen CheckBoxen hinzufügst. Die tests e.getSource().equals(checkBox[x]) sind überflüssig, weil sowieso immer updateUI aufgerufen wird.

Ups :D
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
W JavaFX Farben dynamisch anpassen AWT, Swing, JavaFX & SWT 4
B Größe der Parent-Component dynamisch an children anpassen AWT, Swing, JavaFX & SWT 30
K Buttons dynamisch erstellen (NetBeans) AWT, Swing, JavaFX & SWT 10
ralfb1105 JavaFX TreeView dynamisch aus Datenbank Tabelle erstellen AWT, Swing, JavaFX & SWT 22
ralfb1105 JavaFX Dynamisch TableView Spalten erstellen AWT, Swing, JavaFX & SWT 4
A Swing JPanels dynamisch untereinander einfügen AWT, Swing, JavaFX & SWT 3
Wurstsemmel SWT MenuItem dynamisch hinzufügen AWT, Swing, JavaFX & SWT 2
L JavaFX List oder TableView Größe dynamisch anpassen? AWT, Swing, JavaFX & SWT 4
MaxG. Swing Dynamisch grafische Objekte erzeugen AWT, Swing, JavaFX & SWT 12
Thallius JTable dynamisch Spaltenanzahl verändern AWT, Swing, JavaFX & SWT 2
Thallius JTable dynamisch laden? AWT, Swing, JavaFX & SWT 2
K Liniendicke für Line Chart dynamisch ändern AWT, Swing, JavaFX & SWT 0
N Swing Wie Programm strukturieren? (Dynamisch Komponenten hinzufügen) AWT, Swing, JavaFX & SWT 1
llabusch JavaFX Dynamisch alles vergrößern (wie im Browser) AWT, Swing, JavaFX & SWT 3
agent47 JavaFX TreeView Struktur dynamisch einlesen AWT, Swing, JavaFX & SWT 1
D JavaFX Dynamisch erzeugte Buttons sollen Code ausführen. AWT, Swing, JavaFX & SWT 2
D JavaFX Dynamisch erzeugte Checkboxen aus VBox auslesen AWT, Swing, JavaFX & SWT 3
J Swing/AWT | Dynamisch erzeugte Objekte ansprechen AWT, Swing, JavaFX & SWT 1
I JTable dynamisch aus ArrayList befüllen AWT, Swing, JavaFX & SWT 3
T JavaFX Flexible Layouts dynamisch erstellen / Design-Inspirationen AWT, Swing, JavaFX & SWT 8
T Dynamisch mehrere Checkboxen anlegen AWT, Swing, JavaFX & SWT 2
J JavaFX TextArea dynamisch Icon im Background anzeigen AWT, Swing, JavaFX & SWT 2
T JPanel dynamisch erstellen AWT, Swing, JavaFX & SWT 4
G FormLayout dynamisch wachsend AWT, Swing, JavaFX & SWT 0
T JTable dynamisch mit ArrayList AWT, Swing, JavaFX & SWT 2
A Swing Logikaufgabe: Zeilenanzahl einer JTable mit 3d String dynamisch anpassen AWT, Swing, JavaFX & SWT 2
T Swing JScrollPane in JPanel - Breite dynamisch, Höhe fix - wie? AWT, Swing, JavaFX & SWT 2
P TableViewerColumn dynamisch erzeugen AWT, Swing, JavaFX & SWT 3
Kandum obj_JMenu.addMenuListener - variable Anzahl an JMenus / menulistenern & frame.setTitle() dynamisch AWT, Swing, JavaFX & SWT 7
A HELP: JFieldText dynamisch setzen -> langsam AWT, Swing, JavaFX & SWT 19
C Swing CardLayout dynamisch erweitern AWT, Swing, JavaFX & SWT 11
B Link eines Icons dynamisch gestalten AWT, Swing, JavaFX & SWT 2
P ScrollPane nach zeichnen dynamisch resize AWT, Swing, JavaFX & SWT 7
B JToolBar dynamisch auf mehrere Zeilen erweitern AWT, Swing, JavaFX & SWT 2
I Jlist dynamisch aus Datenbank füllen AWT, Swing, JavaFX & SWT 14
P Gifs dynamisch auf GUI anzeigen AWT, Swing, JavaFX & SWT 4
E Breite eines JButton dynamisch ändern AWT, Swing, JavaFX & SWT 3
P Swing Dynamisch zeichnen mit Shapes wie Rectangle2D.Float ? AWT, Swing, JavaFX & SWT 6
C SWT - widget dynamisch erzeugen und anzeigen AWT, Swing, JavaFX & SWT 10
C Tooltip dynamisch setzen AWT, Swing, JavaFX & SWT 7
T Elemente zu JList dynamisch hinzufügen AWT, Swing, JavaFX & SWT 4
X jTextFields dynamisch initialisieren AWT, Swing, JavaFX & SWT 2
A Swing Dynamisch Objekte erzeugen AWT, Swing, JavaFX & SWT 3
L Label dynamisch awt AWT, Swing, JavaFX & SWT 2
H Swing Symbol in Taskleiste dynamisch aus- bzw. einblenden AWT, Swing, JavaFX & SWT 14
B JTabbedPane mit Enumeration dynamisch füllen AWT, Swing, JavaFX & SWT 5
L Dynamisch Objekte in Canvas zeichnen AWT, Swing, JavaFX & SWT 5
D Panels Dynamisch zur Laufzeit austauschen AWT, Swing, JavaFX & SWT 2
J Java 2D - dynamisch zeichnen AWT, Swing, JavaFX & SWT 4
A AWT HSB-Farben dynamisch berechnen AWT, Swing, JavaFX & SWT 5
P Dynamisch Sortieren AWT, Swing, JavaFX & SWT 2
B Swing Dynamisch Elemente in JScrollPane hinzufügen AWT, Swing, JavaFX & SWT 6
Airwolf89 Swing Dynamisch auf Objekte in einer GUI zugreifen AWT, Swing, JavaFX & SWT 10
Airwolf89 Swing Tabs dynamisch ausblenden AWT, Swing, JavaFX & SWT 3
H Swing Register (jTabbedPane) dynamisch hinzufügen? AWT, Swing, JavaFX & SWT 7
Airwolf89 Swing Anzahl der Tabellenspalten dynamisch setzen AWT, Swing, JavaFX & SWT 2
S SWT WizardPage - Button anzeigen und Text-Widgets dynamisch aktualisieren AWT, Swing, JavaFX & SWT 12
R JLabel und JSlider dynamisch erzeugen? AWT, Swing, JavaFX & SWT 3
W Swing dynamisch Buttons in JEditorPane erstellen AWT, Swing, JavaFX & SWT 2
Pithecanthropus Swing JPanels dynamisch austauschen AWT, Swing, JavaFX & SWT 8
S Applet mit Graphics dynamisch vergrößern AWT, Swing, JavaFX & SWT 3
Spot84 jtable mit checkboxnode dynamisch per arraylist füllen AWT, Swing, JavaFX & SWT 8
bugmenot Dynamisch erzeugte jLabels werden nicht angezeigt. AWT, Swing, JavaFX & SWT 5
ABstraCT JCombobox dynamisch füllen (erstes Element Problem) AWT, Swing, JavaFX & SWT 4
J JLabels usw. dynamisch anlegen AWT, Swing, JavaFX & SWT 8
A JList dynamisch vergrößern AWT, Swing, JavaFX & SWT 4
G Felder dynamisch erzeugen! AWT, Swing, JavaFX & SWT 3
I Textfields dynamisch erzeugen AWT, Swing, JavaFX & SWT 4
G Dynamisch Komponenten in einem JPanel bzw JFram austauschen AWT, Swing, JavaFX & SWT 7
B JTree dynamisch aufbauen AWT, Swing, JavaFX & SWT 3
L JPanel dynamisch zuweisen AWT, Swing, JavaFX & SWT 5
T Inhalt einer Combobox dynamisch erstellen? AWT, Swing, JavaFX & SWT 13
S JTextField-Größe dynamisch an Inhalt anpassen. AWT, Swing, JavaFX & SWT 3
S Farben eienr JTextPane dynamisch zuweisen AWT, Swing, JavaFX & SWT 2
J Zugriff auf "dynamisch erzeugte" JTextFields AWT, Swing, JavaFX & SWT 2
D Systray-Icon dynamisch zeichnen AWT, Swing, JavaFX & SWT 8
B JTree dynamisch nachladen AWT, Swing, JavaFX & SWT 3
U Label Icon dynamisch belegen AWT, Swing, JavaFX & SWT 12
F JRadioButton dynamisch benennen? AWT, Swing, JavaFX & SWT 7
A dynamisch weitere jpanels untereinander hinzufügen AWT, Swing, JavaFX & SWT 10
S dynamisch erzeugte buttons AWT, Swing, JavaFX & SWT 22
J Größe einer JTextArea dynamisch anpassen. AWT, Swing, JavaFX & SWT 2
F Komponente dynamisch erzeugen AWT, Swing, JavaFX & SWT 4
M ImageObserver, Bild dynamisch erzeugen und Speichern AWT, Swing, JavaFX & SWT 24
M gezeichnete Punkte dynamisch verschieben mit mousedragged AWT, Swing, JavaFX & SWT 4
S inhalt dynamisch erzeugter JComboBoxs auslesen AWT, Swing, JavaFX & SWT 3
G Mousecursor selber dynamisch generieren. AWT, Swing, JavaFX & SWT 6
G JRadioButton dynamisch erzeugen AWT, Swing, JavaFX & SWT 6
M Look and Feels dynamisch abfragen AWT, Swing, JavaFX & SWT 13
S Columnname dynamisch verändern AWT, Swing, JavaFX & SWT 2
H JComboBoxen dynamisch erzeugen AWT, Swing, JavaFX & SWT 3
K toolbar dynamisch erzeugen AWT, Swing, JavaFX & SWT 2
L Komponenten dynamisch erkennen und bearbeiten AWT, Swing, JavaFX & SWT 8
H große mengen an jbuttons dynamisch erzeugen? AWT, Swing, JavaFX & SWT 15
Q Swing Fenster updaten - Hinzugefügte Komponenten darstellen AWT, Swing, JavaFX & SWT 3
P Hinzugefügte Componente ist inaktiv AWT, Swing, JavaFX & SWT 14
S JTree hinzugefügte Knoten anzeigen AWT, Swing, JavaFX & SWT 9

Ähnliche Java Themen


Oben