I'm trying to develop some sort of paint using Java.
I have a JComponent that is located inside of a JPanel.
I already can draw lines and rectangles into that JComponent.
Now, how can I export this drawings as an image (png, gif, jpg)?
I tried this:
BufferedImage b = new BufferedImage(1700,1100,BufferedImage.TYPE_INT_RGB);
this.print(getGraphics());
try{ImageIO.write(b,"png",new File("test.png"));}catch (Exception e) {}
But that only creates a .png file all black.
Help!!!
RESOLVED!!!
BufferedImage bi = new BufferedImage(this.getSize().width, this.getSize().height, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
this.paint(g); //this == JComponent
g.dispose();
try{ImageIO.write(bi,"png",new File("test.png"));}catch (Exception e) {}
First of all, print() is the incorrect method.
What I guess should work (haven't tested it yet) is:
get the BufferedImage's Graphics (b.createGraphics()) and use that graphics object to paint() your panel/component.
(e.g. yourPanel.paint(b.createGraphics());)
this is a demo:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
#SuppressWarnings("serial")
public class DrawGraph extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 800;
private static final int BORDER_GAP = 25;
private static final int PADDING = 25;
private static final Color GRAPH_COLOR = Color.green;
private static final Color GRAPH_POINT_COLOR = new Color(100, 100, 100, 180);
private static final Color GRID_COLOR = new Color(200, 200, 200, 200);
private static final Stroke GRAPH_STROKE = new BasicStroke(3f);
private static final int GRAPH_POINT_WIDTH = 4;
private static final int Y_HATCH_CNT = 10;
private List<Double> scores;
public DrawGraph(List<Double> scores2) {
this.scores = scores2;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double xScale = ((double) getWidth() - (2 * BORDER_GAP)-PADDING) / (scores.size() - 1);
double yScale = ((double) getHeight() - (2 * BORDER_GAP)-PADDING) / (getMaxScore() - getMinScore());
List<Point> graphPoints = new ArrayList<Point>();
for (int i = 0; i < scores.size(); i++) {
int x1 = (int) (i * xScale + BORDER_GAP + PADDING);
int y1 = (int) ((getMaxScore() - scores.get(i)) * yScale + BORDER_GAP);
graphPoints.add(new Point(x1, y1));
}
g2.setColor(Color.WHITE);
g2.fillRect(BORDER_GAP + PADDING, BORDER_GAP, getWidth() - (2 * BORDER_GAP) - PADDING, getHeight() - 2 * BORDER_GAP - PADDING);
g2.setColor(Color.BLACK);
g2.drawLine(BORDER_GAP + PADDING, getHeight() - BORDER_GAP - PADDING, BORDER_GAP + PADDING, BORDER_GAP);
g2.drawLine(BORDER_GAP + PADDING, getHeight() - BORDER_GAP - PADDING, getWidth() - BORDER_GAP, getHeight() - BORDER_GAP - PADDING);
for (int i = 0; i < Y_HATCH_CNT + 1; i++) {
int x0 = BORDER_GAP + PADDING;
int x1 = GRAPH_POINT_WIDTH + BORDER_GAP + PADDING;
int y0 = getHeight() - ((i * (getHeight() - BORDER_GAP * 2 - PADDING)) / Y_HATCH_CNT + BORDER_GAP + PADDING);
int y1 = y0;
if (scores.size() > 0) {
g2.setColor(GRID_COLOR);
g2.drawLine(BORDER_GAP + PADDING + 1 + GRAPH_POINT_WIDTH, y0, getWidth() - BORDER_GAP, y1);
g2.setColor(Color.BLACK);
String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 1.0) / Y_HATCH_CNT)) * 100)) / 100.0 + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(yLabel);
g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3);
}
g2.drawLine(x0, y0, x1, y1);
}
for (int i = 0; i < scores.size(); i++) {
if (scores.size() > 1) {
int x0 = i * (getWidth() - BORDER_GAP * 2 - PADDING) / (scores.size() - 1) + BORDER_GAP + PADDING;
int x1 = x0;
int y0 = getHeight() - BORDER_GAP - PADDING;
int y1 = y0 - GRAPH_POINT_WIDTH;
if ((i % ((int) ((scores.size() / 20.0)) + 1)) == 0) {
g2.setColor(GRID_COLOR);
g2.drawLine(x0, getHeight() - BORDER_GAP - PADDING - 1 - GRAPH_POINT_WIDTH, x1, BORDER_GAP);
g2.setColor(Color.BLACK);
String xLabel = i + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(xLabel);
g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3);
}
g2.drawLine(x0, y0, x1, y1);
}
}
Stroke oldStroke = g2.getStroke();
g2.setColor(GRAPH_COLOR);
g2.setStroke(GRAPH_STROKE);
for (int i = 0; i < graphPoints.size() - 1; i++) {
int x1 = graphPoints.get(i).x;
int y1 = graphPoints.get(i).y;
int x2 = graphPoints.get(i + 1).x;
int y2 = graphPoints.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g2.setStroke(oldStroke);
g2.setColor(GRAPH_POINT_COLOR);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - GRAPH_POINT_WIDTH / 2;
int y = graphPoints.get(i).y - GRAPH_POINT_WIDTH / 2;;
int ovalW = GRAPH_POINT_WIDTH;
int ovalH = GRAPH_POINT_WIDTH;
g2.fillOval(x, y, ovalW, ovalH);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private double getMinScore() {
double minScore = Double.MAX_VALUE;
for (Double score : scores) {
minScore = Math.min(minScore, score);
}
return minScore;
}
private double getMaxScore() {
double maxScore = Double.MIN_VALUE;
for (Double score : scores) {
maxScore = Math.max(maxScore, score);
}
return maxScore;
}
public static void createAndShowGui(ArrayList<Double> scores, String s) {
DrawGraph mainPanel = new DrawGraph(scores);
JFrame frame = new JFrame(s);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.getContentPane().add(new JButton(new AbstractAction("Save Image") {
#Override
public void actionPerformed(ActionEvent e) {
mainPanel.saveImage(new File("graph.png"));
}
}),BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void saveImage(File file){
BufferedImage bi = new BufferedImage(this.getSize().width, this.getSize().height, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
this.paint(g);
g.dispose();
try{
ImageIO.write(bi,"png",file);
}catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
final ArrayList<Double> inputValues = new ArrayList<Double>();
inputValues.add(1d);
inputValues.add(2d);
// Read input values from text document and store in ArrayList
SwingUtilities.invokeLater(new Runnable() {
public void run() {
DrawGraph.createAndShowGui(inputValues, "MyGraphTitle");
}
});
}
}
you can change it by youself.
Related
I am trying to code a paint like program (for fun), but to challenge myself I tried to do it using setRGB method, but I see that when I move the mouse fast the behavior of the stroke gets erratic, do you know how to "soft" the data get from methods getX and getY? or why I am getting random points colored
Thank you in advance and sorry for my english. :)
public class Canvas extends JPanel implements ActionListener, MouseMotionListener, MouseListener {
int canvasW;
int canvasH;
BufferedImage imgCanvas;
int X1;
int Y1;
int X0;
int Y0;
int sizeCanvas = 10;
int expCanvas = 2 * sizeCanvas - 1;
public Canvas(int width, int height) {
canvasH = height;
canvasW = width;
setPreferredSize(new Dimension(width, height));
setBorder(BorderFactory.createLineBorder(Color.black));
setBackground(Color.white);
CanvasImage(width, height);
addMouseListener(this);
addMouseMotionListener(this);
}
public BufferedImage CanvasImage(int width, int height) {
imgCanvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
return imgCanvas;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(imgCanvas, null, null);
}
#Override
public void actionPerformed(ActionEvent e) {
}
public void drawer() {
int deltaX = abs(X1 - X0);
int deltaY = abs(Y1 - Y0);
double m;
double b;
if (deltaX >= deltaY) {
if (deltaY == 0) {
m = 0;
} else {
m = (X0 - X1) / (Y0 - Y1);
}
b = Y0 - m * X0;
if (X1 > X0) {
for (int i = X0; i <= X1; i++) {
imgCanvas.setRGB(i, (int) (m * i + b), Color.BLACK.getRGB());
System.out.println(i + " ; " + (int) (m * i + b));
}
} else {
for (int i = X0; i >= X1; i--) {
imgCanvas.setRGB(i, (int) (m * i + b), Color.BLACK.getRGB());
System.out.println(i + " ; " + (int) (m * i + b));
}
}
} else {
if (deltaX == 0) {
m = 0;
} else {
m = (Y0 - Y1) / (X0 - X1);
}
b = X0 - m * Y0;
if (Y1 > Y0) {
for (int i = Y0; i <= Y1; i++) {
imgCanvas.setRGB((int) (m * i + b), i, Color.BLACK.getRGB());
}
} else {
for (int i = Y0; i >= Y1; i--) {
imgCanvas.setRGB((int) (m * i + b), i, Color.BLACK.getRGB());
}
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
X1 = e.getX();
Y1 = e.getY();
drawer();
repaint();
X0 = X1;
Y0 = Y1;
}
#Override
public void mousePressed(MouseEvent e) {
X0 = e.getX();
Y0 = e.getY();
}
In my program I want to draw a simple score line graph. I have a text file and on each line is an integer score, which I read in and want to pass as argument to my graph class. I'm having some trouble implementing the graph class and all the examples I've seen have their methods in the same class as their main, which I won't have.
I want to be able to pass my array to the object and generate a graph, but when calling my paint method it is asking me for a Graphics g... This is what I have so far:
public class Graph extends JPanel {
public void paintGraph (Graphics g){
ArrayList<Integer> scores = new ArrayList<Integer>(10);
Random r = new Random();
for (int i : scores){
i = r.nextInt(20);
System.out.println(r);
}
int y1;
int y2;
for (int i = 0; i < scores.size(); i++){
y1 = scores.get(i);
y2 = scores.get(i+1);
g.drawLine(i, y1, i+1, y2);
}
}
}
For now I have inserted a simple random number generator to fill up my array.
I have an existing frame and basically want to instantiate the Graph class and mount the panel onto my frame. I'm really sorry that this question seems so jumbled by the way, but I've had little sleep...
The code in my main statement is:
testFrame = new JFrame();
testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Graph graph = new Graph();
testFrame.add(graph);
I'm not sure exactly what an SSCE is but this is my attempt at one:
public class Test {
JFrame testFrame;
public Test() {
testFrame = new JFrame();
testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Graph graph = new Graph();
testFrame.add(graph);
testFrame.setBounds(100, 100, 764, 470);
testFrame.setVisible(true);
}
Graph.java
public class Graph extends JPanel {
public Graph() {
setSize(500, 500);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D gr = (Graphics2D) g; // This is if you want to use Graphics2D
// Now do the drawing here
ArrayList<Integer> scores = new ArrayList<Integer>(10);
Random r = new Random();
for (int i : scores) {
i = r.nextInt(20);
System.out.println(r);
}
int y1;
int y2;
for (int i = 0; i < scores.size() - 1; i++) {
y1 = (scores.get(i)) * 10;
y2 = (scores.get(i + 1)) * 10;
gr.drawLine(i * 10, y1, (i + 1) * 10, y2);
}
}
}
Problems with your code and suggestions:
Again you need to change the preferredSize of the component (here the Graph JPanel), not the size
Don't set the JFrame's bounds.
Call pack() on your JFrame after adding components to it and before calling setVisible(true)
Your foreach loop won't work since the size of your ArrayList is 0 (test it to see that this is correct). Instead use a for loop going from 0 to 10.
You should not have program logic inside of your paintComponent(...) method but only painting code. So I would make the ArrayList a class variable and fill it inside of the class's constructor.
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawGraph extends JPanel {
private static final int MAX_SCORE = 20;
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final int BORDER_GAP = 30;
private static final Color GRAPH_COLOR = Color.green;
private static final Color GRAPH_POINT_COLOR = new Color(150, 50, 50, 180);
private static final Stroke GRAPH_STROKE = new BasicStroke(3f);
private static final int GRAPH_POINT_WIDTH = 12;
private static final int Y_HATCH_CNT = 10;
private List<Integer> scores;
public DrawGraph(List<Integer> scores) {
this.scores = scores;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double xScale = ((double) getWidth() - 2 * BORDER_GAP) / (scores.size() - 1);
double yScale = ((double) getHeight() - 2 * BORDER_GAP) / (MAX_SCORE - 1);
List<Point> graphPoints = new ArrayList<Point>();
for (int i = 0; i < scores.size(); i++) {
int x1 = (int) (i * xScale + BORDER_GAP);
int y1 = (int) ((MAX_SCORE - scores.get(i)) * yScale + BORDER_GAP);
graphPoints.add(new Point(x1, y1));
}
// create x and y axes
g2.drawLine(BORDER_GAP, getHeight() - BORDER_GAP, BORDER_GAP, BORDER_GAP);
g2.drawLine(BORDER_GAP, getHeight() - BORDER_GAP, getWidth() - BORDER_GAP, getHeight() - BORDER_GAP);
// create hatch marks for y axis.
for (int i = 0; i < Y_HATCH_CNT; i++) {
int x0 = BORDER_GAP;
int x1 = GRAPH_POINT_WIDTH + BORDER_GAP;
int y0 = getHeight() - (((i + 1) * (getHeight() - BORDER_GAP * 2)) / Y_HATCH_CNT + BORDER_GAP);
int y1 = y0;
g2.drawLine(x0, y0, x1, y1);
}
// and for x axis
for (int i = 0; i < scores.size() - 1; i++) {
int x0 = (i + 1) * (getWidth() - BORDER_GAP * 2) / (scores.size() - 1) + BORDER_GAP;
int x1 = x0;
int y0 = getHeight() - BORDER_GAP;
int y1 = y0 - GRAPH_POINT_WIDTH;
g2.drawLine(x0, y0, x1, y1);
}
Stroke oldStroke = g2.getStroke();
g2.setColor(GRAPH_COLOR);
g2.setStroke(GRAPH_STROKE);
for (int i = 0; i < graphPoints.size() - 1; i++) {
int x1 = graphPoints.get(i).x;
int y1 = graphPoints.get(i).y;
int x2 = graphPoints.get(i + 1).x;
int y2 = graphPoints.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g2.setStroke(oldStroke);
g2.setColor(GRAPH_POINT_COLOR);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - GRAPH_POINT_WIDTH / 2;
int y = graphPoints.get(i).y - GRAPH_POINT_WIDTH / 2;;
int ovalW = GRAPH_POINT_WIDTH;
int ovalH = GRAPH_POINT_WIDTH;
g2.fillOval(x, y, ovalW, ovalH);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
List<Integer> scores = new ArrayList<Integer>();
Random random = new Random();
int maxDataPoints = 16;
int maxScore = 20;
for (int i = 0; i < maxDataPoints ; i++) {
scores.add(random.nextInt(maxScore));
}
DrawGraph mainPanel = new DrawGraph(scores);
JFrame frame = new JFrame("DrawGraph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which will create a graph that looks like so:
Just complementing Hovercraft Full Of Eels's solution:
I reworked his code, tweaked it a bit, adding a grid, axis labels and now the Y-axis goes from the minimum value present up to the maximum value. I planned on adding a couple of getters/setters but I didn't need them, you can add them if you want.
Here is the Gist link, I'll also paste the code below: GraphPanel on Gist
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GraphPanel extends JPanel {
private int width = 800;
private int heigth = 400;
private int padding = 25;
private int labelPadding = 25;
private Color lineColor = new Color(44, 102, 230, 180);
private Color pointColor = new Color(100, 100, 100, 180);
private Color gridColor = new Color(200, 200, 200, 200);
private static final Stroke GRAPH_STROKE = new BasicStroke(2f);
private int pointWidth = 4;
private int numberYDivisions = 10;
private List<Double> scores;
public GraphPanel(List<Double> scores) {
this.scores = scores;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (scores.size() - 1);
double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore());
List<Point> graphPoints = new ArrayList<>();
for (int i = 0; i < scores.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - scores.get(i)) * yScale + padding);
graphPoints.add(new Point(x1, y1));
}
// draw white background
g2.setColor(Color.WHITE);
g2.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding - labelPadding);
g2.setColor(Color.BLACK);
// create hatch marks and grid lines for y axis.
for (int i = 0; i < numberYDivisions + 1; i++) {
int x0 = padding + labelPadding;
int x1 = pointWidth + padding + labelPadding;
int y0 = getHeight() - ((i * (getHeight() - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding);
int y1 = y0;
if (scores.size() > 0) {
g2.setColor(gridColor);
g2.drawLine(padding + labelPadding + 1 + pointWidth, y0, getWidth() - padding, y1);
g2.setColor(Color.BLACK);
String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 1.0) / numberYDivisions)) * 100)) / 100.0 + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(yLabel);
g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3);
}
g2.drawLine(x0, y0, x1, y1);
}
// and for x axis
for (int i = 0; i < scores.size(); i++) {
if (scores.size() > 1) {
int x0 = i * (getWidth() - padding * 2 - labelPadding) / (scores.size() - 1) + padding + labelPadding;
int x1 = x0;
int y0 = getHeight() - padding - labelPadding;
int y1 = y0 - pointWidth;
if ((i % ((int) ((scores.size() / 20.0)) + 1)) == 0) {
g2.setColor(gridColor);
g2.drawLine(x0, getHeight() - padding - labelPadding - 1 - pointWidth, x1, padding);
g2.setColor(Color.BLACK);
String xLabel = i + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(xLabel);
g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3);
}
g2.drawLine(x0, y0, x1, y1);
}
}
// create x and y axes
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding);
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding);
Stroke oldStroke = g2.getStroke();
g2.setColor(lineColor);
g2.setStroke(GRAPH_STROKE);
for (int i = 0; i < graphPoints.size() - 1; i++) {
int x1 = graphPoints.get(i).x;
int y1 = graphPoints.get(i).y;
int x2 = graphPoints.get(i + 1).x;
int y2 = graphPoints.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g2.setStroke(oldStroke);
g2.setColor(pointColor);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - pointWidth / 2;
int y = graphPoints.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
g2.fillOval(x, y, ovalW, ovalH);
}
}
// #Override
// public Dimension getPreferredSize() {
// return new Dimension(width, heigth);
// }
private double getMinScore() {
double minScore = Double.MAX_VALUE;
for (Double score : scores) {
minScore = Math.min(minScore, score);
}
return minScore;
}
private double getMaxScore() {
double maxScore = Double.MIN_VALUE;
for (Double score : scores) {
maxScore = Math.max(maxScore, score);
}
return maxScore;
}
public void setScores(List<Double> scores) {
this.scores = scores;
invalidate();
this.repaint();
}
public List<Double> getScores() {
return scores;
}
private static void createAndShowGui() {
List<Double> scores = new ArrayList<>();
Random random = new Random();
int maxDataPoints = 40;
int maxScore = 10;
for (int i = 0; i < maxDataPoints; i++) {
scores.add((double) random.nextDouble() * maxScore);
// scores.add((double) i);
}
GraphPanel mainPanel = new GraphPanel(scores);
mainPanel.setPreferredSize(new Dimension(800, 600));
JFrame frame = new JFrame("DrawGraph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
It looks like this:
Or simply use the JFreechart library - http://www.jfree.org/jfreechart/ .
There exist many open source projects that handle all the drawing of line charts for you with a couple of lines of code. Here's how you can draw a line chart from data in a couple text (CSV) file with the XChart library. Disclaimer: I'm the lead developer of the project.
In this example, two text files exist in ./CSV/CSVChartRows/. Notice that each row in the files represents a data point to be plotted and that each file represents a different series. series1 contains x, y, and error bar data, whereas series2 contains just x and y, data.
series1.csv
1,12,1.4
2,34,1.12
3,56,1.21
4,47,1.5
series2.csv
1,56
2,34
3,12
4,26
Source Code
public class CSVChartRows {
public static void main(String[] args) throws Exception {
// import chart from a folder containing CSV files
XYChart chart = CSVImporter.getChartFromCSVDir("./CSV/CSVChartRows/", DataOrientation.Rows, 600, 400);
// Show it
new SwingWrapper(chart).displayChart();
}
}
Resulting Plot
Override the paintComponent method of your panel so you can custom draw. Like this:
#Override
public void paintComponent(Graphics g) {
Graphics2D gr = (Graphics2D) g; //this is if you want to use Graphics2D
//now do the drawing here
...
}
Hovercraft Full Of Eels' answer is very good, but i had to change it a bit in order to get it working on my program:
int y1 = (int) ((this.height - 2 * BORDER_GAP) - (values.get(i) * yScale - BORDER_GAP));
instead of
int y1 = (int) (scores.get(i) * yScale + BORDER_GAP);
because if i used his way the graphic would be upside down
(you'd see it if you used hardcoded values (e.g 1,3,5,7,9) instead of random values)
I have like total of 500 array list in my program as HashMap and want to generate graph for each list (500 graphs in total). I used the below code to draw a single graph..
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawGraph extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 800;
private static final int BORDER_GAP = 25;
private static final int PADDING = 25;
private static final Color GRAPH_COLOR = Color.green;
private static final Color GRAPH_POINT_COLOR = new Color(100, 100, 100, 180);
private static final Color GRID_COLOR = new Color(200, 200, 200, 200);
private static final Stroke GRAPH_STROKE = new BasicStroke(3f);
private static final int GRAPH_POINT_WIDTH = 4;
private static final int Y_HATCH_CNT = 10;
private List<Double> scores;
public DrawGraph(List<Double> scores2) {
this.scores = scores2;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double xScale = ((double) getWidth() - (2 * BORDER_GAP)-PADDING) / (scores.size() - 1);
double yScale = ((double) getHeight() - (2 * BORDER_GAP)-PADDING) / (getMaxScore() - getMinScore());
List<Point> graphPoints = new ArrayList<Point>();
for (int i = 0; i < scores.size(); i++) {
int x1 = (int) (i * xScale + BORDER_GAP + PADDING);
int y1 = (int) ((getMaxScore() - scores.get(i)) * yScale + BORDER_GAP);
graphPoints.add(new Point(x1, y1));
}
g2.setColor(Color.WHITE);
g2.fillRect(BORDER_GAP + PADDING, BORDER_GAP, getWidth() - (2 * BORDER_GAP) - PADDING, getHeight() - 2 * BORDER_GAP - PADDING);
g2.setColor(Color.BLACK);
g2.drawLine(BORDER_GAP + PADDING, getHeight() - BORDER_GAP - PADDING, BORDER_GAP + PADDING, BORDER_GAP);
g2.drawLine(BORDER_GAP + PADDING, getHeight() - BORDER_GAP - PADDING, getWidth() - BORDER_GAP, getHeight() - BORDER_GAP - PADDING);
for (int i = 0; i < Y_HATCH_CNT + 1; i++) {
int x0 = BORDER_GAP + PADDING;
int x1 = GRAPH_POINT_WIDTH + BORDER_GAP + PADDING;
int y0 = getHeight() - ((i * (getHeight() - BORDER_GAP * 2 - PADDING)) / Y_HATCH_CNT + BORDER_GAP + PADDING);
int y1 = y0;
if (scores.size() > 0) {
g2.setColor(GRID_COLOR);
g2.drawLine(BORDER_GAP + PADDING + 1 + GRAPH_POINT_WIDTH, y0, getWidth() - BORDER_GAP, y1);
g2.setColor(Color.BLACK);
String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 1.0) / Y_HATCH_CNT)) * 100)) / 100.0 + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(yLabel);
g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3);
}
g2.drawLine(x0, y0, x1, y1);
}
for (int i = 0; i < scores.size(); i++) {
if (scores.size() > 1) {
int x0 = i * (getWidth() - BORDER_GAP * 2 - PADDING) / (scores.size() - 1) + BORDER_GAP + PADDING;
int x1 = x0;
int y0 = getHeight() - BORDER_GAP - PADDING;
int y1 = y0 - GRAPH_POINT_WIDTH;
if ((i % ((int) ((scores.size() / 20.0)) + 1)) == 0) {
g2.setColor(GRID_COLOR);
g2.drawLine(x0, getHeight() - BORDER_GAP - PADDING - 1 - GRAPH_POINT_WIDTH, x1, BORDER_GAP);
g2.setColor(Color.BLACK);
String xLabel = i + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(xLabel);
g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3);
}
g2.drawLine(x0, y0, x1, y1);
}
}
Stroke oldStroke = g2.getStroke();
g2.setColor(GRAPH_COLOR);
g2.setStroke(GRAPH_STROKE);
for (int i = 0; i < graphPoints.size() - 1; i++) {
int x1 = graphPoints.get(i).x;
int y1 = graphPoints.get(i).y;
int x2 = graphPoints.get(i + 1).x;
int y2 = graphPoints.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g2.setStroke(oldStroke);
g2.setColor(GRAPH_POINT_COLOR);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - GRAPH_POINT_WIDTH / 2;
int y = graphPoints.get(i).y - GRAPH_POINT_WIDTH / 2;;
int ovalW = GRAPH_POINT_WIDTH;
int ovalH = GRAPH_POINT_WIDTH;
g2.fillOval(x, y, ovalW, ovalH);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private double getMinScore() {
double minScore = Double.MAX_VALUE;
for (Double score : scores) {
minScore = Math.min(minScore, score);
}
return minScore;
}
private double getMaxScore() {
double maxScore = Double.MIN_VALUE;
for (Double score : scores) {
maxScore = Math.max(maxScore, score);
}
return maxScore;
}
public static void createAndShowGui(ArrayList<Double> scores, String s) {
DrawGraph mainPanel = new DrawGraph(scores);
JFrame frame = new JFrame(s);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String args[]) {
final ArrayList<Double> inputValues = new ArrayList<Double>();
// Read input values from text document and store in ArrayList
SwingUtilities.invokeLater(new Runnable() {
public void run() {
DrawGraph.createAndShowGui(inputValues, "MyGraphTitle");
}
});
}
}
When i provided 20 sample array list as input it plot and displays 20 graphs correctly..But i want to save the graph as an image in my system without displaying it as a separate window since when plotting 500 graphs i dont want to open 500 windows. Is there any option to save the graph as image after plotting it.? I checked few methods online but im not sure how to integrate the saving as image code with this particular graph generation code that uses 2D Graphics.
I've been trying for hours to find the solution but with no results, so I have nowhere else to turn. I have a program that gathers data from user input and uses it to draw a graph. Every time the user changes the data in the text fields and presses submit I want a new graph drawn and get rid of the old one.
Currently nothing happens with the graph when I press submit with new inputs even though the inputs do change in both classes. For debugging purposes I had a
System.out.println(graphPoints.size());
in my DrawComponent class. I noticed that for everytime I press submit the amount of times graphPoints.size() gets printed out increases with one, so I assume thats no good. I really dont know where to go from here though.
Here is my actionlistener where I call the GraphPanel class:
query.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
textarea1.setText("");
textarea1.append(run(tickerInput,tickerInput2,startInput,slutInput,valuta));
Mainpanel.repaint();
if(testx != null)
testx.removeAll();
testx = new GraphPanel(first,second);
addItem(Mainpanel, testx, 0,20, 20,20, GridBagConstraints.SOUTH);
minframe.setVisible(true);
minframe.repaint();
minframe.pack();
testx.repaint();
And here is my GraphPanel class:
public GraphPanel(ArrayList<Double> first, ArrayList<Double> second) {
first1 = first;
Collections.reverse(first1);
second1 = second;
Collections.reverse(second1);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (first1.size() - 1);
double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore());
ArrayList<Point> graphPoints = new ArrayList<>();
for (int i = 0; i < first1.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - first1.get(i)) * yScale + padding);
graphPoints.add(new Point(x1, y1));
}
ArrayList<Point> graphPoints2 = new ArrayList<>();
graphPoints2.clear();
for (int i = 0; i < second1.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - second1.get(i)) * yScale + padding);
graphPoints2.add(new Point(x1, y1));
}
g2.setColor(Color.WHITE);
g2.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding - labelPadding);
g2.setColor(Color.BLACK);
for (int i = 0; i < numberYDivisions + 1; i++) {
int x0 = padding + labelPadding;
int x1 = pointWidth + padding + labelPadding;
int y0 = getHeight() - ((i * (getHeight() - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding);
int y1 = y0;
if (first1.size() > 0) {
g2.setColor(gridColor);
g2.drawLine(padding + labelPadding + 1 + pointWidth, y0, getWidth() - padding, y1);
g2.setColor(Color.BLACK);
String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 1.0) / numberYDivisions)) * 100)) / 100.0 + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(yLabel);
g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3);
}
g2.drawLine(x0, y0, x1, y1);
}
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding);
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding);
Graphics g3 = g2;
Stroke oldStroke = g2.getStroke();
g2.setColor(lineColor);
g2.setStroke(GRAPH_STROKE);
System.out.println(graphPoints.size());
for (int i = 0; i < graphPoints.size() - 1; i++) {
int x1 = graphPoints.get(i).x;
int y1 = graphPoints.get(i).y;
int x2 = graphPoints.get(i + 1).x;
int y2 = graphPoints.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g3.setColor(Color.PINK);
for (int i = 0; i < graphPoints2.size() - 1; i++) {
int x1 = graphPoints2.get(i).x;
int y1 = graphPoints2.get(i).y;
int x2 = graphPoints2.get(i + 1).x;
int y2 = graphPoints2.get(i + 1).y;
g3.drawLine(x1, y1, x2, y2);
}
g2.setStroke(oldStroke);
g2.setColor(pointColor);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - pointWidth / 2;
int y = graphPoints.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
g2.fillOval(x, y, ovalW, ovalH);
}
for (int i = 0; i < graphPoints2.size(); i++) {
int x = graphPoints2.get(i).x - pointWidth / 2;
int y = graphPoints2.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
g3.fillOval(x, y, ovalW, ovalH);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, heigth);
}
private double getMinScore() {
double minScore =0;
if (Collections.min(first1)<=Collections.max(second1)){
minScore= Collections.min(first1)-10;
}
else{
minScore = Collections.min(second1)-10;
}
return minScore;
}
private double getMaxScore() {
double maxScore =0;
if (Collections.max(first1)>=Collections.max(second1)){
maxScore= Collections.max(first1)+10;
}
else{
maxScore = Collections.max(second1)+10;
}
return maxScore;
}
Sorry for the wall of code, I couldn't decide what was relevant and what isn't.
The main clue here is the repeated messages. Either paintComponent is getting called a bunch of times, or you have a bunch of components getting painted. From this block in the action listener, it looks like the later:
if(testx != null)
testx.removeAll();
testx = new GraphPanel(first,second);
addItem(Mainpanel, testx, 0,20, 20,20, GridBagConstraints.SOUTH);
It removes all of the children from testx, then makes a new one and adds it to Mainpanel. What it doesn't do is remove the old testx from Mainpanel, so they're building up.
I'm looking for an example of a real-time graph data visualizatior in Java, but i've only found this one, and it's not a dynamic real time visualizator:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GraphPanel extends JPanel {
private int width = 800;
private int heigth = 400;
private int padding = 25;
private int labelPadding = 25;
private Color lineColor = new Color(44, 102, 230, 180);
private Color pointColor = new Color(100, 100, 100, 180);
private Color gridColor = new Color(200, 200, 200, 200);
private static final Stroke GRAPH_STROKE = new BasicStroke(2f);
private int pointWidth = 4;
private int numberYDivisions = 10;
private List<Double> scores;
public GraphPanel(List<Double> scores) {
this.scores = scores;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (scores.size() - 1);
double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore());
List<Point> graphPoints = new ArrayList<>();
for (int i = 0; i < scores.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - scores.get(i)) * yScale + padding);
graphPoints.add(new Point(x1, y1));
}
// draw white background
g2.setColor(Color.WHITE);
g2.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding - labelPadding);
g2.setColor(Color.BLACK);
// create hatch marks and grid lines for y axis.
for (int i = 0; i < numberYDivisions + 1; i++) {
int x0 = padding + labelPadding;
int x1 = pointWidth + padding + labelPadding;
int y0 = getHeight() - ((i * (getHeight() - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding);
int y1 = y0;
if (scores.size() > 0) {
g2.setColor(gridColor);
g2.drawLine(padding + labelPadding + 1 + pointWidth, y0, getWidth() - padding, y1);
g2.setColor(Color.BLACK);
String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 1.0) / numberYDivisions)) * 100)) / 100.0 + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(yLabel);
g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3);
}
g2.drawLine(x0, y0, x1, y1);
}
// and for x axis
for (int i = 0; i < scores.size(); i++) {
if (scores.size() > 1) {
int x0 = i * (getWidth() - padding * 2 - labelPadding) / (scores.size() - 1) + padding + labelPadding;
int x1 = x0;
int y0 = getHeight() - padding - labelPadding;
int y1 = y0 - pointWidth;
if ((i % ((int) ((scores.size() / 20.0)) + 1)) == 0) {
g2.setColor(gridColor);
g2.drawLine(x0, getHeight() - padding - labelPadding - 1 - pointWidth, x1, padding);
g2.setColor(Color.BLACK);
String xLabel = i + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(xLabel);
g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3);
}
g2.drawLine(x0, y0, x1, y1);
}
}
// create x and y axes
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding);
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding);
Stroke oldStroke = g2.getStroke();
g2.setColor(lineColor);
g2.setStroke(GRAPH_STROKE);
for (int i = 0; i < graphPoints.size() - 1; i++) {
int x1 = graphPoints.get(i).x;
int y1 = graphPoints.get(i).y;
int x2 = graphPoints.get(i + 1).x;
int y2 = graphPoints.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g2.setStroke(oldStroke);
g2.setColor(pointColor);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - pointWidth / 2;
int y = graphPoints.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
g2.fillOval(x, y, ovalW, ovalH);
}
}
// #Override
// public Dimension getPreferredSize() {
// return new Dimension(width, heigth);
// }
private double getMinScore() {
double minScore = Double.MAX_VALUE;
for (Double score : scores) {
minScore = Math.min(minScore, score);
}
return minScore;
}
private double getMaxScore() {
double maxScore = Double.MIN_VALUE;
for (Double score : scores) {
maxScore = Math.max(maxScore, score);
}
return maxScore;
}
public void setScores(List<Double> scores) {
this.scores = scores;
invalidate();
this.repaint();
}
public List<Double> getScores() {
return scores;
}
private static void createAndShowGui() {
List<Double> scores = new ArrayList<>();
Random random = new Random();
int maxDataPoints = 40;
int maxScore = 10;
for (int i = 0; i < maxDataPoints; i++) {
scores.add((double) random.nextDouble() * maxScore);
// scores.add((double) i);
}
GraphPanel mainPanel = new GraphPanel(scores);
mainPanel.setPreferredSize(new Dimension(800, 600));
JFrame frame = new JFrame("DrawGraph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
This is the output:
What i need is something like this:
Does anyone knows how to do it?