I'm trying to create a bar chart that generates a dataset from within a for loop.
String scores = scoreText.getText();
String[] data = scores.split(",");
DefaultCategoryDataset barChartDataset = null;
for (int l = 0; l < data.length; l++) {
barChartDataset = new DefaultCategoryDataset();
// barChartDataset.setValue(new Double(data[l]), "Scores", stu);
barChartDataset.addValue(new Double(data[l]), "Scores", stu);
System.out.println(data[l]);
}
JFreeChart barChart = ChartFactory.createBarChart3D("Summary", "Name", "Scores", barChartDataset, PlotOrientation.VERTICAL, false, true, false);
The data is 10,5. Now when the data goes through all of this and the graph is generated, only the bar for the value 5 is shown. Where is the separate bar for the value of 10? Does anyone know what I'm doing wrong? Any help is appreciated. Thanks
EDIT:
Here is the code for the bar graph:
String scores = scoreText.getText();
String[] data = scores.split(",");
DefaultCategoryDataset barChartDataset = new DefaultCategoryDataset();
//JFreeChart barChart = null;
for (int l = 0; l < data.length; l++) {
//barChartDataset.addValue(new Double(data[l]), "Scores", stu);
barChartDataset.setValue(new Double(data[l]), "Scores", stu);
System.out.println(new Double(data[l]));
}
JFreeChart barChart = ChartFactory.createBarChart3D("Summary", "Name", "Scores", barChartDataset, PlotOrientation.VERTICAL, false, true, false);
barChart.setBackgroundPaint(Color.YELLOW);
barChart.getTitle().setPaint(Color.RED);
final CategoryPlot categoryPlot = barChart.getCategoryPlot();
BarRenderer barRenderer = (BarRenderer) categoryPlot.getRenderer();
DecimalFormat decimalFormat = new DecimalFormat("#.##");
barRenderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", decimalFormat));
categoryPlot.setRenderer(barRenderer);
barRenderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.HALF_ASCENT_CENTER));
barRenderer.setItemLabelsVisible(true);
barChart.getCategoryPlot().setRenderer(barRenderer);
ValueMarker marker = new ValueMarker(7);
marker.setLabel("Required Level");
marker.setLabelAnchor(RectangleAnchor.BOTTOM_RIGHT);
marker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
marker.setPaint(Color.BLACK);
categoryPlot.addRangeMarker(marker);
categoryPlot.setRangeGridlinePaint(Color.BLUE);
//The JFrame that the bar chart will be in.
ChartFrame chartFrame = new ChartFrame("Bar Chart for Parameters", barChart);
chartFrame.setVisible(true);
chartFrame.setSize(600, 600);
I guess you are doing a small mistake, that is with in for loop for each iteration of loop you are creating a new DefaultCategoryDataset instance. So each time each item is added to a separate DefaultCategoryDataset object and the final DefaultCategoryDataset instance having the last value is utilized to create the chart, that is the only reason you are getting only last value in your chart.
Solution is create DefaultCategoryDataset object outside and before the for loop only once like:
DefaultCategoryDataset barChartDataset = new DefaultCategoryDataset();
for (int l = 0; l < data.length; l++) {
// barChartDataset.setValue(new Double(data[l]), "Scores", stu);
barChartDataset.addValue(new Double(data[l]), "Scores", stu);
System.out.println(data[l]);
}
JFreeChart barChart = ChartFactory.createBarChart3D("Summary", "Name", "Scores", barChartDataset, PlotOrientation.VERTICAL, false, true, false);
Here is the code snippet I have in one of my application and it is working fine:
DefaultCategoryDataset dataset= new DefaultCategoryDataset();
// Get today as a Calendar....
Calendar today = Calendar.getInstance();
for(int i=0; i<15 ;i++)
{
//get util.Date class object for today date.....
java.util.Date today_date=new java.util.Date(today.getTimeInMillis());
//convert date in string format to display on chart.....
String today_string_date = new SimpleDateFormat("dd/MM/yy").format(today_date);
// set values to DefaultCategoryDataset to display on chart...
dataset.setValue(rs1.getInt("login_count"),"Login Frequency", today_string_date);
today.add(Calendar.DATE, -1);
}// for closing...
JFreeChart chart = ChartFactory.createBarChart3D("ISIS:Overall login history for last 15 days", "Date -->", "No of user(s) login per day -->", dataset, PlotOrientation.VERTICAL, true, true, false);
CategoryPlot p = chart.getCategoryPlot();
NumberAxis rangeAxis = (NumberAxis) p.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
BarRenderer renderer = (BarRenderer) p.getRenderer();
DecimalFormat decimalformat1 = new DecimalFormat("##");
renderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", decimalformat1));
renderer.setItemLabelsVisible(true);
ChartUtilities.saveChartAsPNG(new File(filePath +"/chart1.png"), chart ,1250, 400);
I hope it will solve your problem.
Related
I have a chart where I display the values of a table (stock and date). The stock is displayed in the y axis and the dates in the x axis.
As long as the query returns 2 entries, it is shown normally as a line, but if the query returns only one entry, nothing is shown (there should be a point there).
Any suggestions on how to fix this would be highly appreciated.
2 entries: enter image description here
1 entry: enter image description here
Code (the chart is built in an action listener):
historyButton.addActionListener(e -> {
// stock list and dates list retrieved from database
int articleNr = Integer.parseInt(articleIDText.getText());
List<Integer> displayStockHistory;
List<String> displayDatesStockHistory;
try {
displayStockHistory = business.displayStockHistory(articleNr);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
try {
displayDatesStockHistory = business.displayDatesStockHistory(articleNr);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
// add db values to the dataset
for(int i = 0; i < displayStockHistory.size(); i++){
dataset.addValue(displayStockHistory.get(i), "Articles in Stock", displayDatesStockHistory.get(i));
}
// compose chart
JFreeChart chart = ChartFactory.createLineChart(
"Stock History",
"Date",
"Stock",
dataset,
PlotOrientation.VERTICAL,
true,
true,
false);
chart.setBackgroundPaint(c2);
chart.getTitle().setPaint(c3);
CategoryPlot p = chart.getCategoryPlot();
p.setForegroundAlpha(0.9f);
CategoryItemRenderer renderer = p.getRenderer();
//renderer.setSeriesPaint(0, c4);
renderer.setSeriesStroke( 0, new BasicStroke( 5 ) );
chart.getCategoryPlot().setBackgroundPaint(c1);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setBackground(c2);
chartScrollPane.getViewport().add(chartPanel);
chartPanel.setPreferredSize(new Dimension(2000, 270));
ChartFrame frame1 = new ChartFrame("Line graph", chart);
frame1.setVisible(true);
frame1.setSize(500, 400);
});
}
Your chosen chart factory instantiates a LineAndShapeRenderer, so one approach is to make the renderer's shapes visible for all series, as shown here; note that the API has changed:
CategoryPlot plot = (CategoryPlot) chart.getPlot();
LineAndShapeRenderer r = (LineAndShapeRenderer) plot.getRenderer();
r.setDefaultShapesVisible(true);
To enable shapes only for series having a single, non-null value, you'll have to iterate through the data explicitly:
DefaultCategoryDataset data = new DefaultCategoryDataset();
data.addValue(3, "Data1", LocalDate.now());
data.addValue(2, "Data2", LocalDate.now());
data.addValue(1, "Data2", LocalDate.now().plusDays(1));
…
for (int row = 0; row < data.getRowCount(); row++) {
int count = 0;
for (int col = 0; col < data.getColumnCount(); col++) {
count += data.getValue(row, col) != null ? 1 : 0;
}
if (count == 1) {
r.setSeriesShapesVisible(row, true);
}
}
In the chart factory and I use there SlidingGanttCategoryDataset. But the scrolling does not appear. What am I missing?
public JFreeChartGanttChart(String applicationTitle, String chartTitle) {
super(applicationTitle);
// based on the dataset we create the chart
Map<Integer, Map<Integer, String>> labels = new LinkedHashMap<>();
JFreeChart chart = ChartFactory.createGanttChart(chartTitle,
"Vessels",
"Time",
createDataset(labels),
true,
true,
true);
// Adding chart into a chart pane
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.getDomainAxis().setUpperMargin(0.001);
plot.getRangeAxis().setLowerMargin(0.01);
plot.getRangeAxis().setUpperMargin(0.01);
plot.getDomainAxis().setLowerMargin(0.001);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(1000, 1500));
setContentPane(chartPanel);
CategoryItemRenderer renderer = plot.getRenderer();
renderer.setDefaultItemLabelGenerator(new IntervalCategoryItemLabelGenerator(){
#Override
public String generateRowLabel(CategoryDataset dataset, int row) {
return "Text ... " + row ; // not needed here
}
#Override
public String generateColumnLabel(CategoryDataset dataset, int column) {
return " Text ... " + column; // not needed here
}
#Override
public String generateLabel(CategoryDataset dataset, int row, int column) {
return labels.get(row).get(column) ; // row+ " " + column
}
});
renderer.setDefaultItemLabelsVisible(true);
renderer.setDefaultItemLabelPaint(Color.BLACK);
renderer.setDefaultItemLabelFont(new Font("arial", Font.PLAIN, 6), false);
// setDefaultPositiveItemLabelPosition - text will be inside label
renderer.setDefaultNegativeItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.INSIDE6,
TextAnchor.BOTTOM_LEFT));
}
}
While it is technically possible to add a ChartPanel to a JScrollPane, rendering and scrolling hundreds or thousands of tasks scales poorly; the typical appearance is shown here. Instead, use a SlidingGanttCategoryDataset, which "presents a subset of the categories in an underlying dataset." Given an arbitrary number, N, of tasks to to be displayed MAX at a time, construct the corresponding dataset:
private static final int N = 1000;
private static final int MAX = 12;
…
private final SlidingGanttCategoryDataset dataset = new
SlidingGanttCategoryDataset(taskSeriesCollection, 0, MAX);
Then add a suitable control adjacent to the ChartPanel and listen for changes; update the dataset's first displayed index accordingly:
JSlider slider = new JSlider(JSlider.VERTICAL, 0, N - MAX, 0);
slider.addChangeListener((ChangeEvent e) -> {
dataset.setFirstCategoryIndex(slider.getValue());
});
Using setSeriesPaint, I set the colors for the series: red and black. You can see the problem in the picture:
Instead of black, there is something in between black and red, because, apparently, there is an overlay on red. How to solve this problem?
TimeSeries all = new TimeSeries( "All" );
TimeSeries heal = new TimeSeries( "Heal" );
Document document = Jsoup.connect(. . .).get();
Elements h = document.select("tr");
int a = 0;
for(int i = h.size()-1;i>1;i--) {
String[] mas = String.valueOf(h.get(i).text()).split(" ");
SimpleDateFormat ft = new SimpleDateFormat ("dd.MM.yyyy");
Date da = ft.parse(mas[0]);
Day d = new Day(da);
all.add(d, Double.parseDouble(mas[10]));
heal.add(d, Double.parseDouble(mas[4]));
}
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(all);
dataset.addSeries(heal);
JFreeChart lineChartObject = ChartFactory.createXYAreaChart(. . .);
XYPlot plot = (XYPlot) lineChartObject.getPlot();
plot.setBackgroundPaint(Color.white);
plot.setDomainGridlinePaint(Color.black);
plot.setRangeGridlinePaint(Color.black);
DateAxis domain = new DateAxis("Дата");
plot.setDomainAxis(domain);
XYAreaRenderer movingAverageRenderer = new XYAreaRenderer();
movingAverageRenderer.setUseFillPaint(false);
movingAverageRenderer.setSeriesPaint(0, Color.red);
movingAverageRenderer.setSeriesPaint(1, Color.black);
plot.setRenderer(movingAverageRenderer);
int width = 640;
int height = 480;
File lineChart = new File( "C://gr", "graph.jpeg");
ChartUtilities.saveChartAsJPEG(lineChart ,lineChartObject, width ,height);
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries validKoordinates = new XYSeries("Not dangerous");
for (SimulationResult sr : validSR.values()) {
validKoordinates.add(sr.getMinTTC(), sr.getMinTHW()); //x,y
}
dataset.addSeries(validKoordinates);
JFreeChart chart = chart = ChartFactory.createScatterPlot(
"Distribution of THW and TTC Values",
"TTC", "THW", dataset);
//Changes background color
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(255, 228, 196));
plot.getRendererForDataset(plot.getDataset(0)).setSeriesPaint(0, Color.GRAY);
XYSeriesCollection dataset2 = new XYSeriesCollection();
XYSeries warningKoordinates = new XYSeries("Very critical");
for (SimulationResult sr : criticalSR.values()) {
warningKoordinates.add(sr.getMinTTC(), sr.getMinTHW()); //x,y
}
dataset2.addSeries(warningKoordinates);
plot.setDataset(1, dataset2);
plot.getRendererForDataset(plot.getDataset(1)).setSeriesPaint(0, Color.RED);
So I have two different datasets (dataset 1 and dataset 2). Each dataset contains different values. My aim is to change the color of the dataset 1 to gray and the color of the second one to red. (BUT the shape should same the SAME). At the beginning I only had one dataset with 2 XYSeries. The problem at that time was that the shape was different for each XYSeries. Now I have the opposite problem. The shape stays but the color does not change.
This is what my table looks right now:
As you can see right now I cant seperate which one is very critical and whitch not.
It is found that only one dataSet is required, all series should be added to the dataSet. And using the first parameter of setSeriesPaint to configure color of the series. Since the version of jfreeChart is not provide, I used 1.0.12. The code is edited for testing.
public static void main(String[] args) throws IOException {
XYSeriesCollection dataset = new XYSeriesCollection();
int[][] sr = new int[3][2];
for (int i = 0; i < sr.length; i++) {
sr[i][0] = i + 3;
sr[i][1] = 2 * (i + 1) + 1;
}
XYSeries validKoordinates = new XYSeries("Not dangerous");
XYSeries warningKoordinates = new XYSeries("Very critical");
System.out.println(sr.length);
for (int i = 0; i < sr.length; i++) {
validKoordinates.add(sr[i][0], sr[i][1]);
}
for (int i = 0; i < sr.length; i++) {
warningKoordinates.add(sr[i][0]+1, sr[i][1]+1);
}
// Add dataset for all series
dataset.addSeries(validKoordinates);
dataset.addSeries(warningKoordinates);
// Only reference one dataset
JFreeChart chart = ChartFactory.createScatterPlot("Distribution of THW and TTC Values", "TTC", "THW", dataset,
PlotOrientation.HORIZONTAL, true, true, true);
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(255, 228, 196));
// Change the index of setSeriesPaint to set color
plot.getRendererForDataset(dataset).setSeriesPaint(0, Color.GRAY);
plot.getRendererForDataset(dataset).setSeriesPaint(1, Color.RED);
BufferedImage objBufferedImage = chart.createBufferedImage(600, 800);
ByteArrayOutputStream bas = new ByteArrayOutputStream();
try {
ImageIO.write(objBufferedImage, "png", bas);
} catch (IOException e) {
e.printStackTrace();
}
byte[] byteArray = bas.toByteArray();
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage image = ImageIO.read(in);
File outputfile = new File("testimage.png");
ImageIO.write(image, "png", outputfile);
}
The image generated by the above method
I have problem on the Axis and the Tooltip display on JFreeChart they don't display all the values, I am trying to display the bytes based on daily use, here is an image to show exactly my problem:
There are missing some values and on the tallest red bar it doesn't show me the bytes on the tooltip. Here is my code:
final JFreeChart chart = createTrafficChart();
chartPanel = new ChartPanel(chart, true, true, true, true, true);
chartPanel.setPreferredSize(new java.awt.Dimension(750, 367));
a.gridx = 0;
a.gridy = 3;
jpContainer.add(chartPanel, a);
private JFreeChart createTrafficChart() {
// create plot ...
final IntervalXYDataset data1 = createDatasetDownload();
XYBarRenderer t= new XYBarRenderer(0.20);
t.setShadowVisible(false);
final XYItemRenderer renderer1 = t;
renderer1.setBaseToolTipGenerator(new MyTrafficToolTipGenerator());
final DateAxis domainAxis = new DateAxis("Date");
domainAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
final NumberAxis rangeAxis = new NumberAxis("Bytes");
setupRangeAxis(rangeAxis);
final XYPlot plot = new XYPlot(data1, domainAxis, rangeAxis, renderer1);
// add a second dataset and renderer...
final XYDataset data2 = createDatasetUpload();
final XYItemRenderer renderer2 = new StandardXYItemRenderer();
renderer2.setBaseToolTipGenerator(new MyTrafficToolTipGenerator());
plot.setDataset(1, data2);
plot.setRenderer(1, renderer2);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
return new JFreeChart("Traffic", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
}
And this code:
public void setupRangeAxis(NumberAxis rangeAxis) {
final TickUnits standardUnits = new TickUnits();
standardUnits.add(new MyNumberTickUnit(1));
standardUnits.add(new MyNumberTickUnit(10));
standardUnits.add(new MyNumberTickUnit(100));
standardUnits.add(new MyNumberTickUnit(1024)); // Kilo
standardUnits.add(new MyNumberTickUnit(10000));
standardUnits.add(new MyNumberTickUnit(100000));
standardUnits.add(new MyNumberTickUnit(1024*1024)); // Mega
standardUnits.add(new MyNumberTickUnit(10000000));
standardUnits.add(new MyNumberTickUnit(100000000));
standardUnits.add(new MyNumberTickUnit(1024*1024*1024)); // Giga
standardUnits.add(new MyNumberTickUnit(10000000000L));
standardUnits.add(new MyNumberTickUnit(100000000000L));
standardUnits.add(new MyNumberTickUnit(1024*1024*1024*1024)); // Tera
standardUnits.add(new MyNumberTickUnit(10000000000000L));
standardUnits.add(new MyNumberTickUnit(100000000000000L));
standardUnits.add(new MyNumberTickUnit(1000000000000000L)); // Peta
standardUnits.add(new MyNumberTickUnit(10000000000000000L));
standardUnits.add(new MyNumberTickUnit(100000000000000000L));
standardUnits.add(new MyNumberTickUnit(1000000000000000000L)); // Exa
rangeAxis.setStandardTickUnits(standardUnits);
}
Which i found here .
I also have this code:
public class MyNumberTickUnit extends NumberTickUnit{
private static final long serialVersionUID = 4281451255133640119L;
public MyNumberTickUnit(double size) {
super(size);
}
public String valueToString(double value){
return StringFormat.formatTheTraffic(value);
}
}
public class StringFormat {
public static String formatTheTraffic(double input) {
String result = "";
if (input < KILO_BYTES) {
result = input + " Byte";
} else if ((input < MEGA_BYTES) && (input >= KILO_BYTES)) {
result = new DecimalFormat("##.#").format(input / KILO_BYTES) + " KB";
} else if ((input < GIGA_BYTES) && (input >= MEGA_BYTES)) {
result = new DecimalFormat("##.#").format(input / MEGA_BYTES) + " MB";
} else if ((input < TERA_BYTES) && (input >= GIGA_BYTES)) {
result = new DecimalFormat("##.#").format(input / GIGA_BYTES) + " GB";
}
return result;
}
}
Thanks for your attention and time!
I found my problem. It was inside the formatTheTraffic method! I change it and works properly now!