I am using JFreeChart to make a barchart vs time. For some reason on these charts, the tick labels on the x axis turn into "..." occasionally. There seems like there is plenty of room for the labels to expand, but instead it just cuts off the whole thing. How can I fix this.
I tried uploading a picture using the image button, but it does not seem to be working.
Here is code with a similar set up to my project. Strangely it acted different then what is happening to my build. On mine instead of saying "Hou...", it just says "...". Ignore comments and all other uneeded things please.
package dataDisplay;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
public class mockTest extends JPanel{
ChartPanel chartPanel;
JFreeChart chart;
CategoryAxis domainAxis;
NumberAxis rangeAxis;
public mockTest()
{
//Mock data
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
int[] times = new int[]{1,2,3,4,5,6,7,8,9,10,11,12};
for ( int i = 0; i < times.length; i++ ){
dataset.addValue(times[i], "Time", "Houreee" + String.valueOf(i+1));;
}
CategoryPlot plot = new CategoryPlot();
//create the plot
//add the first dataset, and render as bar values
CategoryItemRenderer renderer = new BarRenderer();
plot.setDataset(0,dataset);
plot.setRenderer(0,renderer);
//set axis
domainAxis = new CategoryAxis("Time");
rangeAxis = new NumberAxis("Value");
plot.setDomainAxis(0,domainAxis);
plot.setRangeAxis(rangeAxis);
chart = new JFreeChart(plot);
chartPanel = new ChartPanel( chart );
this.addComponentListener(new ComponentAdapter() {
#Override
/**
* Makes it so it does not stretch out text. Resizes the fonts to scale with the screen width..
*/
public void componentResized(ComponentEvent e) {
chartPanel.setMaximumDrawHeight(e.getComponent().getHeight());
chartPanel.setMaximumDrawWidth(e.getComponent().getWidth());
chartPanel.setMinimumDrawWidth(e.getComponent().getWidth());
chartPanel.setMinimumDrawHeight(e.getComponent().getHeight());
// Makes the font size scale according to the width of the chart panel.
rangeAxis.setLabelFont(new Font("SansSerif", Font.PLAIN,e.getComponent().getWidth()/60));
domainAxis.setTickLabelFont(new Font("SansSerif", Font.PLAIN,e.getComponent().getWidth()/80));
rangeAxis.setTickLabelFont(new Font("SansSerif", Font.PLAIN,e.getComponent().getWidth()/75));
}
});
this.add(chartPanel, "Center");
}
public static void main (String[] args)
{
// Get the default toolkit
Toolkit toolkit = Toolkit.getDefaultToolkit();
// Get the current screen size
Dimension scrnsize = toolkit.getScreenSize();
int scrnWidth= (int)scrnsize.getWidth();
int scrnHeight = (int) scrnsize.getHeight();
JFrame J= new JFrame();
JPanel jP = new JPanel();
J.setContentPane(jP);
J.setSize(scrnWidth, scrnHeight);
jP.setBackground(Color.white);
jP.setBounds(0,0,scrnWidth,scrnHeight);
int xPercent= 50;
int yPercent = 50;
int widthPercent=50;
int heightPercent=43;
jP.setLayout(null);
jP.setSize(scrnWidth, scrnHeight);
mockTest b= new mockTest();
jP.add(b);
b.setBounds(new Rectangle((int)(scrnWidth*((double)xPercent/100)),(int)(scrnHeight*((double)yPercent/100)),(int)(scrnWidth*((double)widthPercent/100)),(int)(scrnHeight*((double)heightPercent/100))));
J.setUndecorated(true);
J.setVisible(true);
}
Don't use a null layout; let the layout manager do the work. The default layout of JPanel is FlowLayout, which ignores your subsequent changes. In the example below,
The chartPanel is given a GridLayout; when added to the enclosing frame's CENTER, the chart will be free to grow as the frame is resized.
Avoid unnecessarily nested panels.
Use setExtendedState() to maximize the frame.
If necessary, use one of the approaches suggested here to alter the chart's initial size.
If you choose to alter a Font, use deriveFont() to avoid abrupt disparities in the user's chosen settings.
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
/** #see https://stackoverflow.com/a/31014252/230513 */
public class Test {
public void display() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (int i = 0; i < 12; i++) {
dataset.addValue(i, "Time", "Hours" + String.valueOf(i + 1));
}
CategoryPlot plot = new CategoryPlot();
CategoryItemRenderer renderer = new BarRenderer();
plot.setDataset(0, dataset);
plot.setRenderer(0, renderer);
CategoryAxis domainAxis = new CategoryAxis("Time");
NumberAxis rangeAxis = new NumberAxis("Value");
plot.setDomainAxis(0, domainAxis);
plot.setRangeAxis(rangeAxis);
JFreeChart chart = new JFreeChart(plot);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setLayout(new GridLayout());
JFrame f = new JFrame();
f.add(chartPanel);
f.setExtendedState(f.getExtendedState() | JFrame.MAXIMIZED_BOTH);
f.setUndecorated(true);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Test()::display);
}
}
Related
On an XYPlot, I want the coordinates of mouse displayed as hint near to mouse, but only when (the mouse) move on chart! In another words, when the crosshair moves to another point, the positioning of the coordinate values would move too, following the crosshair.
Also 1 horizontal line and 1 vertical line will be drawn, that intersects specifically at the point that mouse is over on.
Is this possible?
Until now I can get the coordinates and printed on console using ChartMouseListener and chartMouseMoved method.
This is my project and how I want to be the chart with mouse.
JFreeChart has quite flexible support for crosshairs. To do what you described I would use an Overlay on the ChartPanel, and update the crosshairs from your ChartMouseListener. Here is a self-contained example (which I'll add to the collection of demos that we ship with the JFreeChart Developer Guide):
package org.jfree.chart.demo;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleEdge;
/**
* A demo showing crosshairs that follow the data points on an XYPlot.
*/
public class CrosshairOverlayDemo1 extends JFrame implements ChartMouseListener {
private ChartPanel chartPanel;
private Crosshair xCrosshair;
private Crosshair yCrosshair;
public CrosshairOverlayDemo1(String title) {
super(title);
setContentPane(createContent());
}
private JPanel createContent() {
JFreeChart chart = createChart(createDataset());
this.chartPanel = new ChartPanel(chart);
this.chartPanel.addChartMouseListener(this);
CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
this.xCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.xCrosshair.setLabelVisible(true);
this.yCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yCrosshair.setLabelVisible(true);
crosshairOverlay.addDomainCrosshair(xCrosshair);
crosshairOverlay.addRangeCrosshair(yCrosshair);
chartPanel.addOverlay(crosshairOverlay);
return chartPanel;
}
private JFreeChart createChart(XYDataset dataset) {
JFreeChart chart = ChartFactory.createXYLineChart("Crosshair Demo",
"X", "Y", dataset);
return chart;
}
private XYDataset createDataset() {
XYSeries series = new XYSeries("S1");
for (int x = 0; x < 10; x++) {
series.add(x, x + Math.random() * 4.0);
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
return dataset;
}
#Override
public void chartMouseClicked(ChartMouseEvent event) {
// ignore
}
#Override
public void chartMouseMoved(ChartMouseEvent event) {
Rectangle2D dataArea = this.chartPanel.getScreenDataArea();
JFreeChart chart = event.getChart();
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis xAxis = plot.getDomainAxis();
double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea,
RectangleEdge.BOTTOM);
double y = DatasetUtilities.findYValue(plot.getDataset(), 0, x);
this.xCrosshair.setValue(x);
this.yCrosshair.setValue(y);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CrosshairOverlayDemo1 app = new CrosshairOverlayDemo1(
"JFreeChart: CrosshairOverlayDemo1.java");
app.pack();
app.setVisible(true);
}
});
}
}
I found a thermometer demo and customized it for my dashboard project. http://www.java2s.com/Code/Java/Chart/JFreeChartThermometerDemo2.htm
In my dashboard I have six thermometer with different Mercury Color. However, I cannot seem to find a way to change the color of the range numbers that are displayed beside the thermometer.
How do I change the range number text color from Black to White?
My Demo Thermometer screenshot
package Thermometers;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.ThermometerPlot;
import org.jfree.data.general.DefaultValueDataset;
import App.App_v2;
public class ThermometerDemo2 extends JPanel
{
private static final long serialVersionUID = 1L;
public ThermometerDemo2(Color color, double maxValue)
{
// create a dataset...
final DefaultValueDataset dataset = new DefaultValueDataset(110);
// create the chart...
final ThermometerPlot plot = new ThermometerPlot(dataset);
plot.setRange(0.0, maxValue);
plot.setSubrange(ThermometerPlot.CRITICAL, 250, 300);
plot.setValueFont(new Font("Georgia", Font.BOLD, 32));
plot.setThermometerStroke(new BasicStroke(2.0f));
plot.setBackgroundPaint(new Color(20,42,60));
plot.setMercuryPaint(color);
final JFreeChart chart = new JFreeChart(plot);
chart.setBorderVisible(false);
// add the chart to a panel...
ChartPanel chartPanel = new ChartPanel(chart);
this.add(chartPanel);
this.setBackground(new Color(20,42,60));
}
public static void main(final String[] args) {
JFrame frame = new JFrame("change the black range color into white");
frame.setVisible(true);
frame.setSize(500, 500);
ThermometerDemo2 demo = new ThermometerDemo2(Color.magenta, 300);
demo.setVisible(true);
frame.add(demo);
frame.pack();
}
}
I'm having some trouble while working on JFreeChart RingPlot. I've managed to put labels inside my chart, yet I can't change their positions as I want. Here where am I right now;
I need to move the labes closer to the edges of the chart so that I can lower the section depth and have a better ring look. So far, I tried to play with setSimpleLabelOffset and setLabelGap methods but didn't work well.
Here is my code;
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("Critical", new Integer(5));
dataset.setValue("Important", new Integer(20));
dataset.setValue("Moderate", new Integer(19));
dataset.setValue("Low", new Integer(5));
JFreeChart chart = ChartFactory.createRingChart("", dataset, false, true, false);
RingPlot pie = (RingPlot) chart.getPlot();
pie.setBackgroundPaint(Color.WHITE);
pie.setOutlineVisible(false);
pie.setShadowPaint(null);
pie.setSimpleLabels(true);
pie.setLabelGenerator(new StandardPieSectionLabelGenerator("{1}"));
//pie.setSimpleLabelOffset(new RectangleInsets(1, 1, 1, 1));
//pie.setLabelGap(0.05);
//pie.setLabelPadding(new RectangleInsets(100, 5, 10, 5));
pie.setLabelBackgroundPaint(null);
pie.setLabelOutlinePaint(null);
pie.setLabelShadowPaint(null);
pie.setSectionDepth(0.50);
pie.setSectionOutlinesVisible(false);
pie.setSeparatorsVisible(false);
pie.setIgnoreZeroValues(true);
Any idea how may I achieve this?
Thanks in advance.
Edit: Thanks for the response #trashgod, but something is wrong with my environment iI guess. I copied and pasted the whole code you presented above and what I get is this:
The default RectangleInsets for PiePlot labels are inset relative to the plot's pieArea:
this.simpleLabelOffset = new RectangleInsets(UnitType.RELATIVE, 0.18, 0.18, 0.18, 0.18);
The example below cuts the insets in half and changes the section depth accordingly:
pie.setSimpleLabelOffset(new RectangleInsets(UnitType.RELATIVE, 0.09, 0.09, 0.09, 0.09));
pie.setSectionDepth(0.33);
As tested with jfreechart-1.0.19.jar and jcommon-1.0.23.jar, Java 1.8.0_92, Mac OS X 10.11.5, Windows 10:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.RingPlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.ui.RectangleInsets;
import org.jfree.util.UnitType;
/**
* #see http://stackoverflow.com/a/37414338/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("Critical", new Integer(5));
dataset.setValue("Important", new Integer(20));
dataset.setValue("Moderate", new Integer(19));
dataset.setValue("Low", new Integer(5));
JFreeChart chart = ChartFactory.createRingChart("", dataset, false, true, false);
RingPlot pie = (RingPlot) chart.getPlot();
pie.setBackgroundPaint(Color.WHITE);
pie.setOutlineVisible(false);
pie.setShadowPaint(null);
pie.setSimpleLabels(true);
pie.setLabelGenerator(new StandardPieSectionLabelGenerator("{1}"));
pie.setSimpleLabelOffset(new RectangleInsets(
UnitType.RELATIVE, 0.09, 0.09, 0.09, 0.09));
pie.setLabelBackgroundPaint(null);
pie.setLabelOutlinePaint(null);
pie.setLabelShadowPaint(null);
pie.setSectionDepth(0.33);
pie.setSectionOutlinesVisible(false);
pie.setSeparatorsVisible(false);
pie.setIgnoreZeroValues(true);
f.add(new ChartPanel(chart){
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
});
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Test()::display);
}
}
I have a program that is operating fine which repeats a series of formulas using different values for independent variables. I now want to make a plot of the calculations after every iteration of the loop. This is what I have so far:
public static void main(String[] args) {
JFrame window=new JFrame();
window.setTitle("Try");
window.setSize(600, 400);
window.setLayout(new BorderLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
XYSeries series = new XYSeries("graph");
XYSeriesCollection dataset= new XYSeriesCollection(series);
...
My big questions are how do I take my data and generate a dataset, and then how do I make the graph update after every iteration of the loop? I have imported the JFreeChart class and some swing. Any and all insight would be greatly appreciated.
So I figured this out after some time. The trick is to set visible inside of the loop. But now, the JFrame redraws with every iteration. I don't know if there is a way to hold the frame constant. If anyone does know, I would appreciate the help.
package trylog{
import javax.swing.JFrame;
import java.awt.BorderLayout;
java.util.List;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DatasetChangeListener;
import org.jfree.data.general.DatasetGroup;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import sun.security.jca.GetInstance.Instance;
public class TryLog {
private static Object InstanceTools;
public static void main(String[] args) {
JFrame window=new JFrame();
window.setTitle("Try");
window.setSize(600, 400);
window.setLayout(new BorderLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//window.setVisible(true);
XYSeries series = new XYSeries("graph");
XYSeriesCollection dataset= new XYSeriesCollection(series);
double[] newArray= new double[1000];
for (int j=0;j<1000;j++)
{
newArray[j]=1+10;
}
JFreeChart chart=ChartFactory.createXYLineChart("Graph Try", "hi", "bye", dataset);
window.add(new ChartPanel(chart),BorderLayout.CENTER);
int x=0;
int number=10;
JFrame window1=new JFrame();
window1.setTitle("Try");
window1.setSize(600, 400);
window1.setLayout(new BorderLayout());
window1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//window.setVisible(true);
XYSeries series1 = new XYSeries("graph");
XYSeriesCollection dataset1= new XYSeriesCollection(series1);
double[] newArray1= new double[1000];
for (int j=0;j<1000;j++)
{
newArray[j]=1+10;
}
JFreeChart chart1=ChartFactory.createXYLineChart("Graph Try", "hi", "bye", dataset1);
window1.add(new ChartPanel(chart1),BorderLayout.CENTER);
int y=0;
int number1=10;
for (int i=0;i<10000;i++)
{
series.add(x,number);
x++;
number++;
window.setVisible(true);
series1.add(y,number1);
y++;
number1++;
window1.setVisible(true);
}
}
I have a JFree XY Line chart which always starts at x = 0. Then based on user defined settings from a properties file, the application increments based on that number (this represents the time in minutes).
For example, x = 0 to start the user defined setting is 5 so the scale goes 0, 5, 10, 15, 20…, or the user setting is 3 so it goes 0, 3, 6, 9, 12… Pretty simple.
The issue I am having is the way in which the graph starts. If I start at 0, then 0 is in the middle of the graph rather than at the bottom left with -0.0000005, -0.000004, -0.000003… 0.000000 , 0.000001 , 0.000002… 0.000005
How can I just manually add the scale at the bottom, i.e. define it should be increments of 2 and then maintain it?
You should use NumberAxis, which contains a lot of methods to define the scale of your chart.
Example :
// Create an XY Line chart
XYSeries series = new XYSeries("Random Data");
series.add(1.0, 500.2);
series.add(10.0, 694.1);
XYSeriesCollection data = new XYSeriesCollection(series);
JFreeChart chart = ChartFactory.createXYLineChart("XY Series Demo", "X", "Y", data,
PlotOrientation.VERTICAL,
true, true, false);
// Create an NumberAxis
NumberAxis xAxis = new NumberAxis();
xAxis.setTickUnit(new NumberTickUnit(2));
// Assign it to the chart
XYPlot plot = (XYPlot) chart.getPlot();
plot.setDomainAxis(xAxis);
Based on this example, here's an sscce that uses setTickUnit() to adjust the domain axis tick unit dynamically, starting from the value 5.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/** #see https://stackoverflow.com/a/14167983/230513 */
public class SSCCE {
private static final int COUNT = 100;
private static final int UNITS = 5;
private static final Random r = new Random();
public static void main(String[] args) {
XYSeries series = new XYSeries("Data");
for (int i = 0; i < COUNT; i++) {
series.add(i, r.nextGaussian());
}
XYSeriesCollection data = new XYSeriesCollection(series);
final JFreeChart chart = ChartFactory.createXYLineChart("TickUnits",
"X", "Y", data, PlotOrientation.VERTICAL, true, true, false);
XYPlot plot = (XYPlot) chart.getPlot();
final NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
xAxis.setTickUnit(new NumberTickUnit(UNITS));
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("TickUnitDemo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new ChartPanel(chart));
final JSpinner spinner = new JSpinner(
new SpinnerNumberModel(UNITS, 1, COUNT, 1));
spinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
JSpinner s = (JSpinner) e.getSource();
Number n = (Number) s.getValue();
xAxis.setTickUnit(new NumberTickUnit(n.intValue()));
}
});
JPanel p = new JPanel();
p.add(new JLabel(chart.getTitle().getText()));
p.add(spinner);
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}