leeyuiwah Posted December 18, 2008 Share Posted December 18, 2008 Hi,I want to make a stacked bar with the X-axis value from a timeseries. I learned that there is no stacked (bar or area) time series,so I decided to use a vanilla stackedArea, and just assign the"Category expression" so that it take values from a time field. (By the way, thetwo names "series expression" and "category expression" seem invertedto me -- it took me a long time to find out what each of them actuallymeans)However, the plot is not pretty, because I have too many data points(see the attached image).So I thought maybe I should write the label expression in such a waythat a string is displayed only a few other lines. Is there a way todo that?I tried several methods to no avail:1. I set the label expression to (see Code Listing 1) use the deprecated getMinutes() method of a java.util.Date object2. I then tried using a java.util.Calendar object, this object has to be calculated for every row in the data set, and I don't know how to do that. The constructor of java.util.Calendar does not take the time value; instead, one must get an instance by a getInstance() static method, and then use the setTimeInMillis() method to set the time value. This latter method returns void. None of the "Calculation Type" -- "Nothing", "Sum", "Average", "First" seems to be appropriate. Also I also tried setting the time in the "label expression", that also did not work. I think I can not execute more than one java statement in the "label expression", can I? (See Code Listing 2) (And in java there is no "common operator" that let you link two statements together)I am stuck now. Any ideas will be appreciated.Clement Code:Code Listing 1$V{createtime_java_util_Date}.getMinutes()==0) ? $V{createtime_java_util_Date}.toLocaleString() : ""Code Listing 2$V{createtime_java_util_Calendar}.setTimeInMillis($F{createtime}.longValue()*1000); ($V{createtime_java_util_Calendar}.get( Calendar.MINUTES )==0) ? $V{createtime_java_util_Date}.toLocaleString() : "" Link to comment Share on other sites More sharing options...
bklawans Posted December 19, 2008 Share Posted December 19, 2008 I just had to do that for a client, but they own the code so I can't post it. I can tell you what I did though. Basically, you have to create a time based stacked area chart, then change the type of the x-axis to a time period axis. This involves writing a chart customizer that makes some pretty big changes to the underlying JFreeChart. It might be possible to do this via the new component or chart theme API in 3.1, but I was working with the 3.0. You want the area chart to be time based, so you have to author the report using a time series chart. Don't worry that a time series chart in JasperReports is a line chart, as your customizer will change it. This way your customizer gets a nice time based data set, and you can set the usual timePeriodExpression in the jrxml. The first thing your customizer has to do is convert the data set - JFreeChart requires a TimeTableXYDataset for stacked area charts, and JasperReports will have created the chart using a TimeSeriesCollection. You can get the TimeSeriesCollection by calling chart.getPlot().getDataset() on the chart passed in to the customizer. You create a new TimeTableXYDataset. Then for each series in the original dataset loop through all the items in the series. Add a new entry to your dataset using the period, value and key of the original item. Set the dataset in the chart's plot to the one you just created. Create a StackedXYAreaRender2, and set that in the plot. To avoid some JFreeChart issues set the plot's dataset rendering order and series rendering order to FORWARD. Finally, create a PeriodAxis, set the date intervals as appropriate for you chart, and then set that as the domain axis in the plot. I strongly recommend getting the JFreeChart documentation before trying this. Its tricky, but when done you get a chart like the one attached. It contains 30 days worth of data collected hourly, and the date axis is still readable.Post Edited by Barry Klawans at 12/19/08 20:05 Link to comment Share on other sites More sharing options...
leeyuiwah Posted December 24, 2008 Author Share Posted December 24, 2008 Barry, Wow, that is wonderful. I will try your suggestion. Thanks a lot! Clement Link to comment Share on other sites More sharing options...
lotus4 Posted March 4, 2011 Share Posted March 4, 2011 Hi,your replies are very interesting. Thank you for that.I've followed your guidelines writing my customize method like this: JRChartPlot plot = jasperChart.getPlot(); //dataset timeseries JRFillTimeSeriesPlot myPlot = (JRFillTimeSeriesPlot)plot; JRFillTimeSeriesDataset inputDataSet = (JRFillTimeSeriesDataset)myPlot.getChart().getDataset(); JRTimeSeries[] timeSeriesArray = inputDataSet.getSeries(); System.out.println(inputDataSet.getSeries().length); i ve refer to a time series graph with 3 series (lines), but it prints on console just 1 serie.Debugging the code i see that the methot getSeries does not return the whole series but just one, all the others fields of JRFillTimeSeriesDataset object are private and so inaccesible. How could i loop throgh them?? Thank you Link to comment Share on other sites More sharing options...
lotus4 Posted March 7, 2011 Share Posted March 7, 2011 ah! i've found my error: the customize method has this signature: public void customize(JFreeChart jFreeChart, JRChart jasperChart) I've used jasperChart, while jFreeChart reference must be used. Anyway, this is the piece of code.Now i'm facing with Period axis to set a specific interval of time, because now it prints a random interval seriesCode:public void customize(JFreeChart jFreeChart, JRChart jasperChart) { Plot plot = jFreeChart.getPlot(); XYPlot myPlot = (XYPlot)plot; //dataset timeseries TimeSeriesCollection inputDataSet = (TimeSeriesCollection )myPlot.getDataset(); //dataset per stacked area graph TimeTableXYDataset ti = new TimeTableXYDataset(); List seriesList = inputDataSet.getSeries(); //loop through series items to copy to other dataset: TimeTableXYDataset Iterator it = seriesList.iterator(); while (it.hasNext()) { TimeSeries serie = (TimeSeries)it.next(); int itemCount = serie.getItemCount(); for(int i =0; i<itemCount; i++) { //add serie to other dataset ti.add(serie.getTimePeriod(i), serie.getValue(i), (String)serie.getKey(), false); } } //stacked area render to draw the correct graph StackedXYAreaRenderer2 s = new StackedXYAreaRenderer2(); myPlot.setDataset(ti); myPlot.setRenderer(s); myPlot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD); myPlot.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD); //axis formatter PeriodAxis p = new PeriodAxis("");// p.setAutoRangeTimePeriodClass(Day.class);// p.setMajorTickTimePeriodClass(Minute.class); p.setFixedAutoRange(new Double("12.4")); PeriodAxisLabelInfo[] info = new PeriodAxisLabelInfo[2]; info[0] = new PeriodAxisLabelInfo(Minute.class, new SimpleDateFormat("hh:mm")); // info[1] = new PeriodAxisLabelInfo(Year.class, new SimpleDateFormat("yyyy")); info[1] = new PeriodAxisLabelInfo(Day.class, new SimpleDateFormat("dd-MMM-yyyy")); p.setLabelInfo(info); myPlot.setDomainAxis(p); } Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now