我已经将jstockchart实现为 jfreechart 的插件。
我已经通过实现 Yahoo Finance API 来获取股票报价来改变他们的JStockChartGettingStarted 。
我运行以下规格:
- JDK 1.7
- commons-io-2.4
- commons-lang3-3.1
- jfreechart 1.0.15
- jstockchart 0.4.3
现在我的结果如下所示:
现在我非常喜欢这个插件的是数量和价格是分开的,但两个显示器仍然是链接的。因此,如果我放大一个显示器,另一个显示器也会放大。
我想知道如何在当前两个显示器下方添加另一个显示器,它也与其他两个显示器交互,正如我上面解释的那样。
我知道使用的情节是组合DomainXYPlot,我可以简单地添加到它如下:
if (timeseriesArea.getVolumeWeight() > 0) {
XYPlot volumePlot = createVolumePlot();
combinedDomainXYPlot.add(volumePlot, timeseriesArea
.getVolumeWeight());
}
但是如何添加另一个显示器?
更新
所以我想要做的是添加一组额外的轴/一个额外的面板,如下图所示:
所以我知道如何向任何面板添加额外的图,但不知道如何向整个面板添加额外的(第三个)面板。这第三个面板也使用与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;
}
}
前面板显示代码如下:
图形用户界面代码
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;
}
}
希望有人可以帮助我。提前致谢。