Skip to content

Commit

Permalink
Merge pull request #12 from matoos32/develop
Browse files Browse the repository at this point in the history
Merge develop into main
  • Loading branch information
matoos32 authored Nov 30, 2020
2 parents 4c00a3b + 6109e64 commit 6977700
Show file tree
Hide file tree
Showing 30 changed files with 885 additions and 149 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
jfreechart-builder: a builder pattern module for working with the jfreechart library

(C) Copyright 2020, by Matt E.
(C) Copyright 2020, by Matt E. and project contributors

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
Expand Down
194 changes: 120 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,140 +4,166 @@ A [builder pattern](https://en.wikipedia.org/wiki/Builder_pattern) module for wo

Takes an opinionated approach to creating "good enough" charts while providing a more declarative way of parameterizing them.

Code like this:

```
public static final Stroke SOLID =
new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);

private static final Color DARK_GREEN = new Color(0, 150, 0);
## Capabilities

ChartBuilder.instance()
* XY time series plots using a [CombinedDomainXYPlot](https://github.com/jfree/jfreechart/blob/master/src/main/java/org/jfree/chart/plot/CombinedDomainXYPlot.java) 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.

.title("Multi Plot Minute Time Series")
* Stock market OHLC candlestick charts

.timeData(timestampsArray)
* Stock market volume bar charts

.xyPlot(XYPlotBuilder.instance().yAxisName("Values")
.series(XYTimeSeriesBuilder.instance().data(array1).color(Color.BLUE).style(SOLID))
.series(XYTimeSeriesBuilder.instance().data(array2).color(Color.RED).style(SOLID))
.series(XYTimeSeriesBuilder.instance().data(array3).color(DARK_GREEN).style(SOLID))
.series(XYTimeSeriesBuilder.instance().data(array4).color(Color.MAGENTA).style(SOLID)))
* Stright lines

.xyPlot(XYPlotBuilder.instance().yAxisName("Amplitudes")
.series(XYTimeSeriesBuilder.instance().data(array2).color(Color.GRAY).style(SOLID))
.series(XYTimeSeriesBuilder.instance().data(array3).color(Color.LIGHT_GRAY).style(SOLID)))
* Annotations (arrows and text)

.xyPlot(XYPlotBuilder.instance().yAxisName("Series 1")
.series(XYTimeSeriesBuilder.instance().data(array1).color(Color.BLUE).style(SOLID)))
In the future, more parameterization may be added like specifying background and axis colors, or even the actual series renderer objects themselves to fully leverage what [jfreechart](https://github.com/jfree/jfreechart) provides.

.xyPlot(XYPlotBuilder.instance().yAxisName("Series 2")
.series(XYTimeSeriesBuilder.instance().data(array2).color(Color.RED).style(SOLID)))
## Samples

.xyPlot(XYPlotBuilder.instance().yAxisName("Series 3")
.series(XYTimeSeriesBuilder.instance().data(array3).color(DARK_GREEN).style(SOLID)))
Code like this:

.build()
```
ChartBuilder.get()
.title("Simple Time Series With Annotations")
.timeData(timeArray)
.xyPlot(XYPlotBuilder.get()
.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()
```

Produces a chart like this:

![A multi-plot minute time series chart](./screenshots/multi-plot-minute-time-series.png "Screenshot")
![A multi-plot minute time series chart](./screenshots/simple-time-series-with-annotations.png "Screenshot")

And code like this:
Multiple series can be multi-plotted like this:

```
ChartBuilder.instance()
public static final Stroke SOLID = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
.title("Stock Chart Time Series With Weekend Gaps")
private static final Color DARK_GREEN = new Color(0, 150, 0);
.timeData(timestampsArray) // Has weekend date timestamps missing
ChartBuilder.get()
.xyPlot(OhlcPlotBuilder.instance().yAxisName("Price").plotWeight(3)
.series(OhlcSeriesBuilder.instance().ohlcv(ohlcv).upColor(Color.WHITE).downColor(Color.RED))
.series(XYTimeSeriesBuilder.instance().name("MA(20)").data(sma20).color(Color.MAGENTA).style(SOLID))
.series(XYTimeSeriesBuilder.instance().name("MA(50)").data(sma50).color(Color.BLUE).style(SOLID))
.series(XYTimeSeriesBuilder.instance().name("MA(200)").data(sma200).color(Color.RED).style(SOLID)))
.title("Multi Plot Minute Time Series")
.xyPlot(VolumeXYPlotBuilder.instance().yAxisName("Volume")
.series(VolumeXYTimeSeriesBuilder.instance().ohlcv(ohlcv).closeUpSeries().color(Color.WHITE))
.series(VolumeXYTimeSeriesBuilder.instance().ohlcv(ohlcv).closeDownSeries().color(Color.RED))
.series(XYTimeSeriesBuilder.instance().name("MA(90)").data(volSma90).color(Color.BLUE).style(SOLID)))
.timeData(timeArray)
.xyPlot(XYPlotBuilder.instance().yAxisName("Stoch").yAxisRange(0.0, 100.0).yAxisTickSize(50.0)
.series(XYTimeSeriesBuilder.instance().name("K(" + K + ")").data(stochK).color(Color.RED).style(SOLID))
.series(XYTimeSeriesBuilder.instance().name("D(" + D + ")").data(stochD).color(Color.BLUE).style(SOLID))
.line(LineBuilder.instance().orientation(Orientation.HORIZONTAL).atValue(80.0).color(Color.BLACK).style(SOLID))
.line(LineBuilder.instance().orientation(Orientation.HORIZONTAL).atValue(50.0).color(Color.BLUE).style(SOLID))
.line(LineBuilder.instance().orientation(Orientation.HORIZONTAL).atValue(20.0).color(Color.BLACK).style(SOLID)))
.xyPlot(XYPlotBuilder.get().yAxisName("Values")
.series(XYTimeSeriesBuilder.get().data(array1).color(Color.BLUE).style(SOLID))
.series(XYTimeSeriesBuilder.get().data(array2).color(Color.RED).style(SOLID))
.series(XYTimeSeriesBuilder.get().data(array3).color(DARK_GREEN).style(SOLID))
.series(XYTimeSeriesBuilder.get().data(array4).color(Color.MAGENTA).style(SOLID)))
.build()
```
.xyPlot(XYPlotBuilder.get().yAxisName("Amplitudes")
.series(XYTimeSeriesBuilder.get().data(array2).color(Color.GRAY).style(SOLID))
.series(XYTimeSeriesBuilder.get().data(array3).color(Color.LIGHT_GRAY).style(SOLID)))
Produces a chart like this:
.xyPlot(XYPlotBuilder.get().yAxisName("Series 1")
.series(XYTimeSeriesBuilder.get().data(array1).color(Color.BLUE).style(SOLID)))
![A stock chart time series chart with weekend gaps](./screenshots/stock-chart-time-series-weekend-gaps.png "Screenshot")
.xyPlot(XYPlotBuilder.get().yAxisName("Series 2")
.series(XYTimeSeriesBuilder.get().data(array2).color(Color.RED).style(SOLID)))
.xyPlot(XYPlotBuilder.get().yAxisName("Series 3")
.series(XYTimeSeriesBuilder.get().data(array3).color(DARK_GREEN).style(SOLID)))
## Demo App
.build()
```

See the [jfreechart-builder-demo](https://github.com/matoos32/jfreechart-builder-demo) for an interactive demo used for development.
Produces a chart like this:

## Scope
![A multi-plot minute time series chart](./screenshots/multi-plot-minute-time-series.png "Screenshot")

Currently only supports XY time series plots and uses a [CombinedDomainXYPlot](https://github.com/jfree/jfreechart/blob/master/src/main/java/org/jfree/chart/plot/CombinedDomainXYPlot.java) 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 chart code and data like this:

Currently also only supports lines, stock market OHLC candlestick charts, and stock market volume bar charts.
```
ChartBuilder.get()
.title("Stock Chart Time Series With Weekend Gaps, Lines, and Annotations")
.timeData(timeArray)
.xyPlot(OhlcPlotBuilder.get().yAxisName("Price").plotWeight(3)
.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").plotWeight(1)
.series(VolumeXYTimeSeriesBuilder.get().ohlcv(dohlcv).closeUpSeries().color(Color.WHITE))
.series(VolumeXYTimeSeriesBuilder.get().ohlcv(dohlcv).closeDownSeries().color(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(XYPlotBuilder.get().yAxisName("Stoch").yAxisRange(0.0, 100.0).yAxisTickSize(50.0).plotWeight(1)
.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()
```

In the future, more parameterization may be added like specifying background and axis colors, or even the actual series renderer objects themselves to fully leverage what [jfreechart](https://github.com/jfree/jfreechart) provides.
Produces a chart like this:

![A stock chart time series chart with weekend gaps](./screenshots/stock-chart-time-series-weekend-gaps.png "Screenshot")

## Thread-safety and garbage collection

No thread-safety measures are deliberately taken. If you require thread-safety then either provide deep copies of parameter objects or or synchronize access to builders and data vs. what your app is doing.
## Demo App

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.
See the [jfreechart-builder-demo](https://github.com/matoos32/jfreechart-builder-demo) for an interactive demo used for development.


## Versioning

The major and minor numbers are the same as the **jfreechart** major and minor used. This is to indicate general compatibility. The incremental ("patch") number is the version of this module.
The major and minor numbers are the same as the **jfreechart** major and minor to denote what version is compatible. The incremental ("patch") number is the monolithic version number of **jfreechart-builder**.


## License
## Branching model

**jfreechart-builder** is not affiliated with the **jfreechart** project but for compatibility is provided under the terms of the same [LGPL 2.1 license](./license-LGPL.txt).
If you want the latest and greatest contributions use the `develop` branch. These commits have not yet been merged into `main` nor received a version tag, but give you a preview of what's to come.

You should be aware of the contents of the **jfreechart-builder** JAR file built form this project.

It's understood it will contain the compiled `.class` files of only **jfreechart-builder** and should not incorporate any from **jfreechart**, however you must verify its contents to know what your build tools are actually producing.

If you need clarification on the LGPL vs. Java, please see the [FSF's tech note about it](https://www.gnu.org/licenses/lgpl-java.html).
Each time `develop` is merged into `main`, a version tag is added onto that merge commit so that each commit to `main` represents the next version.


## Incorporating into your project

### Building Prerequisites

### Prerequisites

* JDK 8 or greater [[1](https://openjdk.java.net/)] [[2](https://www.oracle.com/java/)] installed.
* [Apache Maven](https://maven.apache.org/) installed.
* Internet connection so Maven can download artifacts or you provide and install those into your local Maven repo by alternative means.


### Installing source code

`git clone` this repo locally.
```
git clone <repo URL>
```


### Building and installing the JAR

```
cd path/to/the/cloned/repo
```
Next, use `git` to checkout the desired branch or tag.
git checkout <desired branch or tag>
```

If you want to simply build the jar and figure out what to do with it next ...
To simply build the jar and figure out what to do with it next:

```
mvn package
Expand All @@ -146,7 +172,7 @@ mvn package
The jar will be in the `target/` folder.


If you want to build and install the jar into your Maven repo:
To build and install the jar into your Maven repo:

```
mvn install
Expand All @@ -161,11 +187,31 @@ Add this dependency to your project's `.pom` file:
<dependency>
<groupId>com.jfcbuilder</groupId>
<artifactId>jfreechart-builder</artifactId>
<version>1.5.0</version>
<version>1.5.1</version>
<dependency>
```

## Thread-safety and garbage collection

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.


## License

**jfreechart-builder** is not affiliated with the **jfreechart** project but for compatibility is provided under the terms of the same [LGPL 2.1 license](./license-LGPL.txt).

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](https://www.gnu.org/licenses/lgpl-java.html).


## Contributing

Contributions are welcome. The project maintainers' time permitting, merge/pull requests will be reviewed. If accepted they will be merged. No guarantees are made that requests will be reviewed or merged.
Contributions are welcome and will be accepted as the maintainers' time permits.

Please use indentations of two spaces (no tabs) and wrap lines at a max width of 100 characters.
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.jfcbuilder</groupId>
<artifactId>jfreechart-builder</artifactId>
<version>1.5.0</version>
<version>1.5.1</version>
<name>JFreeChartBuilder</name>
<description>A builder framework for creating JFreeChart charts.</description>

Expand All @@ -15,8 +15,8 @@
<licenses>
<license>
<!-- For compatibility with JFreeChart -->
<name>GNU Lesser General Public Licence 3</name>
<url>http://www.gnu.org/licenses/lgpl-3.0.txt</url>
<name>GNU Lesser General Public Licence 2.1</name>
<url>http://www.gnu.org/licenses/lgpl-2.1.txt</url>
<distribution>repo, manual</distribution>
</license>
</licenses>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/stock-chart-time-series-weekend-gaps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions src/main/java/com/jfcbuilder/builders/ChartBuilder.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* jfreechart-builder: a builder pattern module for working with the jfreechart library
*
* (C) Copyright 2020, by Matt E.
* (C) Copyright 2020, by Matt E. and project contributors
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -70,7 +70,7 @@ private ChartBuilder() {
*
* @return New instance of this class
*/
public static ChartBuilder instance() {
public static ChartBuilder get() {
return new ChartBuilder();
}

Expand Down Expand Up @@ -146,8 +146,8 @@ private void checkBuildPreconditions() throws IllegalStateException {
/**
* Builds the JFreeChart using all configured settings.
*
* @return New instance of a JFreeChart corresponding to all configured data sets and settings.
* @throws IllegalStateException If time data to be shared by all plots was not set.
* @return New instance of a JFreeChart corresponding to all configured data sets and settings
* @throws IllegalStateException If time data to be shared by all plots was not set
*/
public JFreeChart build() {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* jfreechart-builder: a builder pattern module for working with the jfreechart library
*
* (C) Copyright 2020, by Matt E.
* (C) Copyright 2020, by Matt E. and project contributors
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down
Loading

0 comments on commit 6977700

Please sign in to comment.