Wykres x-y i obracający się tekst etykiety osi

Poniższy kod przedstawia kilka prostych danych x-y, ale ma dwa problemy, których nie wiem, jak naprawić.

Najpierw wykreśla wartości ujemne dla niektórych punktów danych, co oznacza linie rozciągające się na południe poniżej osi x. Ponieważ punkty danych są wybierane losowo, być może trzeba będzie nieco zmienić rozmiar ramki, aby wyświetlić nowe liczby losowe, które zostaną wykreślone w sposób, który pokazuje ten błąd. Wszystkie wartości danych będą dodatnie, więc chcę, aby wszystkie odchylenia były rzutowane na północ powyżej niebieskiej dolnej linii znacznika i muszę się upewnić, że żadne odchylenia nie rozciągają się na południe poniżej niebieskiej dolnej linii znacznika.

Po drugie, etykieta na osi Y zajmuje zbyt dużo miejsca na ekranie. Musi być obrócony o 90 stopni. Jednak wszystkie przykłady, które widziałem, dotyczą obracania całego panelu za pomocą obiektu graphics2d. Nie chcę obracać całego panelu. Zamiast tego chcę po prostu obrócić tekst etykiety osi y.

Czy ktoś może mi pokazać, jak zmienić poniższy kod, aby naprawić te dwa konkretne problemy?

Kod znajduje się w następujących dwóch plikach:

GUI.java

import java.awt.*;
import javax.swing.*;

class GUI{

GUI() { 
    // Create a new JFrame container. 
    JFrame jfrm = new JFrame("X-Y Plot"); 
    // Specify FlowLayout for the layout manager. 
    jfrm.getContentPane().setLayout(new FlowLayout()); 
    int frameHeight = 400;
    int frameWidth = 300;
    // Give the frame an initial size. 
    jfrm.setSize(frameWidth, frameHeight);

    // Terminate the program when the user closes the application. 
    jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    // Create a text-based label.
    JVertLabel myVLabel = new JVertLabel("y-axis label");
    int width = myVLabel.WIDTH;

    PaintPanel myPP = new PaintPanel(frameWidth-width-50-20,frameHeight-70);
    jfrm.add(myPP);

    jfrm.add(myVLabel);// Add the label to the frame.

    // Display the frame. 
    jfrm.setVisible(true); 
} 

public static void main(String args[]) { 
    // Create the frame on the event dispatching thread.
    SwingUtilities.invokeLater(new Runnable() {public void run(){new GUI();}});
}

    public class JVertLabel extends JComponent {

        private String text;

        public JVertLabel(String s) {
            text = s;
        }//constructor

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.rotate(Math.toRadians(-90));
            g2d.drawString(text, 0, 0);
        }
    }
}

PaintPanel.java

import java.awt.*;
import javax.swing.*;   
import java.util.*;

class PaintPanel extends JPanel {

    Insets ins; // holds the panel's insets 
    Random rand; // used to generate random numbers 

    PaintPanel(int w, int h) {
        setOpaque(true);// Ensure that panel is opaque.
        setPreferredSize(new Dimension(w, h));// Set preferred dimension as specfied. 
        rand = new Random();
    }

    protected void paintComponent(Graphics g) {// Override paintComponent() method.
        super.paintComponent(g);// Always call superclass method first.
        int height = getHeight();// Get height of component.
        int width = getWidth();// Get width of component.
        ins = getInsets();// Get the insets.
        // Get dimensions of text
        Graphics2D g2d = (Graphics2D) g;
        Font font = new Font("Serif", Font.PLAIN, 12);
        FontMetrics fontMetrics = g2d.getFontMetrics();
        String xString = ("x-axis label");
        int xStrWidth = fontMetrics.stringWidth(xString);
        int xStrHeight = fontMetrics.getHeight();
        String yString = "y-axis-label";
        int yStrWidth = fontMetrics.stringWidth(yString);
        int yStrHeight = fontMetrics.getHeight();
        int leftStartPlotWindow = ins.left + 5 + yStrWidth;
        int hPad = 3;

        // Fill panel by plotting random data in a bar graph. 
        for (int i = leftStartPlotWindow + hPad; i <= width - leftStartPlotWindow - hPad + yStrWidth + 1; i += 4) {
            int h = Math.abs(rand.nextInt(height - ins.bottom));//Get rand# betw/0 and max height of drawing area.
            // If generated value w/in or too close to border, change it to just outside border.
            if (h <= ins.top) {
                h = ins.top + 1;
            }
            g.drawLine(i, Math.abs(height - ins.bottom - xStrHeight - 5), i, h);// Draw a line that represents data.
        }
        g.setColor(Color.blue);
        g.drawRect(leftStartPlotWindow, ins.bottom + 2, width - leftStartPlotWindow - ins.right - hPad, height - xStrHeight - 6);
        g.setColor(Color.red);
        g.drawRect(ins.left, ins.bottom, width - ins.left - 1, height - ins.bottom - 1);
        g.drawString(xString, (width / 2) - (xStrWidth / 2), height - ins.bottom - 6);
        g.drawString(yString, ins.left, height / 2);
    }
}

person CodeMed    schedule 20.12.2011    source źródło
comment
+1 dla sscce.   -  person trashgod    schedule 20.12.2011


Odpowiedzi (2)


Wszystkie wartości danych będą dodatnie, więc chcę, aby wszystkie odchylenia były rzutowane na północ powyżej niebieskiej dolnej linii znacznika i muszę się upewnić, że żadne odchylenia nie rozciągają się na południe poniżej niebieskiej dolnej linii znacznika.

Musisz obliczyć losową wysokość, aby wszystkie wartości zmieściły się w dostępnej przestrzeni. Tak więc obliczenie wyglądałoby mniej więcej tak:

int randomHeight = panelHeight - offset.top - offset.bottom - heightForTheXAxisText;

Wtedy nie musisz się martwić o wartości ujemne lub górną część linii wychodzącą poza granice panelu.

wszystkie przykłady, które widziałem, dotyczą obracania całego panelu za pomocą obiektu graphics2d. Nie chcę obracać całego panelu. Zamiast tego chcę po prostu obrócić tekst etykiety osi y.

Ustaw obrót obiektu Graphics, narysuj tekst, a następnie przywróć obrót obiektu Graphics z powrotem do 0.

Lub tworzysz nowy obiekt Graphcis z bieżącego obiektu Graphics, następnie stosujesz obrót, rysujesz tekst, a następnie usuwasz tymczasowy obiekt Graphics.

person camickr    schedule 20.12.2011

JFreeChart domyślnie rozwiązuje oba problemy, jak pokazano w tym przykład.

W twoim przykładzie

  1. Będziesz musiał utworzyć model danych, zanim spróbujesz go wyrenderować. Następnie możesz zeskanować go pod kątem min i maks, aby określić limity swojej zakres oś. List<Double> może być odpowiednim wyborem.

  2. Możesz obrócić etykietę zakresu, zmieniając AffineTransform kontekstu graficznego, jak pokazano na RotateText.

person trashgod    schedule 20.12.2011
comment
+1 za próbę pomocy. Nie używam JFreeChart z powodów licencyjnych. Ale przeczytałem artykuły, które wysłałeś. Dziękuję Ci. - person CodeMed; 20.12.2011