JFreeCharts - Making a chart with X as category and Y as TimeInterval - jfreechart

I am trying to find out apis in JFreeChart, that would allow me to build up a chart, where a long the X axis I would have categories and the Y axis interval values corresponding to times.
Y axis should represent time.
X axis category.
This is similar to a google calendar scenario, where in the X axis such as day of the week. And on the Y axis, you can write what you do along certain regions of time.
The following JFREE chart, represents what I would like to represent.
However, my Y axis is holding time as miliseconds and not as a time unit (e.g. seconds).
In the following image, i illustrate categories along the X that we can imagine they are something like an edge on a graph.
And on the Y axis, we have for example something time spend traveling it and then after traveling it time spent saying cultivating it.
The Y axis is compised by double values, and it would be preferable to be able to use an appropriate time axis. This seems to be problem when using category data sets.
Alreayd to make the chart bellow, many hacks had to be put in place, to make the stacks not being rendered from 0 - by having invisible data series.

Althgout it is definitely not obvious how to use JFreeChart to solve the problem posted above, based on the demo7 sample mentinoed in my comments I can now say that it is definitely possible to use the XYBarChart as an engine to render the bars at the right places for your problem, while having an axis that represents time and another axis that represents whatever you want such as categories.
The sample7 example uses a numberic axis and allocates intervals of the numeric axis as steps for rendering with of a bar.
In such a way, the problem can easily be adapted to my question above, and here is the adapted application that pseudo-implements the chart on my question in a proper way.
import java.awt.Color;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYIntervalSeries;
import org.jfree.data.xy.XYIntervalSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
public class XYBarChartDemo7VarianRepresentingStackOverFlowQuestion extends ApplicationFrame {
/**
* Constructs the demo application.
*
* #param title
* the frame title.
*/
public XYBarChartDemo7VarianRepresentingStackOverFlowQuestion(String title) {
super(title);
JPanel chartPanel = createDemoPanel();
chartPanel.setPreferredSize(new java.awt.Dimension(500, 300));
setContentPane(chartPanel);
}
private static JFreeChart createChart(IntervalXYDataset dataset) {
JFreeChart chart = ChartFactory.createXYBarChart("XYBarChartDemo7", "Date", true, "Y", dataset,
PlotOrientation.HORIZONTAL, true, false, false);
XYPlot plot = (XYPlot) chart.getPlot();
// The Y axis is turned into a date axis
plot.setRangeAxis(new DateAxis("Date"));
// The X axis is turned is turned into a label axis
SymbolAxis xAxis = new SymbolAxis("Series",
new String[] { "R107 => R101", "R101 => R5", "R5 => R15", "R15 => R16" });
xAxis.setGridBandsVisible(false);
plot.setDomainAxis(xAxis);
// Enables using Y interval
XYBarRenderer renderer = (XYBarRenderer) plot.getRenderer();
renderer.setUseYInterval(true);
plot.setRenderer(renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
ChartUtilities.applyCurrentTheme(chart);
return chart;
}
/**
* Creates a sample dataset.
*
* #return A dataset.
*/
private static IntervalXYDataset createDataset() {
// Time points to represnet
// Edge: "R107 => R101"
RegularTimePeriod d0 = new Day(12, 6, 2007);
RegularTimePeriod d1 = new Day(13, 6, 2007);
RegularTimePeriod d2 = new Day(14, 6, 2007);
// "R101 => R5"
RegularTimePeriod d3 = new Day(15, 6, 2007);
RegularTimePeriod d4 = new Day(16, 6, 2007);
RegularTimePeriod d5 = new Day(17, 6, 2007);
// "R5 => R15"
RegularTimePeriod d6 = new Day(18, 6, 2007);
RegularTimePeriod d7 = new Day(19, 6, 2007);
RegularTimePeriod d8 = new Day(20, 6, 2007);
// "R15 => R16"
RegularTimePeriod d9 = new Day(21, 6, 2007);
RegularTimePeriod d10 = new Day(22, 6, 2007);
RegularTimePeriod d11 = new Day(23, 6, 2007);
/// Next edge that is not part of the path
RegularTimePeriod d12 = new Day(24, 6, 2007);
// Create three interval series (each series has a different color)
XYIntervalSeriesCollection dataset = new XYIntervalSeriesCollection();
XYIntervalSeries s1 = new XYIntervalSeries("ProductiveTime");
XYIntervalSeries s2 = new XYIntervalSeries("WaitTime");
// Series 1 and series2 along edge1
addItem(s1, d0, d1, 0);
addItem(s2, d1, d3, 0);
// Series 1 and series2 along edge2
addItem(s1, d3, d4, 1);
addItem(s2, d4, d6, 1);
// Series 1 and series2 along edge3
addItem(s1, d6, d7, 2);
addItem(s2, d7, d9, 2);
// Series 1 and series2 along edge4
addItem(s1, d9, d10, 3);
addItem(s2, d10, d12, 3);
// puts in the data set the data series
dataset.addSeries(s1);
dataset.addSeries(s2);
return dataset;
}
private static void addItem(XYIntervalSeries s, RegularTimePeriod p0, RegularTimePeriod p1, int index) {
s.add(index,
// xLow x xHigh we see this on the Y because chart is horizontal
index - 0.45, index + 0.45, p0.getFirstMillisecond(),
// yLow yHigh (time interval) - we see this on the X because chart is set as horizontal
// NOTE: - notice how miliseconds are being used to make the xy interval and not
// actually a date object. But then on the date axis we shall have a proper DateAxis for rendering
// these miliseconds values
p0.getFirstMillisecond(), p1.getFirstMillisecond());
}
/**
* Creates a panel for the demo.
*
* #return A panel.
*/
public static JPanel createDemoPanel() {
return new ChartPanel(createChart(createDataset()));
}
/**
* Starting point for the demonstration application.
*
* #param args
* ignored.
*/
public static void main(String[] args) {
XYBarChartDemo7VarianRepresentingStackOverFlowQuestion demo = new XYBarChartDemo7VarianRepresentingStackOverFlowQuestion(
"JFreeChart : XYBarChartDemo7.java");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
And the image bellow illustrates how stepping away from the BarChart and category data sets, and moving into the XYBarChart and into IntervalXYDataSets, we can render bars where we want them.
Note if we plot the graph vertically, it will look exactly like the first chart at the question. With time axis on the Y and and the cateogories on the X.
So, another satisfied user.

Related

DynamicReport - How to plot too many data points

I am trying to create LineChartReport using more than 1000 data points. Problem is that the X Axis should show the time stamp, and since there are too many data points, the data gets overlapped and no comprehensible data is shown. So I need help on following 2 points:
1. Limit the data points on X-Axis (only) to say 25. The number of data points for the graph/chart still remains at 1000
2. Rotate the Timestamp data by 90 degrees so that the Timestamp data is recorded correctly and not truncated.
Have tried to get the domain axis and manipulate it, like this, but the library does not allow that:
CategoryAxis domainAxis = chart.getCategoryPlot().getDomainAxis();
domainAxis.setMinorTickMarksVisible(false);
domainAxis.clearCategoryLabelToolTips();
chart.getCategoryPlot().getDataset().getColumnKeys()
CategoryDataset ds = chart.getCategoryPlot().getDataset();
List ls = ds.getColumnKeys();
List ls2 = new ArrayList();
int i = 0;
for (Iterator it = ls.iterator(); it.hasNext(); ) {
it.next();
if (i % 2 != 0) {
ls2.add(ls.get(i));
}
i++;
}
chart.getCategoryPlot().setDataset(ds);
Sample image with 10 data points appear here: https://drive.google.com/drive/u/0/folders/0B-m6SCJULOTRdHZ6cUwxX041SHM
Any suggestions ??
The below codes are based on DynamicReport 4.0.2. I didn't test them in other versions.
Regarding your first question, you want 1000 points of data, and just want the few data in line chart. In this case, you need to use the different data source for you data table and line chart.
Firstly, create the subreport for the data table and set up.
SubreportBuilder subreport = cmp.subreport(
report().setTemplate(Templates.reportTemplate)
.addColumn(
col.column("Name", "name", type.stringType()),
col.column("Counts", "value", type.integerType())
)
);
JasperReportBuilder reportContent = report();
subreport.setDataSource(allDatasource);
reportContent.summary(subreport, cmp.verticalGap(20));
Secondly, prepare another data source for line chart and set up.
reportContent.setTemplate(Templates.reportTemplate)
/* add title */
.title(title, subtitle,
/* add chart in the head of title */
cmp.verticalList(LINE_CHART)
/* set style */
.setStyle(stl.style().setBottomPadding(30).setTopPadding(30)))
/* set data source for line chart*/
.setDataSource(dataSource);
About your second question, you need to create customizer at first.
public class DynamicLineCustomizer implements DRIChartCustomizer, Serializable {
private static final long serialVersionUID = -8493880774698206000L;
#Override
public void customize(JFreeChart jFreeChart, ReportParameters reportParameters) {
CategoryPlot plot = jFreeChart.getCategoryPlot();
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setCategoryLabelPositions(CategoryLabelPositions
.createUpRotationLabelPositions(Math.PI / 6.0));
}
}
Then use this customizer in line chard builder.
LineChartBuilder lineChart = cht.lineChart()
.customizers(new DynamicLineCustomizer())
.setCategory(columns[0])
.series(createSeries(columns))
.setCategoryAxisFormat(cht.axisFormat().setLabel("TimeStamp"))
.seriesColors(seriesColors);
The line chart and data table will be like below:
This finally worked for me (hope it helps somebody) :
Ref: http://www.dynamicreports.org/forum/viewtopic.php?f=1&t=1046
private void build(String startDate, String endDate) {
TextColumnBuilder<Integer> i = col.column("I", "I", type.integerType());
TextColumnBuilder<Integer> b = col.column("B", "B", type.integerType());
TextColumnBuilder<Integer> t = col.column("T", "T", type.integerType());
TextColumnBuilder<Date> timeColumn = col.column("TimeStamp", "TimeStamp", type.dateType());
createDataSource(startDate, endDate);
try {
TimeSeriesChartBuilder timeSeriesChartBuilder1 = cht.timeSeriesChart();
timeSeriesChartBuilder1.series(cht.serie(b), cht.serie(t), cht.serie(i));
timeSeriesChartBuilder1.setShowShapes(false);
timeSeriesChartBuilder1.setDataSource(dataSource);
timeSeriesChartBuilder1.setTimePeriod(timeColumn);
timeSeriesChartBuilder1.setTimePeriodType(TimePeriod.SECOND);
timeSeriesChartBuilder1.setTitle("ABC Information");
JasperReportBuilder builder = report()
.summary(cht.multiAxisChart(timeSeriesChartBuilder1))
.setTemplate(Templates.reportTemplate)
.title(Templates.createTitleComponent("ABC Complete Info"))
;
builder.show();
} catch (Exception e) {
e.printStackTrace();
}
}

How can I pass a variable from one class to another class and use it as a value in JFreeChart [duplicate]

This question already has an answer here:
I have a bar chart which I want to update and I tried the revalidate and repaint methods but with no success
(1 answer)
Closed 8 years ago.
I want to generate a bar graph based from user inputs but, I tried passing it from my main class to the class where I coded my graph and it doesn't work.
here's a part of my main class. It's were I will get the value.
public double computeE1() {
double x1 = sFrame.s1;
double x2 = tFrame.t1;
double x3 = fFrame.f1;
E1 = 5.278 + ((-0.172)*x1) + ((-0.197)*x2) + ((-0.191)*x3);
return E1;
}
and here's my JFreeChart class
public class BarChart extends ApplicationFrame {
GUImain gui; //main class
public BarChart(final String title)
{
super(title);
final CategoryDataset dataset = createDataset();
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(500,270));
setContentPane(chartPanel);
}
private CategoryDataset createDataset()
{
double e1 = gui.E1;
double e2 = gui.E2;
double e3 = gui.E3;
double e4 = gui.E4;
DefaultCategoryDataset ds = new DefaultCategoryDataset();
ds.addValue(e1, "asdas", null);
ds.addValue(e2, "asdasda", null);
ds.addValue(e3, "sar", null);
ds.addValue(e4, "asda", null);
return ds;
}
This can be very confusing when you are just learning Java. The trick is to have a "control" class, which controls and coordinates the other elements of the program (ie analytics, ui, etc). Your your case, I'd probably try to include the class that has your analytics into the class that you're using for your UI... Is the analytics class stateless? https://softwareengineering.stackexchange.com/.../whats-the-difference-between-stateful-and-stateless

xy plot of renderer label points(data points) are overlapping with line chart of TimeSeriesChart of jfreechart

I am using Jfreechart API 1.0.8 to generate the TimeSeriesChart(line chart).
when I am generating the chart, i am facing the problem of overlapping.
Here I am trying to display the rendered points(graph rendered points), by using XYLineAndShapeRenderer with StandardXYItemLabelGenerator.
When the points are displayed, the data-point is overlapping with the generated line chart (graph).
I am taking X-Axis as time, and y-Axis as revenue of organization, and i am using line chart here.
I'm displaying the points as discussed below.
By using "renderer.setBasePositiveItemLabelPosition" method, globally i am setting the position of graph points(data points) inside the xyplot rendered chart while considering the rendered "ItemLabelAnchor".
I am sending my sample code here:
chart = ChartFactory.createTimeSeriesChart("", "", "", newxyseries, false, true, false);
renderer = new XYLineAndShapeRenderer();
renderer = (XYLineAndShapeRenderer) chart.getXYPlot().getRenderer();
renderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator("{2}", monthDate, formatSymbol));
renderer.setBaseItemLabelsVisible(true);
renderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.TOP_RIGHT));
chart.getXYPlot().setRenderer(renderer);
But when I am generating the graph chart using Ms-office of Excel tools, there is no problem of overlapping of labels, the points are displayed in an effective manner without any overlapping.
JFreeChart doesn't do any overlap detection for item labels. It would be a great feature to have, but nobody has written the code to do it.
you have to refrain the labels to get overlap by define your own algo or logic because as the graph keep growing sooner the labels will start to get overlap.
the key is to make some or alternative labels transparent so that no overlapping occur
For example in the following P.O.C, only 35 labels will be drawn but the tick of graphs will remai same just the labels will reduce
CategoryAxis domainAxis = plot.getDomainAxis();
CategoryLabelPositions pos = domainAxis.getCategoryLabelPositions();
double size = plot.getCategories().size();
double occurence = Math.ceil(plot.getCategories().size() / 20);
double interval = Math.ceil(plot.getCategories().size() / 20);
for (int i = 1; i <= plot.getCategories().size(); i++) {
if (plot.getCategories().size() > 35) {
if(plot.getCategories().size()>35 && plot.getCategories().size()<250) {
if(i%8==0){
String cat_Name = (String) plot.getCategories().get(i-1);
} else{
String cat_Names = (String) plot.getCategories().get(i-1);
domainAxis.setTickLabelPaint(cat_Names, new Color(0,0,0,0));
}
}else if(plot.getCategories().size()>250){
[![enter image description here][1]][1]
if (i == occurence) {
String cat_Name = (String) plot.getCategories().get(i - 1);
if (occurence + interval >= size) {
// occurence=size;
} else {
occurence = occurence + interval;
}
} else {
String cat_Names = (String) plot.getCategories().get(i - 1);
domainAxis.setTickLabelPaint(cat_Names, new Color(0, 0, 0, 0));
}
}
}
Below line will make label transparent
domainAxis.setTickLabelPaint(cat_Names, new Color(0,0,0,0));

JFreeChart : How to make a series invisible?

I am trying to make a chart of ohlc bars invisible so that I can leave the window with only the moving average.
Here is the code with the two series (ohlc bars and moving average) :
private static JFreeChart createChart(OHLCDataset dataset)
{
JFreeChart chart = ChartFactory.createHighLowChart(
"HighLowChartDemo2",
"Time",
"Value",
dataset,
true);
XYPlot plot = (XYPlot)chart.getPlot();
DateAxis axis = (DateAxis)plot.getDomainAxis();
axis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
NumberAxis yAxis = (NumberAxis)plot.getRangeAxis();
yAxis.setNumberFormatOverride(new DecimalFormat("$0.00"));
//overlay the moving average dataset...
XYDataset dataset2 = MovingAverage.createMovingAverage(dataset, "-MAVG", 3 * 24 * 60 * 60 * 1000L, 0L);
plot.setDataset(1, dataset2);
plot.setRenderer(1, new StandardXYItemRenderer());
XYItemRenderer theRenderer = plot.getRenderer(0);
theRenderer.setSeriesVisible(0, false);
return chart;
}
For some reason setSeriesVisible function is not working.
Any ideas?
Thank you.
HighLowRenderer ignores getSeriesVisible() and getBaseSeriesVisible(), although it does check getDrawOpenTicks() and getDrawCloseTicks(). You can replace the OHLCDataset:
plot.setDataset(0, null);
Alternatively, don't add the OHLCDataset in the first place; just use it to create the MovingAverage.

JFreechart: Displaying X axis with values after specific units

I am using jfreechart for displaying line graph.Now, on X axis it shows value for every (x,y) pair on chart.As a result the X axis has huge amount of values getting overlapped.I want to display few values eg after every 5 units or something like that.How is this possible using Jfreechart.
Before the NumberAxis of the chart's plot is drawn, its tick marks are refreshed. The result is a List that includes a NumberTick object for each tick mark of the axis.
By overriding the function NumberAxis.refreshTicks you can control how and if the marks will be shown.
For example, in the following code I get all tick marks and iterate through them looking for TickType.MAJOR. If the value of a major tick mark is not dividable by 5, it gets replaced by a minor tick mark.
As a result, only values dividable by 5 will be shown with their text label.
XYPlot plot = (XYPlot) chart.getPlot();
NumberAxis myAxis = new NumberAxis(plot.getDomainAxis().getLabel()) {
#Override
public List refreshTicks(Graphics2D g2, AxisState state,
Rectangle2D dataArea, RectangleEdge edge) {
List allTicks = super.refreshTicks(g2, state, dataArea, edge);
List myTicks = new ArrayList();
for (Object tick : allTicks) {
NumberTick numberTick = (NumberTick) tick;
if (TickType.MAJOR.equals(numberTick.getTickType()) &&
(numberTick.getValue() % 5 != 0)) {
myTicks.add(new NumberTick(TickType.MINOR, numberTick.getValue(), "",
numberTick.getTextAnchor(), numberTick.getRotationAnchor(),
numberTick.getAngle()));
continue;
}
myTicks.add(tick);
}
return myTicks;
}
};
plot.setDomainAxis(myAxis);

Resources