jstockchart添加第三个显示

时间:2013-10-28 21:09:21

标签: java swing plugins jfreechart jstockchart

我已将jstockchart作为jfreechart的插件实现。

我通过实施Yahoo Finance API来改变他们的JStockChartGettingStarted以获取股票报价。

我运行以下规范:

  • JDK 1.7
  • 公地-IO-2.4
  • 公地lang3-3.1
  • jfreechart 1.0.15
  • jstockchart 0.4.3

我还使用jstockchart 0.4.3 package中找到的所有包。

现在我的结果如下:

enter image description here

现在我非常喜欢这个插件,因为音量和价格是分开的,但两个显示器仍然是相互关联的。因此,如果我放大一个显示器,另一个显示器也会缩放。

我想知道如何在当前的两个显示器下方添加另一个显示器,这也与我上面解释的其他两个显示器相互作用。

我知道用过的地图是combinedDomainXYPlot,我可以简单地按如下方式添加:

    if (timeseriesArea.getVolumeWeight() > 0) {
        XYPlot volumePlot = createVolumePlot();
        combinedDomainXYPlot.add(volumePlot, timeseriesArea
                .getVolumeWeight());
    }

但如何添加其他显示?

更新

所以我想要做的是添加一组额外的轴/一个额外的面板,如下图所示:

enter image description here

所以我知道如何向任何面板添加其他图表,但如何向整个添加额外(第三个)面板。第三个面板也使用与前两个面板相同的CombinedDomainXYPlot

我知道添加其他面板的代码应该在下面的代码中。但在哪里?

渲染图的代码

package org.jstockchart.plot;

import java.awt.BasicStroke;

import org.jfree.chart.axis.SegmentedTimeline;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.TimeSeriesCollection;
import org.jstockchart.area.PriceArea;
import org.jstockchart.area.TimeseriesArea;
import org.jstockchart.area.VolumeArea;
import org.jstockchart.axis.TimeseriesDateAxis;
import org.jstockchart.axis.TimeseriesNumberAxis;
import org.jstockchart.axis.logic.CentralValueAxis;
import org.jstockchart.axis.logic.LogicDateAxis;
import org.jstockchart.axis.logic.LogicNumberAxis;
import org.jstockchart.dataset.TimeseriesDataset;

/**
 * Creates <code>CombinedDomainXYPlot</code> and <code>XYPlot</code> for the
 * timeseries chart.
 * 
 * @author Sha Jiang
 */
public class TimeseriesPlot {

    private static final long serialVersionUID = 8799771872991017065L;

    private TimeseriesDataset dataset = null;

    private SegmentedTimeline timeline = null;

    private TimeseriesArea timeseriesArea = null;

    /**
     * Creates a new <code>TimeseriesPlot</code> instance.
     * 
     * @param dataset
     *            timeseries data set(<code>null</code> not permitted).
     * @param timeline
     *            a "segmented" timeline.
     * @param timeseriesArea
     *            timeseries area.
     */
    public TimeseriesPlot(TimeseriesDataset dataset,
            SegmentedTimeline timeline, TimeseriesArea timeseriesArea) {
        if (dataset == null) {
            throw new IllegalArgumentException("Null 'dataset' argument.");
        }
        this.dataset = dataset;

        this.timeline = timeline;

        if (timeseriesArea == null) {
            throw new IllegalArgumentException(
                    "Null 'timeseriesArea' argument.");
        }
        this.timeseriesArea = timeseriesArea;
    }

    private CombinedDomainXYPlot createCombinedXYPlot() {
        LogicDateAxis logicDateAxis = timeseriesArea.getlogicDateAxis();
        TimeseriesDateAxis dateAxis = new TimeseriesDateAxis(logicDateAxis
                .getLogicTicks());
        if (timeline != null) {
            dateAxis.setTimeline(timeline);
        }

        CombinedDomainXYPlot combinedDomainXYPlot = new CombinedDomainXYPlot(
                dateAxis);
        combinedDomainXYPlot.setGap(timeseriesArea.getGap());
        combinedDomainXYPlot.setOrientation(timeseriesArea.getOrientation());
        combinedDomainXYPlot.setDomainAxis(dateAxis);
        combinedDomainXYPlot.setDomainAxisLocation(timeseriesArea
                .getDateAxisLocation());
        combinedDomainXYPlot.setDomainPannable(true);
        combinedDomainXYPlot.setRangePannable(true);

        if (timeseriesArea.getPriceWeight() <= 0
                && timeseriesArea.getVolumeWeight() <= 0) {
            throw new IllegalArgumentException(
                    "Illegal weight value: priceWeight="
                            + timeseriesArea.getPriceWeight()
                            + ", volumeWeight="
                            + timeseriesArea.getVolumeWeight());
        }

        if (timeseriesArea.getPriceWeight() > 0) {
            XYPlot pricePlot = createPricePlot();
            combinedDomainXYPlot
                    .add(pricePlot, timeseriesArea.getPriceWeight());
        }

        if (timeseriesArea.getVolumeWeight() > 0) {
            XYPlot volumePlot = createVolumePlot();
            combinedDomainXYPlot.add(volumePlot, timeseriesArea
                    .getVolumeWeight());
        }

        return combinedDomainXYPlot;
    }

    private XYPlot createPricePlot() {
        PriceArea priceArea = timeseriesArea.getPriceArea();
        TimeSeriesCollection priceDataset = new TimeSeriesCollection();
        priceDataset.addSeries(dataset.getPriceTimeSeries().getTimeSeries());
        if (priceArea.isAverageVisible()) {
            priceDataset.addSeries(dataset.getAverageTimeSeries()
                    .getTimeSeries());
        }

        CentralValueAxis logicPriceAxis = priceArea.getLogicPriceAxis();
        TimeseriesNumberAxis priceAxis = new TimeseriesNumberAxis(
                logicPriceAxis.getLogicTicks());
        XYLineAndShapeRenderer priceRenderer = new XYLineAndShapeRenderer(true,
                false);
        priceAxis.setUpperBound(logicPriceAxis.getUpperBound());
        priceAxis.setLowerBound(logicPriceAxis.getLowerBound());
        priceRenderer.setSeriesPaint(0, priceArea.getPriceColor());
        priceRenderer.setSeriesPaint(1, priceArea.getAverageColor());

        TimeseriesNumberAxis rateAxis = new TimeseriesNumberAxis(logicPriceAxis
                .getRatelogicTicks());
        rateAxis.setUpperBound(logicPriceAxis.getUpperBound());
        rateAxis.setLowerBound(logicPriceAxis.getLowerBound());

        XYPlot plot = new XYPlot(priceDataset, null, priceAxis, priceRenderer);
        plot.setBackgroundPaint(priceArea.getBackgroudColor());
        plot.setOrientation(priceArea.getOrientation());
        plot.setRangeAxisLocation(priceArea.getPriceAxisLocation());

        if (priceArea.isRateVisible()) {
            plot.setRangeAxis(1, rateAxis);
            plot.setRangeAxisLocation(1, priceArea.getRateAxisLocation());
            plot.setDataset(1, null);
            plot.mapDatasetToRangeAxis(1, 1);
        }

        if (priceArea.isMarkCentralValue()) {
            Number centralPrice = logicPriceAxis.getCentralValue();
            if (centralPrice != null) {
                plot.addRangeMarker(new ValueMarker(centralPrice.doubleValue(),
                        priceArea.getCentralPriceColor(), new BasicStroke()));
            }
        }
        return plot;
    }

    private XYPlot createVolumePlot() {
        VolumeArea volumeArea = timeseriesArea.getVolumeArea();
        LogicNumberAxis logicVolumeAxis = volumeArea.getLogicVolumeAxis();

        TimeseriesNumberAxis volumeAxis = new TimeseriesNumberAxis(
                logicVolumeAxis.getLogicTicks());
        volumeAxis.setUpperBound(logicVolumeAxis.getUpperBound());
        volumeAxis.setLowerBound(logicVolumeAxis.getLowerBound());
        volumeAxis.setAutoRangeIncludesZero(false);
        XYBarRenderer volumeRenderer = new XYBarRenderer();
        volumeRenderer.setSeriesPaint(0, volumeArea.getVolumeColor());
        volumeRenderer.setShadowVisible(false);

        XYPlot plot = new XYPlot(new TimeSeriesCollection(dataset
                .getVolumeTimeSeries()), null, volumeAxis, volumeRenderer);
        plot.setBackgroundPaint(volumeArea.getBackgroudColor());
        plot.setOrientation(volumeArea.getOrientation());
        plot.setRangeAxisLocation(volumeArea.getVolumeAxisLocation());
        return plot;
    }

    public CombinedDomainXYPlot getTimeseriesPlot() {
        return createCombinedXYPlot();
    }

    public TimeseriesDataset getDataset() {
        return dataset;
    }

    public void setDataset(TimeseriesDataset dataset) {
        if (dataset == null) {
            throw new IllegalArgumentException("Null 'dataset' argument.");
        }
        this.dataset = dataset;
    }

    public SegmentedTimeline getTimeline() {
        return timeline;
    }

    public void setTimeline(SegmentedTimeline timeline) {
        this.timeline = timeline;
    }

    public TimeseriesArea getTimeseriesArea() {
        return timeseriesArea;
    }

    public void setTimeseriesArea(TimeseriesArea timeseriesArea) {
        if (timeseriesArea == null) {
            throw new IllegalArgumentException(
                    "Null 'timeseriesArea' argument.");
        }
        this.timeseriesArea = timeseriesArea;
    }
}

前面板显示的代码如下:

GUI代码

package gui;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

import javax.swing.JFrame;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.SegmentedTimeline;
import org.jfree.data.Range;
import org.jfree.data.time.Minute;
import org.jfree.data.xy.OHLCDataItem;
import org.jstockchart.JStockChartFactory;
import org.jstockchart.area.PriceArea;
import org.jstockchart.area.TimeseriesArea;
import org.jstockchart.area.VolumeArea;
import org.jstockchart.axis.TickAlignment;
import org.jstockchart.axis.logic.CentralValueAxis;
import org.jstockchart.axis.logic.LogicDateAxis;
import org.jstockchart.axis.logic.LogicNumberAxis;
import org.jstockchart.dataset.TimeseriesDataset;
import org.jstockchart.model.TimeseriesItem;
import org.jstockchart.util.DateUtils;

/**
 * Demo application for JStockChart timeseries.
 * 
 * @author Sha Jiang
 */
public class TimeseriesChartDemo {

    public static int period = 400;

    public static void main(String[] args) throws IOException {
        String imageDir = "./images";
        File images = new File(imageDir);
        if (!images.exists()) {
            images.mkdir();
        }
        String imageFile = imageDir + "/jstockchart-timeseries.png";


        Date startTime = DateUtils.createDate(2008, 1, 1, 9, 30, 0);
        Date endTime = DateUtils.createDate(2008, 1, 1, 15, 0, 0);
        // 'data' is a list of TimeseriesItem instances.
        List<TimeseriesItem> data = getData("AAPL", period, "d");

        // the 'timeline' indicates the segmented time range '00:00-11:30, 13:00-24:00'.
        SegmentedTimeline timeline = new SegmentedTimeline(
                SegmentedTimeline.DAY_SEGMENT_SIZE, 1351, 89);
        timeline.setStartTime(SegmentedTimeline.firstMondayAfter1900() + 780
                * SegmentedTimeline.DAY_SEGMENT_SIZE);

        // Creates timeseries data set.
        TimeseriesDataset dataset = new TimeseriesDataset(Minute.class, 1,
                timeline, true);
        dataset.addDataItems(data);

        DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.US);
        otherSymbols.setDecimalSeparator('.');
        otherSymbols.setGroupingSeparator(','); 
        DecimalFormat df = new DecimalFormat(".##", otherSymbols);

        // Creates logic price axis.
        CentralValueAxis logicPriceAxis = new CentralValueAxis(
                dataset.getPriceTimeSeries().getTimeSeries().getValue(data.size()-1).doubleValue(), new Range(
                        dataset.getMinPrice().doubleValue(), dataset
                                .getMaxPrice().doubleValue()), 9,
                                df);
        PriceArea priceArea = new PriceArea(logicPriceAxis);

        // Creates logic volume axis.
        LogicNumberAxis logicVolumeAxis = new LogicNumberAxis(new Range(dataset
                .getMinVolume().doubleValue(), dataset.getMaxVolume()
                .doubleValue()), 5, new DecimalFormat("0"));
        VolumeArea volumeArea = new VolumeArea(logicVolumeAxis);

        TimeseriesArea timeseriesArea = new TimeseriesArea(priceArea,
                volumeArea, createlogicDateAxis(DateUtils
                        .createDate(2008, 1, 1)));

        JFreeChart jfreechart = JStockChartFactory.createTimeseriesChart(
                "Stock chart test with two seperate displays", dataset, timeline, timeseriesArea,
                false);


        JFrame outside = new JFrame();
        ChartPanel chartPanel = new ChartPanel(jfreechart, false);

        chartPanel.setMouseWheelEnabled(true);

        outside.add(chartPanel);

        outside.setVisible(true);

        ChartUtilities
                .saveChartAsPNG(new File(imageFile), jfreechart, 545, 300);
    }

    // Specifies date axis ticks.
    private static LogicDateAxis createlogicDateAxis(Date baseDate) {
        LogicDateAxis logicDateAxis = new LogicDateAxis(baseDate,
                new SimpleDateFormat("HH:mm"));
        logicDateAxis.addDateTick("09:30", TickAlignment.START);
        logicDateAxis.addDateTick("10:00");
        logicDateAxis.addDateTick("10:30");
        logicDateAxis.addDateTick("11:00");
        logicDateAxis.addDateTick("11:30", TickAlignment.END);
        logicDateAxis.addDateTick("13:00", TickAlignment.START);
        logicDateAxis.addDateTick("13:30");
        logicDateAxis.addDateTick("14:00");
        logicDateAxis.addDateTick("14:30", TickAlignment.END);
        logicDateAxis.addDateTick("15:00", TickAlignment.END);
        return logicDateAxis;
    }

    static List<TimeseriesItem> dataItems;

    static boolean TodayAdded = true;

    static ArrayList<Double> prices;
    static ArrayList<Date> dates;

    static List<TimeseriesItem> getData(String stockSymbol, int periodToLoad, String periodUnit) {

        TodayAdded = true;

        dataItems = new ArrayList<TimeseriesItem>();

        Date today = new Date();
        today = addDays(today, 1);
        Date beginDate = addDays(today, -periodToLoad);

        GregorianCalendar BEGIN = (GregorianCalendar) DateToCalendar(beginDate);
        GregorianCalendar END   = (GregorianCalendar) DateToCalendar(today);

        String QUOTE = constructURL(stockSymbol, BEGIN, END, periodUnit);

        try {
            String strUrl = QUOTE;
            URL url = new URL(strUrl);
            BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
            DateFormat df = new SimpleDateFormat("y-M-d");

            dates = new ArrayList<Date>();
            prices = new ArrayList<Double>();

            String inputLine;
            in.readLine();
            int counter = 0;

            while ((inputLine = in.readLine()) != null) {
                StringTokenizer st = new StringTokenizer(inputLine, ",");

                Date date       = df.parse( st.nextToken() );
                double open     = Double.parseDouble( st.nextToken() );
                double high     = Double.parseDouble( st.nextToken() );
                double low      = Double.parseDouble( st.nextToken() );
                double close    = Double.parseDouble( st.nextToken() );
                double volume   = Double.parseDouble( st.nextToken() );
                double adjClose = Double.parseDouble( st.nextToken() );

                double price = close;

                dataItems.add(new TimeseriesItem(date, close, volume));

                System.out.println(close);

                dates.add(date);
                prices.add(close);
            }
            in.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        //Reversal of dates
        Collections.reverse(dates);
        Collections.reverse(prices);
        //Data from Yahoo is from newest to oldest. Reverse so it is oldest to newest


        return dataItems;
    }

    public static Date addDays(Date date, int days)
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, days); //minus number would decrement the days
        return cal.getTime();
    }

    public static String constructURL(String symbol, Calendar start, Calendar end, String periodUnit) {
        return "http://ichart.finance.yahoo.com/table.csv" +
    "?s=" +
                symbol + 
    "&a=" +
                Integer.toString(start.get(Calendar.MONTH)) +
    "&b=" +
                start.get(Calendar.DAY_OF_MONTH) +
    "&c=" +
                Integer.toString(start.get(Calendar.YEAR)) +
    "&d=" +
                Integer.toString(end.get(Calendar.MONTH)) +
    "&e=" +
                Integer.toString(end.get(Calendar.DAY_OF_MONTH)) +
    "&f=" +
                Integer.toString(end.get(Calendar.YEAR)) +
    "&g=" +
                periodUnit +
    "&ignore=.csv";
    }

    public static Calendar DateToCalendar(Date date){ 
          Calendar cal = Calendar.getInstance();
          cal.setTime(date);
          return cal;
        }
}

希望有人可以帮助我。提前谢谢。

1 个答案:

答案 0 :(得分:1)

trashgod再次正确。他真的是jfreechart的神。

我发现CombinedDomainXYPlot包中的jstockchart是从名为org.jstockchart.axis.logic的包构建的,它确保每个新的绘图都有自己的框架。

或换句话说,包的行为如下:

  • 创建(完整)独立图
  • 将图表添加到CombinedDomainXYPlot
  • 该包将确保图表具有自己的面板

在编码方面,这意味着以下声明:

    if (timeseriesArea.getPriceWeight() > 0) {
        XYPlot pricePlot = createPricePlot();
        combinedDomainXYPlot
                .add(pricePlot, timeseriesArea.getPriceWeight());
    }

    if (timeseriesArea.getVolumeWeight() > 0) {
        XYPlot volumePlot = createVolumePlot();
        combinedDomainXYPlot.add(volumePlot, timeseriesArea
                .getVolumeWeight());
    }

    if (timeseriesArea.getPriceWeight() > 0) {
        XYPlot pricePlot2 = createPricePlot();
        combinedDomainXYPlot
                .add(pricePlot2, timeseriesArea.getPriceWeight());
    }

创建以下输出:

enter image description here

这正是我想要实现的目标(或想表现出来)。

非常感谢trashgod,我不知道jstockchart包以这种方式工作。