0

Dual axis in ZK charts

asked 2009-07-01 10:49:12 +0800

piyush1985 gravatar image piyush1985
3 1

Hi 2 all....
I have to add dual axis chart to my project. I have seen examples using jfree chat but don't know how to do the same using zk. I tried googling for the same but haven't found any result for the same. Please help me out...Hope for the reply asap.

Thanks
Piyush Garg

delete flag offensive retag edit

17 Replies

Sort by » oldest newest

answered 2009-10-10 04:39:32 +0800

narayanss gravatar image narayanss
3

well, you are not alone .. does anyone have when the dual / multiple axis option for charting will be available with in ZK ? Thanks Narayanan

link publish delete flag offensive edit

answered 2009-10-10 17:36:29 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2009-10-10 17:39:12 +0800

Not Dual Axis, but the way is the same. I do with chart.createBufferedImage create the chart
in memory and added to a zk 'AImage' component.

you can download the whole code here.
code for dual axis charts are here

	/**
	 * onClick button Bar Chart. <br>
	 * 
	 * @param event
	 * @throws IOException
	 */
	public void onClick$button_CustomerChart_BarChart(Event event) throws InterruptedException, IOException {

		if (logger.isDebugEnabled()) {
			logger.debug("--> " + event.toString());
		}

		div_chartArea.getChildren().clear();

		// get the customer ID for which we want show a chart
		long kunId = getKunde().getKunId();

		// get a list of data
		List<ChartData> kunAmountList = getChartService().getChartDataForCustomer(kunId);

		if (kunAmountList.size() > 0) {

			DefaultCategoryDataset dataset = new DefaultCategoryDataset();

			for (ChartData chartData : kunAmountList) {

				Calendar calendar = new GregorianCalendar();
				calendar.setTime(chartData.getChartKunInvoiceDate());

				int month = calendar.get(Calendar.MONTH) + 1;
				int year = calendar.get(Calendar.YEAR);
				String key = String.valueOf(month) + "/" + String.valueOf(year);

				BigDecimal bd = chartData.getChartKunInvoiceAmount().setScale(15, 3);
				String amount = String.valueOf(bd.doubleValue());

				// fill the data
				dataset.setValue(new Double(chartData.getChartKunInvoiceAmount().doubleValue()), key + " " + amount, key + " " + amount);
			}

			String title = "Monthly amount for year 2009";
			PlotOrientation po = PlotOrientation.VERTICAL;
			JFreeChart chart = ChartFactory.createBarChart(title, "Month", "Amount", dataset, po, true, true, true);

			CategoryPlot plot = (CategoryPlot) chart.getPlot();
			plot.setForegroundAlpha(0.5f);
			BufferedImage bi = chart.createBufferedImage(750, 400, BufferedImage.TRANSLUCENT, null);
			byte[] bytes = EncoderUtil.encode(bi, ImageFormat.PNG, true);

			AImage chartImage = new AImage("Bar Chart", bytes);

			Image img = new Image();
			img.setContent(chartImage);
			img.setParent(div_chartArea);

		} else {

			div_chartArea.getChildren().clear();

			Label label = new Label();
			label.setValue("This customer have no data for showing in a chart!");

			label.setParent(div_chartArea);

		}
	}

best
Stephan

link publish delete flag offensive edit

answered 2009-12-02 16:04:10 +0800

chavocarlos gravatar image chavocarlos
18

HI terrytornado/Stephan,

I don't understand your post, where can i find an example of dual or multiple axis with zkoss? Your code is an example of... ??

Thanks in advance,

Carlos David

link publish delete flag offensive edit

answered 2009-12-02 18:33:03 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2009-12-02 18:35:26 +0800

You can find several codes for dual axis chart here.

In my case all charts are used JFreeChart and at the end of creation of the chart it is copied into a ZKoss Image component. That's all.
Have a look at the sample app codes. Package de.forsthaus.webui.customer.

AImage chartImage = new AImage("Bar Chart", bytes);

Image img = new Image();
img.setContent(chartImage);
img.setParent(div_chartArea);

I have not implemented this case in the sample app because i have not the needed data for this case.

best
Stephan

link publish delete flag offensive edit

answered 2009-12-07 17:32:02 +0800

chavocarlos gravatar image chavocarlos
18

Thanks Stephan,

I do it, now I have a multiple axis chart with zkoss... but what about the tooltips? I am using a window, a div and a bufferedImage instead a z:chart ...

Best,

Carlos David

link publish delete flag offensive edit

answered 2009-12-08 05:50:58 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

Please can you show us the code ?
I will play a little bit with it.

link publish delete flag offensive edit

answered 2009-12-08 09:52:54 +0800

chavocarlos gravatar image chavocarlos
18

Ok, I have this in my jsp.

			<z:page>
				<z:window id="customChartWindow"
					use="org.cad.zksample.CustomChartCtrl"
					border="none" width="1024">
					<z:div id="div_chartArea" height="350" width="1024">
						The chart.
					</z:div>
				</z:window>
			</z:page>

And i have this in my java class.

	public void onCreate$customChartWindow(Event event) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("--> " + event.toString());
		}
		/* autowire comps and vars */
		doOnCreateCommon(customerChartWindow, event);

		buildGraph();
	}
	
	public void buildGraph() throws InterruptedException, IOException {
		div_chartArea.getChildren().clear();
		JFreeChart chart = processChart();

		if (chart != null) {
			BufferedImage bi = chart.createBufferedImage(1024, 350, BufferedImage.TRANSLUCENT, null);		
			byte[] bytes = EncoderUtil.encode(bi, ImageFormat.PNG, true);
			AImage chartImage = new AImage(WebUtil.findMessage("pg_custom_graph_reports"), bytes);

			Image img = new Image();
			img.setContent(chartImage);
			img.setParent(div_chartArea);
		} else {
			div_chartArea.getChildren().clear();
			Label label = new Label();
			label.setValue(WebUtil.findMessage("data_not_found"));
			label.setParent(div_chartArea);

		}
	}

	private static int[] intArray(double a, double b, double c) {
        return new int[] {(int) a, (int) b, (int) c};
    }
	
	private static int[] intArray(double a, double b, double c, double d) {
        return new int[] {(int) a, (int) b, (int) c, (int) d};
    }
	
	public Shape[] createStandardSeriesShapes(double shapeSize) {
        double size = shapeSize;
        double delta = size / 2.0;
        
        int[] xpoints = null;
        int[] ypoints = null; 
        
        Shape[] result = new Shape[10];
        // square
        result[0] = new Rectangle2D.Double(-delta, -delta, size, size);
        // circle
        result[1] = new Ellipse2D.Double(-delta, -delta, size, size);

        // up-pointing triangle
        xpoints = intArray(0.0, delta, -delta);
        ypoints = intArray(-delta, delta, delta);
        result[2] = new Polygon(xpoints, ypoints, 3);

        // diamond
        xpoints = intArray(0.0, delta, 0.0, -delta);
        ypoints = intArray(-delta, 0.0, delta, 0.0);
        result[3] = new Polygon(xpoints, ypoints, 4);

        // horizontal rectangle
        result[4] = new Rectangle2D.Double(-delta, -delta / 2, size, size / 2);

        // down-pointing triangle
        xpoints = intArray(-delta, +delta, 0.0);
        ypoints = intArray(-delta, -delta, delta);
        result[5] = new Polygon(xpoints, ypoints, 3);

        // horizontal ellipse
        result[6] = new Ellipse2D.Double(-delta, -delta / 2, size, size / 2);

        // right-pointing triangle
        xpoints = intArray(-delta, delta, -delta);
        ypoints = intArray(-delta, 0.0, delta);
        result[7] = new Polygon(xpoints, ypoints, 3);

        // vertical rectangle
        result[8] = new Rectangle2D.Double(-delta / 2, -delta, size / 2, size);

        // left-pointing triangle
        xpoints = intArray(-delta, delta, delta);
        ypoints = intArray(0.0, -delta, +delta);
        result[9] = new Polygon(xpoints, ypoints, 3);
        
        return result;
    }
	
    public static JFreeChart createTimeSeriesChart(String title, String timeAxisLabel, String valueAxisLabel, 
    		XYDataset dataset, boolean legend, boolean tooltips, boolean urls) {
		ValueAxis timeAxis = new DateAxis(timeAxisLabel);
		timeAxis.setLowerMargin(0.02);  // reduce the default margins
		timeAxis.setUpperMargin(0.02);
		NumberAxis valueAxis = new NumberAxis(valueAxisLabel);
		valueAxis.setAutoRangeIncludesZero(false);  // override default
		XYPlot plot = new XYPlot(dataset, timeAxis, valueAxis, null);
		
		XYToolTipGenerator toolTipGenerator = null;
		if (tooltips) {
			toolTipGenerator = StandardXYToolTipGenerator.getTimeSeriesInstance();
		}
		
		XYURLGenerator urlGenerator = null;
		if (urls) {
			urlGenerator = new StandardXYURLGenerator();
		}
		
		XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
		renderer.setBaseToolTipGenerator(toolTipGenerator);
		renderer.setURLGenerator(urlGenerator);
		plot.setRenderer(renderer);
		
		JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
		plot, legend);
		return chart;
	}
	
	public JFreeChart processChart() {
		
		List<String> seriesNames = (List<String>) getDesktop().getExecution().getAttribute("XYSeriesNames");
		List<XYDataset> datasets = (List<XYDataset>)getDesktop().getExecution().getAttribute("XYDatasets");
		Map<String,String> params = new HashMap<String,String>();
		
		// Estos parámetros serán pasados usando el request
		params.put(WebUtil.findMessage("shapeSize"), "3");
		params.put(WebUtil.findMessage("type"), "splines");
		params.put(WebUtil.findMessage("col.aloc"), "#,###,###,###.0");
		params.put(WebUtil.findMessage("col.abr']}"), "##0.0%");
		params.put(WebUtil.findMessage("col.attempts']}"), "#,###,###,###");
		params.put(WebUtil.findMessage("col.chrgtime']}"), "#,###,###,###");
		
		JFreeChart jfreechart = createTimeSeriesChart(WebUtil.findMessage("pg_custom_graph_reports"),"Time of Day","Primary Range Axis",datasets.get(0),true, true, false);
		
		// Si hay más datasets y si tienen 4 o más de ellos
		if(datasets != null && datasets.size() > 0) {
			XYPlot xyPlot = (XYPlot) jfreechart.getPlot();
			xyPlot.setOrientation(PlotOrientation.VERTICAL);
			xyPlot.setDomainPannable(true);
			xyPlot.setRangePannable(true);
			
			DateAxis dateAxis = (DateAxis)xyPlot.getDomainAxis();
			dateAxis.setDateFormatOverride(new SimpleDateFormat(FormatterUtil.TIME_OF_DAY_OF_MONTH_FORMAT_PATTERN));
			
			xyPlot.getRangeAxis().setFixedDimension(10D);
			
			ChartUtilities.applyCurrentTheme(jfreechart);
			
			///// Add other datasets to chart ////
			for(int i=0; i < datasets.size(); i++) {
				int datasetIdx = i;
				String serieName = seriesNames.get(i);
				NumberAxis numberAxis = new NumberAxis(serieName);
				
				if(params.get(serieName) != null) {
					DecimalFormat formatter = new DecimalFormat(String.valueOf(params.get(serieName)));
					numberAxis.setNumberFormatOverride(formatter);
				}

				xyPlot.setRangeAxis(datasetIdx, numberAxis);		 
				xyPlot.setDataset(datasetIdx, datasets.get(i)); 
				xyPlot.mapDatasetToRangeAxis(datasetIdx, datasetIdx);
				
				AbstractXYItemRenderer abstractXYItemRenderer = null;
				String typeOfLines = String.valueOf(params.get("type"));
				if("lines".equals(typeOfLines))
					abstractXYItemRenderer = new XYLineAndShapeRenderer();
				else if ("splines".equals(typeOfLines))
					abstractXYItemRenderer = new XYSplineRenderer();
				else
					abstractXYItemRenderer = new StandardXYItemRenderer();
				
				xyPlot.setRenderer(datasetIdx, abstractXYItemRenderer);
				
				// Los datasets pares van a la izquierda,
				// el resto van a la derecha
				if(i % 2 == 0){
					xyPlot.setRangeAxisLocation(i,AxisLocation.BOTTOM_OR_LEFT);
				}
			}
			
			// Aplicamos el template por default a todo el chart (ya tiene todas las series)
			ChartUtilities.applyCurrentTheme(jfreechart);
			
			double shapeSize = 6;
			if(params.get("shapeSize") != null) {
				shapeSize = Double.parseDouble(String.valueOf(params.get("shapeSize")));
			}
			DefaultDrawingSupplier drawingSupplier = new DefaultDrawingSupplier(
					DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE, 
					DefaultDrawingSupplier.DEFAULT_FILL_PAINT_SEQUENCE,
					DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
					DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
					DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
		            createStandardSeriesShapes(shapeSize));
			xyPlot.setDrawingSupplier(drawingSupplier,true);
			
			// Una vez aplicado el template modificamos los colores
			for(int i=0; i < datasets.size(); i++) {
				// El color actual es negro
				Color currentColor = Color.black;
				if(i < (MultipleAxis.DEFAULT_COLORS.length - 1)) {
					currentColor = MultipleAxis.DEFAULT_COLORS<i >;
				} else {
					// Si se acabó la paleta de colores genero uno al azar
					Random generator = new Random();
					float h = generator.nextFloat();
					float s = generator.nextFloat();
					float b = generator.nextFloat();
					currentColor = Color.getHSBColor(h, s, b);
				}
				
				xyPlot.getRenderer(i).setSeriesPaint(0,currentColor);
				NumberAxis numberAxis = (NumberAxis)xyPlot.getRangeAxis(i); 
				numberAxis.setLabelPaint(currentColor);
				numberAxis.setTickLabelPaint(currentColor);
				numberAxis.setAutoRangeIncludesZero(true);
			}
		}
		
		return jfreechart;
	}

This code was based on your code and cewolf code :) . You gave me some ideas.

Thanks.

CDS

link publish delete flag offensive edit

answered 2009-12-08 09:56:51 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

Thanks for sharing it.

link publish delete flag offensive edit

answered 2009-12-09 09:25:47 +0800

chavocarlos gravatar image chavocarlos
18

This is my updated code, I generate the map for tooltips, but I can't make it to work ... see my comments in the sourcecode.

	public void buildGraph() throws InterruptedException, IOException {
		div_chartArea.getChildren().clear();
		JFreeChart chart = processChart();
		if (chart != null) {
			// Get the number of renderers
			int rendererCount = ((XYPlot)chart.getPlot()).getRendererCount();
			// Set a standard tooltip generator for each one
			for(int i=0; i < rendererCount; i++)
				((XYPlot)chart.getPlot()).getRenderer(i).setBaseToolTipGenerator(StandardXYToolTipGenerator.getTimeSeriesInstance());
			
			// Instance a chart info an send it to the createBufferedImage
			ChartRenderingInfo info = new ChartRenderingInfo();
			BufferedImage bi = chart.createBufferedImage(1024, 350, BufferedImage.TRANSLUCENT, info);
			
			// Generate the imagemap from the chart info
			String map = ChartUtilities.getImageMap("testMap", info);
            
			byte[] bytes = EncoderUtil.encode(bi, ImageFormat.PNG, true);
			AImage chartImage = new AImage(WebUtil.findMessage("pg_custom_graph_reports"), bytes);

			// Custom Image xul element, I add the attribute "usemap"
			org.cad.zksample.Image img = new org.cad.zksample.Image();
			img.setContent(chartImage);
			img.setParent(div_chartArea);
			img.setUsemap("#testMap");
			
			// Custom Div xul element, I add content to it -- currently doesn't work :'(
			org.cad.zksample.Div div = new org.cad.zksample.Div();
			div.setContent(map);
			div.setParent(div_chartArea);
		} else {
			div_chartArea.getChildren().clear();
			Label label = new Label();
			label.setValue(WebUtil.findMessage("data_not_found"));
			label.setParent(div_chartArea);

		}
	}

Thanks in advance,

CDS

link publish delete flag offensive edit

answered 2009-12-10 15:10:05 +0800

chavocarlos gravatar image chavocarlos
18

updated 2009-12-10 15:11:38 +0800

Finally, i did it...

I don't use my own Div element, because it doesn't work. I replaced it for an Html element.

			// Custom Div xul element, I add content to it -- currently doesn't work :'(
			org.cad.zksample.Div div = new org.cad.zksample.Div();
			div.setContent(map);
			div.setParent(div_chartArea);

I changed the above code with this:

			Html html = new Html();
			html.setContent(map);
			html.setParent(div_chartArea);

It's not the best, but it works... I hope that somebody can tell me a better/elegant solution.

Thanks,

CDS

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2009-07-01 10:49:12 +0800

Seen: 2,370 times

Last updated: Jul 03 '12

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More