如何在 JFreeChart 中的数轴域上旋转刻度线标签?

发布于 2024-11-30 00:14:53 字数 292 浏览 2 评论 0原文

就像在下面的示例中所做的那样,我希望图表域上的刻度线标签旋转 45 度,如下图表所示: http://left.subtree.org/2007/08/14/ rotate-labels-jfreechart/

不同的是,我想在带有数字轴的散点图上执行此操作。我在 NumberAxis 类中找不到与 setCategoryLabelPositions() 等效的方法。

Just like is being done in the following example, I want the tick mark labels on the domain of chart to be rotated 45 degrees as the are in this chart:
http://left.subtree.org/2007/08/14/rotate-labels-jfreechart/

The difference is, I want to do this on a scatter plot with a numeric axis. I can't find an equivalent to setCategoryLabelPositions() in the class NumberAxis.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烂柯人 2024-12-07 00:14:53

给出的第一个答案是针对数字域轴的。如果您有类别轴,则需要以下代码:

CategoryAxis domainAxis = plot.getDomainAxis();  
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);  

The first answer given is for a numeric domain axis. If you have a category axis, you want this code:

CategoryAxis domainAxis = plot.getDomainAxis();  
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);  
幸福%小乖 2024-12-07 00:14:53

方法 setVerticalTickLabels() 可能是一种替代方法。如果没有,我看不到任何选择,只能重写 refreshTicksHorizo​​ntal()。另请参阅此示例

在此处输入图像描述

import java.awt.Color;
import java.awt.Dimension;
import java.util.*;
import org.jfree.chart.*;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

/**
 * @see https://stackoverflow.com/questions/7208657
 * @see https://stackoverflow.com/questions/7071057
 */
public class ScatterTickLabels extends ApplicationFrame {

    public ScatterTickLabels(String s) {
        super(s);
        final ChartPanel chartPanel = createDemoPanel();
        chartPanel.setPreferredSize(new Dimension(640, 480));
        this.add(chartPanel);
    }

    public static ChartPanel createDemoPanel() {
        JFreeChart jfreechart = ChartFactory.createScatterPlot(
            "Scatter Plot Demo", "X", "Y", samplexydataset(),
            PlotOrientation.VERTICAL, true, true, false);
        XYPlot xyPlot = (XYPlot) jfreechart.getPlot();
        xyPlot.setDomainCrosshairVisible(true);
        xyPlot.setRangeCrosshairVisible(true);
        XYItemRenderer renderer = xyPlot.getRenderer();
        renderer.setSeriesPaint(0, Color.blue);
        NumberAxis domain = (NumberAxis) xyPlot.getDomainAxis();
        domain.setVerticalTickLabels(true);
        return new ChartPanel(jfreechart);
    }

    private static XYDataset samplexydataset() {
        int cols = 20;
        int rows = 20;
        XYSeriesCollection xySeriesCollection = new XYSeriesCollection();
        XYSeries series = new XYSeries("Random");
        Random rand = new Random();
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                double x = rand.nextGaussian();
                double y = rand.nextGaussian();
                series.add(x, y);
            }
        }
        xySeriesCollection.addSeries(series);
        return xySeriesCollection;
    }

    public static void main(String args[]) {
        ScatterTickLabels demo = new ScatterTickLabels("Scatter Plot Demo");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}

The method setVerticalTickLabels() may be an alternative. If not, I don't see any choice but to override refreshTicksHorizontal(). See also this example.

enter image description here

import java.awt.Color;
import java.awt.Dimension;
import java.util.*;
import org.jfree.chart.*;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

/**
 * @see https://stackoverflow.com/questions/7208657
 * @see https://stackoverflow.com/questions/7071057
 */
public class ScatterTickLabels extends ApplicationFrame {

    public ScatterTickLabels(String s) {
        super(s);
        final ChartPanel chartPanel = createDemoPanel();
        chartPanel.setPreferredSize(new Dimension(640, 480));
        this.add(chartPanel);
    }

    public static ChartPanel createDemoPanel() {
        JFreeChart jfreechart = ChartFactory.createScatterPlot(
            "Scatter Plot Demo", "X", "Y", samplexydataset(),
            PlotOrientation.VERTICAL, true, true, false);
        XYPlot xyPlot = (XYPlot) jfreechart.getPlot();
        xyPlot.setDomainCrosshairVisible(true);
        xyPlot.setRangeCrosshairVisible(true);
        XYItemRenderer renderer = xyPlot.getRenderer();
        renderer.setSeriesPaint(0, Color.blue);
        NumberAxis domain = (NumberAxis) xyPlot.getDomainAxis();
        domain.setVerticalTickLabels(true);
        return new ChartPanel(jfreechart);
    }

    private static XYDataset samplexydataset() {
        int cols = 20;
        int rows = 20;
        XYSeriesCollection xySeriesCollection = new XYSeriesCollection();
        XYSeries series = new XYSeries("Random");
        Random rand = new Random();
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                double x = rand.nextGaussian();
                double y = rand.nextGaussian();
                series.add(x, y);
            }
        }
        xySeriesCollection.addSeries(series);
        return xySeriesCollection;
    }

    public static void main(String args[]) {
        ScatterTickLabels demo = new ScatterTickLabels("Scatter Plot Demo");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}
半山落雨半山空 2024-12-07 00:14:53

您必须查看超类: Axis.setLabelAngle(rad)

这是一个示例

编辑:上面没有用,抱歉。

我查看了org.jfreechart.chart.axis.NumberAxis.refreshTicksHorizo​​ntal的代码。实际上有一个角度设置为 0.0(所有 new NumberTick(...,0.0) 构造函数中的最后一个参数)。您可以创建一个 NumberAxis 的子类,用使用不同角度(在构造函数中指定)的方法来重写刷新TicksHorizo​​ntal 方法。

看起来在绘制图表时总是会调用refreshTicks,所以你不必担心它没有被调用。

/**
 * Calculates the positions of the tick labels for the axis, storing the
 * results in the tick label list (ready for drawing).
 *
 * @param g2  the graphics device.
 * @param dataArea  the area in which the data should be drawn.
 * @param edge  the location of the axis.
 *
 * @return A list of ticks.
 */
protected List refreshTicksHorizontal(Graphics2D g2,
        Rectangle2D dataArea, RectangleEdge edge) {

    List result = new java.util.ArrayList();

    Font tickLabelFont = getTickLabelFont();
    g2.setFont(tickLabelFont);

    if (isAutoTickUnitSelection()) {
        selectAutoTickUnit(g2, dataArea, edge);
    }

    TickUnit tu = getTickUnit();
    double size = tu.getSize();
    int count = calculateVisibleTickCount();
    double lowestTickValue = calculateLowestVisibleTickValue();

    if (count <= ValueAxis.MAXIMUM_TICK_COUNT) {
        int minorTickSpaces = getMinorTickCount();
        if (minorTickSpaces <= 0) {
            minorTickSpaces = tu.getMinorTickCount();
        }
        for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++) {
            double minorTickValue = lowestTickValue 
                    - size * minorTick / minorTickSpaces;
            if (getRange().contains(minorTickValue)){
                result.add(new NumberTick(TickType.MINOR, minorTickValue,
                        "", TextAnchor.TOP_CENTER, TextAnchor.CENTER,
                        0.0));
            }
        }
        for (int i = 0; i < count; i++) {
            double currentTickValue = lowestTickValue + (i * size);
            String tickLabel;
            NumberFormat formatter = getNumberFormatOverride();
            if (formatter != null) {
                tickLabel = formatter.format(currentTickValue);
            }
            else {
                tickLabel = getTickUnit().valueToString(currentTickValue);
            }
            TextAnchor anchor = null;
            TextAnchor rotationAnchor = null;
            double angle = 0.0;
            if (isVerticalTickLabels()) {
                anchor = TextAnchor.CENTER_RIGHT;
                rotationAnchor = TextAnchor.CENTER_RIGHT;
                if (edge == RectangleEdge.TOP) {
                    angle = Math.PI / 2.0;
                }
                else {
                    angle = -Math.PI / 2.0;
                }
            }
            else {
                if (edge == RectangleEdge.TOP) {
                    anchor = TextAnchor.BOTTOM_CENTER;
                    rotationAnchor = TextAnchor.BOTTOM_CENTER;
                }
                else {
                    anchor = TextAnchor.TOP_CENTER;
                    rotationAnchor = TextAnchor.TOP_CENTER;
                }
            }

            Tick tick = new NumberTick(new Double(currentTickValue),
                    tickLabel, anchor, rotationAnchor, angle);
            result.add(tick);
            double nextTickValue = lowestTickValue + ((i + 1)* size);
            for (int minorTick = 1; minorTick < minorTickSpaces;
                    minorTick++) {
                double minorTickValue = currentTickValue
                        + (nextTickValue - currentTickValue)
                        * minorTick / minorTickSpaces;
                if (getRange().contains(minorTickValue)){
                    result.add(new NumberTick(TickType.MINOR,
                            minorTickValue, "", TextAnchor.TOP_CENTER,
                            TextAnchor.CENTER, 0.0));
                }
            }
        }
    }
    return result;

}

You have to look at the super class: Axis.setLabelAngle(rad).

And here is an example.

EDIT: above was not useful, sorry.

I looked at the code of org.jfreechart.chart.axis.NumberAxis.refreshTicksHorizontal. There is actually an angle that is set to 0.0 (the last argument in all the new NumberTick(...,0.0) constructors). You could make a subclass of NumberAxis that overrides the method refreshTicksHorizontal with one which uses a different angle (specified in your constructor).

It looks like refreshTicks is always called when drawing the graph, so you don't have to worry about it not being called.

/**
 * Calculates the positions of the tick labels for the axis, storing the
 * results in the tick label list (ready for drawing).
 *
 * @param g2  the graphics device.
 * @param dataArea  the area in which the data should be drawn.
 * @param edge  the location of the axis.
 *
 * @return A list of ticks.
 */
protected List refreshTicksHorizontal(Graphics2D g2,
        Rectangle2D dataArea, RectangleEdge edge) {

    List result = new java.util.ArrayList();

    Font tickLabelFont = getTickLabelFont();
    g2.setFont(tickLabelFont);

    if (isAutoTickUnitSelection()) {
        selectAutoTickUnit(g2, dataArea, edge);
    }

    TickUnit tu = getTickUnit();
    double size = tu.getSize();
    int count = calculateVisibleTickCount();
    double lowestTickValue = calculateLowestVisibleTickValue();

    if (count <= ValueAxis.MAXIMUM_TICK_COUNT) {
        int minorTickSpaces = getMinorTickCount();
        if (minorTickSpaces <= 0) {
            minorTickSpaces = tu.getMinorTickCount();
        }
        for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++) {
            double minorTickValue = lowestTickValue 
                    - size * minorTick / minorTickSpaces;
            if (getRange().contains(minorTickValue)){
                result.add(new NumberTick(TickType.MINOR, minorTickValue,
                        "", TextAnchor.TOP_CENTER, TextAnchor.CENTER,
                        0.0));
            }
        }
        for (int i = 0; i < count; i++) {
            double currentTickValue = lowestTickValue + (i * size);
            String tickLabel;
            NumberFormat formatter = getNumberFormatOverride();
            if (formatter != null) {
                tickLabel = formatter.format(currentTickValue);
            }
            else {
                tickLabel = getTickUnit().valueToString(currentTickValue);
            }
            TextAnchor anchor = null;
            TextAnchor rotationAnchor = null;
            double angle = 0.0;
            if (isVerticalTickLabels()) {
                anchor = TextAnchor.CENTER_RIGHT;
                rotationAnchor = TextAnchor.CENTER_RIGHT;
                if (edge == RectangleEdge.TOP) {
                    angle = Math.PI / 2.0;
                }
                else {
                    angle = -Math.PI / 2.0;
                }
            }
            else {
                if (edge == RectangleEdge.TOP) {
                    anchor = TextAnchor.BOTTOM_CENTER;
                    rotationAnchor = TextAnchor.BOTTOM_CENTER;
                }
                else {
                    anchor = TextAnchor.TOP_CENTER;
                    rotationAnchor = TextAnchor.TOP_CENTER;
                }
            }

            Tick tick = new NumberTick(new Double(currentTickValue),
                    tickLabel, anchor, rotationAnchor, angle);
            result.add(tick);
            double nextTickValue = lowestTickValue + ((i + 1)* size);
            for (int minorTick = 1; minorTick < minorTickSpaces;
                    minorTick++) {
                double minorTickValue = currentTickValue
                        + (nextTickValue - currentTickValue)
                        * minorTick / minorTickSpaces;
                if (getRange().contains(minorTickValue)){
                    result.add(new NumberTick(TickType.MINOR,
                            minorTickValue, "", TextAnchor.TOP_CENTER,
                            TextAnchor.CENTER, 0.0));
                }
            }
        }
    }
    return result;

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文