Reputation: 2221
In my main project I have a class which plots an Histogram in a frame using JFreeChart. From that frame I want to be able to replot the histogram with the number of bins the user wants.
In order to do that I've added a menu with a textfield and a button where the user can choose the number of bins. When he presses the button the whole frame get's repolted with the new number of bins.
My problem is that it just won't be ploted, the old frame gets disposed but instead of plotting something it just creates an empty frame. I don't get any error or exception so I've not idea where the problem can be. I suspect it has something to do with the JChart class or dataset but I can't find any information of what exactly isn't working.
I've tried to create a MCVE code from my code. From three tiff images called:
"IMG_7911.CR2.R.TIFF", "IMG_7911.CR2.G.TIFF", "IMG_7911.CR2.B.TIFF"
(doesn't matter for the question how they look like, they all could be the same image) I create an histogram with a default bin size 2^16=16384, 16 bits. Then I want the user to be able to change the size from a menu. To do that I use the method "changeBinsSize" and "reDisplay":
package mcve;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Paint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.statistics.HistogramDataset;
public class HistogramRAW {
private int BINS;
private Raster raster;//Load image
private String filename;
private RenderedImage image;
private JFreeChart chart; //Create histogram
private ChartPanel panel;
private HistogramDataset dataset;
private XYBarRenderer renderer;
private JMenuBar menuBar; //Menubar
private JMenu options;
private JTextField numBINS;
private JFrame f; //Frame
public HistogramRAW(String filename) {
this.filename = filename;
this.BINS = 16384;
}
private void getImage(String filename) {
try {
URL url = new URL(filename);
final BufferedImage bi = ImageIO.read(url);
raster=bi.getRaster();
image=(RenderedImage)bi;
} catch (IOException e) {
e.printStackTrace(System.err);
return;
}
}
private ChartPanel createChartPanel() {
// dataset
dataset = new HistogramDataset();
getImage(filename); //Put it here to get width and height from it
final int w = image.getWidth();
final int h = image.getHeight();
double[] buffer = new double[w * h];
//R
buffer = raster.getSamples(0, 0, w, h, 0, buffer);
dataset.addSeries("red", buffer, BINS);
//G
getImage(filename);
buffer = raster.getSamples(0, 0, w, h, 0, buffer);
dataset.addSeries("green", buffer, BINS);
//B
getImage(filename);
buffer = raster.getSamples(0, 0, w, h, 0, buffer);
dataset.addSeries("blue", buffer, BINS);
//chart
chart = ChartFactory.createHistogram("Histogram", "",
"", dataset, PlotOrientation.VERTICAL, false, true, false);
//Set colors
XYPlot plot = (XYPlot) chart.getPlot();
renderer = (XYBarRenderer) plot.getRenderer();
renderer.setBarPainter(new StandardXYBarPainter());
Paint[] paintArray = { // translucent red, green blue
new Color(0x800000ff, true),//blue
new Color(0x8000ff00, true),//green1
new Color(0x80ff0000, true)//red
};
plot.setDrawingSupplier(new DefaultDrawingSupplier(
paintArray,
DefaultDrawingSupplier.DEFAULT_FILL_PAINT_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE));
//Create panel with chart
panel = new ChartPanel(chart);
panel.setMouseWheelEnabled(true);
return panel;
}
private JMenuBar setMenuBar() {
menuBar = new JMenuBar(); //Create Menubar
options = new JMenu("Options"); // menu.
options.setMnemonic(KeyEvent.VK_O);
menuBar.add(options);
JPanel binsPanel = new JPanel(); //Change BINS size button
numBINS = new JTextField("" + BINS);
binsPanel.add(numBINS);
JButton binsButton = new JButton("changeBins");
binsButton.addActionListener(new MenuActionListener());
binsPanel.add(binsButton);
options.add(binsPanel);
return menuBar;
}
public void display() throws CloneNotSupportedException {
f = new JFrame("Histogram");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.add(createChartPanel(), BorderLayout.CENTER);
f.setJMenuBar(setMenuBar());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public void reDisplay() throws CloneNotSupportedException {
f.add(createChartPanel(), BorderLayout.CENTER);
f.setJMenuBar(setMenuBar());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public void changeBinsSize() {
try {
BINS = Integer.parseInt(numBINS.getText());
f.removeAll();
f.dispose();
System.out.println("" + BINS);
reDisplay();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
HistogramRAW hist = new HistogramRAW("https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Wikipedia-logo-v2.svg/245px-Wikipedia-logo-v2.svg.png");
hist.display();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
private class MenuActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("changeBins")) {
changeBinsSize();
}
}
}
}
Update: I modified the code to download a random photo instead of the tiff and all channels are the same photo.
Can anyone see what am I doing wrong?, I've been for hours trying to see what's wrong but I can't find anything.
Upvotes: 3
Views: 414
Reputation: 205855
Your present implementation of changeBinsSize()
tries to replace the view component. Instead, update the model and the listening view will update itself.
I tried to update the dataset, but I don't see any way of deleting series.
The addSeries()
method of HistogramDataset
adjusts the dataset's internal state as a function of the number of bins. As a result, you'll need to recreate the dataset
from the original image samples, passing the new bin count as a parameter to addSeries()
. Use the setDataset()
method of XYPlot
to replace the dataset, which will notify the listening plot to update itself. A complete example is shown here.
Upvotes: 4