Reputation: 9191
The code below plots some simple x-y data, but it has two problems that I do not know how to fix.
First, it plots negative values for some of the data points, which means lines extending southward below the x-axis. Since the data points are selected at random, you may have to resize the frame a bit in order to view new random numbers to be plotted in a way that shows this bug. All data values will be positive, so I want all deflections to project northward above the blue bottom marker line, and I need to make sure that no deflections extend southward below the blue bottom marker line.
Second, the y-axis label takes up too much real estate on the screen. It needs to be rotated -90 degrees. However, all the examples I have seen for this involve rotating the entire panel using a graphics2d object. I do not want to rotate the entire panel. Instead, I just want to rotate the text of the y-axis label.
Can anyone show me how to change the code below to fix these two specific problems?
The code is in the following two files:
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);
}
}
Upvotes: 3
Views: 3496
Reputation: 324118
All data values will be positive, so I want all deflections to project northward above the blue bottom marker line, and I need to make sure that no deflections extend southward below the blue bottom marker line.
You need to calculate the random height so that all values fit into the space available. So the calculation would be something like:
int randomHeight = panelHeight - offset.top - offset.bottom - heightForTheXAxisText;
Then you don't have to worry about negative values or the top of the line extending outside the bounds of the panel.
all the examples I have seen for this involve rotating the entire panel using a graphics2d object. I do not want to rotate the entire panel. Instead, I just want to rotate the text of the y-axis label.
Set the rotation of the Graphics object, the draw the text, then restore the rotation of the Graphics object back to 0.
Or, you create create a new Graphcis object from the current Graphics object, then apply the rotation, draw the text and then dispose of the temporaray Graphics object.
Upvotes: 3
Reputation: 205785
JFreeChart
addresses both issues by default, as shown in this example.
In your example,
You'll have to create the data model before trying to render it. Then you can scan it for min and max to determine the limits of your range axis. List<Double>
may be a suitable choice.
You can rotate the range label by altering the graphics context's AffineTransform
, as shown in RotateText
.
Upvotes: 2