A builder pattern module for working with the jfreechart library. Meant as a companion to ChartFactory.java to build more complex charts with fewer lines of code.
Takes an opinionated approach to creating "good enough" charts while providing a more declarative way of parameterizing them.
ChartBuilder.get()
.title("Simple Time Series With Annotations")
.timeData(timeArray)
.xyPlot(XYTimeSeriesPlotBuilder.get().gridLines()
.series(XYTimeSeriesBuilder.get().name("Amplitude").data(array1).color(Color.BLUE).style(SOLID_LINE))
.annotation(XYArrowBuilder.get().x(arrowX).y(arrowY).angle(180.0).color(Color.RED).text(arrowTxt))
.annotation(XYArrowBuilder.get().x(arrowX).y(arrowY).angle(0.0).color(Color.RED))
.annotation(XYTextBuilder.get().x(arrowX).y(arrowY).color(DARK_GREEN)
.text("This value!").textPaddingLeft(5).textAlign(TextAnchor.BASELINE_LEFT).angle(90.0)))
.build();
ChartBuilder.get()
.title("Multi Plot Minute Time Series")
.timeData(timeArray)
.xyPlot(XYTimeSeriesPlotBuilder.get().yAxisName("Values")
.backgroundColor(Color.DARK_GRAY).axisColor(Color.RED).axisFontColor(Color.BLUE).gridLines()
.series(XYTimeSeriesBuilder.get().data(array1).color(Color.YELLOW).style(SOLID_LINE))
.series(XYTimeSeriesBuilder.get().data(array2).color(Color.RED).style(SOLID_LINE))
.series(XYTimeSeriesBuilder.get().data(array3).color(Color.GREEN).style(SOLID_LINE))
.series(XYTimeSeriesBuilder.get().data(array4).color(Color.MAGENTA).style(SOLID_LINE)))
.xyPlot(XYTimeSeriesPlotBuilder.get().yAxisName("Amplitudes").noGridLines()
.series(XYTimeSeriesBuilder.get().data(array2).color(Color.BLACK).style(SOLID_LINE))
.series(XYTimeSeriesBuilder.get().data(array3).color(Color.LIGHT_GRAY).style(SOLID_LINE)))
.xyPlot(XYTimeSeriesPlotBuilder.get().yAxisName("Series 1")
.backgroundColor(DARK_GREEN).axisColor(Color.RED).axisFontColor(Color.BLUE).gridLines()
.series(XYTimeSeriesBuilder.get().data(array1).color(Color.GREEN).style(SOLID_LINE)))
.xyPlot(XYTimeSeriesPlotBuilder.get().yAxisName("Series 2")
.backgroundColor(DARK_RED).axisColor(Color.RED).axisFontColor(Color.BLUE).gridLines()
.series(XYTimeSeriesBuilder.get().data(array2).color(Color.RED).style(SOLID_LINE)))
.xyPlot(XYTimeSeriesPlotBuilder.get().yAxisName("Series 3")
.backgroundColor(DARK_BLUE).axisColor(Color.RED).axisFontColor(Color.BLUE).gridLines()
.series(XYTimeSeriesBuilder.get().data(array3).color(Color.CYAN).style(SOLID_LINE)))
.build();
ChartBuilder.get()
.title("Stock Chart Time Series With Weekend Gaps, Lines, and Annotations")
.timeData(timeArray)
.xyPlot(OhlcPlotBuilder.get().yAxisName("Price").plotWeight(3).gridLines()
.series(OhlcSeriesBuilder.get().ohlcv(dohlcv).upColor(Color.WHITE).downColor(Color.RED))
.series(XYTimeSeriesBuilder.get().name("MA(20)").data(sma20).color(Color.MAGENTA).style(SOLID_LINE))
.series(XYTimeSeriesBuilder.get().name("MA(50)").data(sma50).color(Color.BLUE).style(SOLID_LINE))
.series(XYTimeSeriesBuilder.get().name("MA(200)").data(sma200).color(Color.RED).style(SOLID_LINE))
.annotation(XYArrowBuilder.get().x(stockEventDate).y(stockEventPrice).angle(270.0).color(DARK_GREEN)
.textAlign(TextAnchor.BOTTOM_CENTER).text(String.format("%.2f", stockEventPrice)))
.line(LineBuilder.get().horizontal().at(resistanceLevel).color(Color.LIGHT_GRAY).style(SOLID_LINE)))
.xyPlot(VolumeXYPlotBuilder.get().yAxisName("Volume").yTickFormat(volNumFormat).gridLines()
.series(VolumeXYTimeSeriesBuilder.get().ohlcv(dohlcv).upColor(Color.DARK_GRAY).downColor(Color.RED))
.series(XYTimeSeriesBuilder.get().name("MA(90)").data(volSma90).color(Color.BLUE).style(SOLID_LINE))
.annotation(XYArrowBuilder.get().x(stockEventDate).y(stockEventVolume).angle(270.0).color(DARK_GREEN)
.textAlign(TextAnchor.BOTTOM_CENTER).text(String.format("%.0f", stockEventVolume)))
.line(LineBuilder.get().horizontal().at(volumeLine).color(DARK_GREEN).style(SOLID_LINE)))
.xyPlot(XYTimeSeriesPlotBuilder.get().yAxisName("Stoch").yAxisRange(0.0, 100.0).yAxisTickSize(50.0).gridLines()
.series(XYTimeSeriesBuilder.get().name("K(" + K + ")").data(stoch.getPctK()).color(Color.RED).style(SOLID_LINE))
.series(XYTimeSeriesBuilder.get().name("D(" + D + ")").data(stoch.getPctD()).color(Color.BLUE).style(SOLID_LINE))
.line(LineBuilder.get().horizontal().at(80.0).color(Color.BLACK).style(SOLID_LINE))
.line(LineBuilder.get().horizontal().at(50.0).color(Color.BLUE).style(SOLID_LINE))
.line(LineBuilder.get().horizontal().at(20.0).color(Color.BLACK).style(SOLID_LINE)))
.build();
Using showTimeGaps(boolean)
you can remove time gaps that JFreeChart renders by default when no data is defined at expected time instances (like on weekends):
ChartBuilder.get()
.title("Stock Chart Time Series No Gaps for Weekends")
.showTimeGaps(false)
...
Note: the x-axis month label in the gapless time chart currently doesn't always correspond to the first day (or trading day) of the month.
See the Builders Summary to browse the public API.
-
XY time series plots using a CombinedDomainXYPlot in all cases.
- This produces left-to-right horizontal time axes and vertical value axes.
- The time axis is meant to be shared by all sub-plots.
- If you need different time axes then you'll need to
build()
multiple charts and lay those out as desired in your app.
-
Stock market OHLC candlestick charts
-
Stock market volume bar charts
-
Stright line charts
-
Overlay series
-
Annotations (arrows and text)
-
Time gap removal
-
Set various colors
-
Toggle grid lines
In the future, more parameterization may be added to leverage more of what jfreechart provides.
See the jfreechart-builder-demo for an interactive demo used for development.
- JDK 8 or greater [1] [2] installed.
- Apache Maven installed.
- Internet connection for Maven downloads or you add them to your local Maven repo yourself.
git clone <this repo's URL>
The major and minor numbers are the same as the jfreechart major and minor to denote compatibility. The incremental ("patch") number is the monolithic version number of jfreechart-builder.
If you want the latest and greatest contributions use the develop
branch. These commits give you a
preview of what's to come.
Each time develop
is merged into main
, a version tag is added onto that merge commit.
Each commit to main
represents the next released version.
cd path/to/cloned/repo
git checkout <desired branch or tag>
mvn package
The jar will be in the target/
folder.
mvn install
You can generate the Javadoc locally
mvn javadoc:javadoc
Use a browser to open target/site/apidocs/index.html
Alternatively, run the generation script by specifying what version tag to associate with the Javadoc:
./scripts/generate-javadoc.sh v1.5.5
That output will be in target/site/apidocs/javadoc
Add this dependency to your project's .pom
file:
<dependency>
<groupId>com.jfcbuilder</groupId>
<artifactId>jfreechart-builder</artifactId>
<version>1.5.5</version>
<dependency>
No thread-safety measures are deliberately taken. If you require thread-safety then provide deep copies of objects, don't share builders, don't share charts, or add synchronization to your business logic.
Generally, primitive data arrays are copied into jfreechart objects. jfreechart-builder will maintain references to other objects passed-in like strings, colors, and drawing strokes. When the builders and charts they produce go out of scope, the objects you provided (and other objects that may be referencing them) should be garbage collected as applicable.
jfreechart-builder is not affiliated with the jfreechart project but for compatibility is provided under the terms of the same LGPL 2.1 license.
You should be aware of the contents of the jfreechart-builder JAR file built from this project.
It should contain the compiled .class
files only of jfreechart-builder and should not incorporate any from jfreechart, however you must verify its contents to know what the build tools are actually producing.
If you need clarification on the LGPL vs. Java, please see the FSF's tech note about it.
Contributions are welcome and will be accepted as the maintainers' time permits.
- Please use indentations of two spaces (no tabs)
- Wrap lines at a width of 100 characters.
- To help others, write good Javadoc at least for class descriptions and public methods.