MultiLine Axis Labels

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
avanidhar
Posts: 16
Joined: Wed Jun 11, 2008 10:47 pm

MultiLine Axis Labels

Post by avanidhar » Tue Jun 17, 2008 11:33 pm

Hi,
I need to have a multiline label for my value axis. More precisely,
my value axis has a label of "Y >>BETTER>>" while i need it to be


Y
>>BETTER>>.

Hope you get what i say. I have tried numerous things like inserting a break/newline character and even concatenating 2 strings. But i do not seem to find a fix for this.

Any suggestions?

avanidhar
Posts: 16
Joined: Wed Jun 11, 2008 10:47 pm

Post by avanidhar » Wed Jun 18, 2008 4:24 pm

FYI,

I am using JFreeChart 1.0.9, and JDK 1.6 on a Windows Server 2003 Machine

gilga
Posts: 1
Joined: Mon Oct 27, 2008 2:22 pm

Post by gilga » Mon Oct 27, 2008 2:26 pm

I patched it by implementing my own version of ValueAxis.drawTickMarksAndLabels(..)
You should get a new line for every newLine ;-)

There are only a few changes (see the comments) but i haven't tested it for every possible case... so don't shoot me if anything goes wrong.

But I hope it helps.

Code: Select all

	@Override
	/**
	 * multiple line-labels aren't supported by ValueAxis so we patched it here...
	 */
	protected AxisState drawTickMarksAndLabels(Graphics2D g2, double cursor, Rectangle2D plotArea,
			Rectangle2D dataArea, RectangleEdge edge) {

		AxisState state = new AxisState(cursor);

		if (isAxisLineVisible()) {
			drawAxisLine(g2, cursor, dataArea, edge);
		}

		double ol = getTickMarkOutsideLength();
		double il = getTickMarkInsideLength();

		List ticks = refreshTicks(g2, state, dataArea, edge);
		state.setTicks(ticks);
		g2.setFont(getTickLabelFont());
		Iterator iterator = ticks.iterator();

		// remember the max number of lines used in any label
		int maxLinesUsed = 0;

		while (iterator.hasNext()) {
			ValueTick tick = (ValueTick) iterator.next();
			if (isTickLabelsVisible()) {
				g2.setPaint(getTickLabelPaint());
				float[] anchorPoint = calculateAnchorPoint(tick, cursor, dataArea, edge);

				// split by "\n" and draw text in a new line for each result
				String tickText = tick.getText();
				int line = 1;
				for (String tickTextLine : tickText.split("\n")) {
					float x = anchorPoint[0];
					// one row down...
					float y = anchorPoint[1] + line * g2.getFont().getSize();
					TextUtilities.drawRotatedString(tickTextLine, g2, x, y, tick.getTextAnchor(), tick.getAngle(), tick
							.getRotationAnchor());
					line++;
				}
				// if we used more lines than any time before remember it
				if (line > maxLinesUsed) {
					maxLinesUsed = line;
				}
			}

			if (isTickMarksVisible() && tick.getTickType().equals(TickType.MAJOR)) {
				float xx = (float) valueToJava2D(tick.getValue(), dataArea, edge);
				Line2D mark = null;
				g2.setStroke(getTickMarkStroke());
				g2.setPaint(getTickMarkPaint());
				if (edge == RectangleEdge.LEFT) {
					mark = new Line2D.Double(cursor - ol, xx, cursor + il, xx);
				} else if (edge == RectangleEdge.RIGHT) {
					mark = new Line2D.Double(cursor + ol, xx, cursor - il, xx);
				} else if (edge == RectangleEdge.TOP) {
					mark = new Line2D.Double(xx, cursor - ol, xx, cursor + il);
				} else if (edge == RectangleEdge.BOTTOM) {
					mark = new Line2D.Double(xx, cursor + ol, xx, cursor - il);
				}
				g2.draw(mark);
			}
		}

		// need to work out the space used by the tick labels...
		// so we can update the cursor...
		// patched using maxLinesUsed => we need more space because of multiple lines
		double used = 0.0;
		if (isTickLabelsVisible()) {
			if (edge == RectangleEdge.LEFT) {
				used += findMaximumTickLabelWidth(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
				state.cursorLeft(used);
			} else if (edge == RectangleEdge.RIGHT) {
				used = findMaximumTickLabelWidth(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
				state.cursorRight(used);
			} else if (edge == RectangleEdge.TOP) {
				used = findMaximumTickLabelHeight(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
				state.cursorUp(used);
			} else if (edge == RectangleEdge.BOTTOM) {
				used = findMaximumTickLabelHeight(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
				state.cursorDown(used);
			}
		}

		return state;
	}

gugurorato
Posts: 1
Joined: Fri Jan 09, 2009 1:56 pm
Location: Curitiba - Paraná - Brasil

Post by gugurorato » Fri Jan 09, 2009 2:01 pm

gilga, thanks a lot, you save me,

i'm trying find solution for this problem for months and now it is resolved.

thankssssss a lot

Obs.: I rewrite the DateAxis instead ValueAxis.

tam
Posts: 1
Joined: Mon Oct 29, 2012 4:04 pm
antibot: No, of course not.

Re: MultiLine Axis Labels

Post by tam » Mon Oct 29, 2012 4:19 pm

Hi,

i tried to use this modification in my project. The new line feature works, but the space for the labels stays the same.

Code: Select all

        JFreeChart chart = ChartFactory.createXYLineChart(
                                "", // chart title
                                "", // x axis label
                                "Status", // index_States axis label
                                dataset, // data
                                PlotOrientation.VERTICAL,
                                false, // include legend
                                true, // tooltips
                                false // urls
                                );



                        XYPlot plot = chart.getXYPlot();
                        plot.setBackgroundPaint(Color.decode("#3B98FF"));
                        XYStepRenderer renderer = new XYStepRenderer();
                        renderer.setBaseShapesVisible(true);
                        renderer.setSeriesStroke(0, new BasicStroke(2.0f));
                        renderer.setSeriesStroke(1, new BasicStroke(2.0f));
                        renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
                        renderer.setDefaultEntityRadius(6);
                        plot.setRenderer(renderer);

                        // sets statusnames on the vertical-axis

                        int optionsCount = state.getStatusOptions().toArray().length;
                        String[] grade = new String[optionsCount + 1];
                        grade[0] = "";
                        for (int x = 1; x < optionsCount + 1; x++) {

                          
                            grade[x] = newLineString(state.getStatusOptions().get(x - 1), 5);
                        }
                        // grade[1]="1.line\n2.line";



                        SymbolAxis rangeAxis;
                        rangeAxis = new SymbolAxis("", grade){

                 @Override
                 protected AxisState drawTickMarksAndLabels(Graphics2D g2, double cursor, Rectangle2D plotArea, Rectangle2D dataArea, RectangleEdge edge) {
                     AxisState state = new AxisState(cursor);

                     if (isAxisLineVisible()) {
                         drawAxisLine(g2, cursor, dataArea, edge);
                     }

                     double ol = getTickMarkOutsideLength();
                     double il = getTickMarkInsideLength();

                     List ticks = refreshTicks(g2, state, dataArea, edge);
                     state.setTicks(ticks);
                     g2.setFont(getTickLabelFont());
                     Iterator iterator = ticks.iterator();

                     // remember the max number of lines used in any label
                     int maxLinesUsed = 0;
                    
                     while (iterator.hasNext()) {
                         ValueTick tick = (ValueTick) iterator.next();
                         if (isTickLabelsVisible()) {
                             g2.setPaint(getTickLabelPaint());
                             float[] anchorPoint = calculateAnchorPoint(tick, cursor, dataArea, edge);
                             
                             
                             g2.draw(plotArea);
                             g2.setPaint(Color.green);
                             g2.draw(dataArea);
                             g2.setPaint(getTickLabelPaint());
                             // split by "\n" and draw text in a new line for each result
                             String tickText = tick.getText();
                             int line = 1;
                             for (String tickTextLine : tickText.split("\n")) {
                                 float x = anchorPoint[0];
                                 // one row down...
                                 float y = anchorPoint[1] + line * g2.getFont().getSize();
                                 TextUtilities.drawRotatedString(tickTextLine, g2, x, y, tick.getTextAnchor(), tick.getAngle(), tick
                                         .getRotationAnchor());
                                 line++;
                             }
                             // if we used more lines than any time before remember it
                             if (line > maxLinesUsed) {
                                 maxLinesUsed = line;
                             }
                         }

                         if (isTickMarksVisible() && tick.getTickType().equals(TickType.MAJOR)) {
                             float xx = (float) valueToJava2D(tick.getValue(), dataArea, edge);
                             Line2D mark = null;
                             g2.setStroke(getTickMarkStroke());
                             g2.setPaint(getTickMarkPaint());
                             if (edge == RectangleEdge.LEFT) {
                                 mark = new Line2D.Double(cursor - ol, xx, cursor + il, xx);
                             } else if (edge == RectangleEdge.RIGHT) {
                                 mark = new Line2D.Double(cursor + ol, xx, cursor - il, xx);
                             } else if (edge == RectangleEdge.TOP) {
                                 mark = new Line2D.Double(xx, cursor - ol, xx, cursor + il);
                             } else if (edge == RectangleEdge.BOTTOM) {
                                 mark = new Line2D.Double(xx, cursor + ol, xx, cursor - il);
                             }
                             g2.draw(mark);
                         }
                     }
                     
                     // need to work out the space used by the tick labels...
                     // so we can update the cursor...
                     // patched using maxLinesUsed => we need more space because of multiple lines
                     double used = 0.0;
                     if (isTickLabelsVisible()) {
                         if (edge == RectangleEdge.LEFT) {
                             used += findMaximumTickLabelWidth(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
                             state.cursorLeft(used);
                         } else if (edge == RectangleEdge.RIGHT) {
                             used = findMaximumTickLabelWidth(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
                             state.cursorRight(used);
                         } else if (edge == RectangleEdge.TOP) {
                             used = findMaximumTickLabelHeight(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
                             state.cursorUp(used);
                         } else if (edge == RectangleEdge.BOTTOM) {
                             used = findMaximumTickLabelHeight(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
                             state.cursorDown(used);
                         }
                     }

                     return state;


                 }
                 
             };
Image

i tried to override the getLabelEnclosure method, but its given string is just "".

Where is my misstake?

thank you

Locked