的
@@ -0,0 +1,154 @@
|
||||
# Advanced XY Series Types
|
||||
Androidplot offers several specialized implementations of XYSeries providing various performance
|
||||
or usability enhancements.
|
||||
|
||||
## EditableXYSeries
|
||||
Enhances the standard XYSeries interface with edit methods.
|
||||
|
||||
## FixedSizeEditableXYSeries
|
||||
An implementation of EditableXYSeries that supports modifying x/y values and has been optimized
|
||||
for speed. FixedSizeEditableXYSeries is optimized for data whose samples may frequently change but
|
||||
whose absolute size doesn't change, such as an ECG (ring buffer) or an animated plot.
|
||||
|
||||
## FastXYSeries
|
||||
By default, Androidplot iterates over every element in each series every render cycle to
|
||||
determine it's current min/max values. This is necessary in order to support dynamic plots where
|
||||
data can change at any moment and invalidate the previously calculated min/max vals.
|
||||
|
||||
FastXYSeries allows the developer to provide a more efficient algorithm to obtain min/max XVals
|
||||
and avoid the high overhead of this iteration. For example, if you know your XVals will always
|
||||
be in strict ascending order then the first and last XVal of the series will always contain the
|
||||
min/max XVals respectively.
|
||||
|
||||
XYSeries implementation supports a min/max algorithm implementation that is more efficient than doing
|
||||
a comparison on each point of the series via iteration. It's a good idea to implement this interface
|
||||
if your series will contain more than about 500 points
|
||||
|
||||
## OrderedXYSeries
|
||||
If the XVals of your series are in ascending order, implementing this interface provides a hint to
|
||||
the series renderer that allows it to avoid iterating over points that are outside the screen's
|
||||
visible domain. For larger data sets, implementing this interface can mean the difference between
|
||||
smooth animations and freezing.
|
||||
|
||||
## ScalingXYSeries
|
||||
Wraps any other instance of XYSeries and provides a simple interface for dynamically
|
||||
scaling x and/or y values. A popular use case for dynamic scaling is to create an animated intro
|
||||
for your XYSeries where yVals increase (or decrease in the case of negative values) from 0 towards
|
||||
their original value. The [AnimatedXYPlotActivity](../demoapp/src/main/java/com/androidplot/demos/AnimatedXYPlotActivity.java)
|
||||
in the DemoApp is one example on how this can be accomplished.
|
||||
|
||||
## SampledXYSeries
|
||||
SampledXYSeries is meant for use with extremely large datasets. Given a series, multiple sampled
|
||||
series instances at stepped resolutions are generated for faster rendering.
|
||||
|
||||
Basic usage:
|
||||
|
||||
```java
|
||||
XYSeries series = ... // instantiate an XYSeries however you want here
|
||||
|
||||
// wrap our series in a SampledXYSeries with a threshold of 1000:
|
||||
SampledXYSeries sampledSeries =
|
||||
new SampledXYSeries(series, OrderedXYSeries.XOrder.ASCENDING, 2,100);
|
||||
|
||||
// add the SampledXYSeries instance to the plot:
|
||||
plot.addSeries(sampledSeries, formatter);
|
||||
```
|
||||
|
||||
SampledXYSeries is meant to be used in conjunction with ZoomEstimator, which enables a plot to
|
||||
automatically render using the resolution appropriate for the current screen boundaries, allowing
|
||||
pan / zoom operations to perform with little or no degradation as series size increases.
|
||||
|
||||
To enable ZoomEstimator:
|
||||
|
||||
```java
|
||||
// enable autoselect of sampling level based on visible boundaries:
|
||||
plot.getRegistry().setEstimator(new ZoomEstimator());
|
||||
```
|
||||
|
||||
[The Touch Zoom Example source code](../demoapp/src/main/java/com/androidplot/demos/TouchZoomExampleActivity.java) provides a functional reference implementation.
|
||||
|
||||
If you want to take advantage of the performance benefits of sampling but don't need pan/zoom support
|
||||
check out the Sampling section below.
|
||||
|
||||
## NormedXYSeries
|
||||
A convenience wrapper to simplify normalizing XYSeries data in the range of 0 to 1. Usage is straightforward:
|
||||
|
||||
```java
|
||||
XYSeries normedSeries = new NormedXYSeries(series);
|
||||
```
|
||||
|
||||
which is equivalent to:
|
||||
|
||||
```java
|
||||
XYSeries normedSeries = new NormedXYSeries(series, null, new Norm(null, 0, false));
|
||||
```
|
||||
|
||||
The first null argument pertains to the normalization being applied to the x axis values. While normalization
|
||||
can certainly be applied on this axis, it's typically unused, which is why the single argument constructor
|
||||
defaults to a null value here.
|
||||
|
||||
Both examples auto normalize the passed in series, maximizing the resolution of the
|
||||
output result. Sometimes however, it's desirable to control the output resolution for the purpose
|
||||
of visually shifting the result up or down in the graph. This can be done by using the `NormedXYSeries.Norm`
|
||||
constructor's second and third arguments: `offset` and `useOffsetCompression`.
|
||||
|
||||
##### offset
|
||||
This value is added to the original normalized value to effectively shift the series data up or down
|
||||
within the normalized range. If the offset is large enough and offset compression is not used, this
|
||||
can cause normalized values to exceed the norm range of 0 to 1.
|
||||
|
||||
##### useOffsetCompression
|
||||
If you want to shift a normalized series up or down in the graph but do not want the shift to potentially
|
||||
move values offscreen, you can set `useOffsetComression` to true. This tells `NormedXYSeries` to shrink
|
||||
the scale of the associated series relative to the offset being used to ensure that normed values
|
||||
stay within the range of 0 to 1. If set to true and you supply an offset <0 or >1, an
|
||||
`IllegalArgumentException` will be thrown.
|
||||
|
||||
We've not talked about the first argument to the `NormedXYSeries.Norm` constructor: `minMax`. This is an
|
||||
optional optimization value that reflects min/max values in the series data being passed in. If they
|
||||
are known, you can pass these in to speed up normalization, otherwise just pass in null and they will
|
||||
be auto calculated.
|
||||
|
||||
IMPORTANT: If your series data is dynamic and it's min/max values change at runtime, you'll need to invoke
|
||||
`NormedXYSeries.normalize(Norm, Norm)` immediately following each change in order to maintain accuracy.
|
||||
|
||||
There's a [reference implementation](../demoapp/src/main/java/com/androidplot/demos/DualScaleActivity.java)
|
||||
of a dual scale plot that demonstrates NormedXYSeries usage in the DemoApp.
|
||||
|
||||
# Sampling
|
||||
Series size is generally the biggest factor when it comes to rendering performance. If you're plotting
|
||||
very large datasets, its generally a good idea to sample the data to improve performance.
|
||||
For example, if you have an XYSeries that consists of 10,000 points, we can sample that data into
|
||||
the 200 points that most accurately represent the profile of the original series:
|
||||
|
||||
```java
|
||||
// An instance of any implementation of XYSeries. Assume it's size is 10,000
|
||||
XYSeries originalSeries = ...;
|
||||
|
||||
// Sampled series of size 200:
|
||||
EditableXYSeries sampledSeries = new FixedSizeEditableXYSeries(
|
||||
originalSeries.getTitle(), 200);
|
||||
|
||||
// an instance of an implementation of Sampler:
|
||||
Sampler sampler = ...
|
||||
|
||||
// do the actual sampling:
|
||||
new LTTBSampler().run(originalSeries, sampledSeries);
|
||||
```
|
||||
|
||||
Currently LTTBSampler is the only available implementation.
|
||||
|
||||
# Storing series data in onSaveInstanceState
|
||||
If your series data requires a non trivial amount of preprocessing (subsampling etc.) or your data comes
|
||||
from a dynamic source, you'll likely want to persist your series data when your Activity saves its
|
||||
instance state. There are a few caveats to be aware of:
|
||||
|
||||
* You can only persist about 1mb worth of data at a time so if your series data is much larger than that
|
||||
you'll need to find a creative solution to the problem
|
||||
* Due to [quirks in the way Android persists data](http://stackoverflow.com/questions/12300886/linkedlist-put-into-intent-extra-gets-recast-to-arraylist-when-retrieving-in-nex)
|
||||
`XYSeries` implementations such as `SimpleXYSeries` that use `LinkedList` instances to store data cannot be serialized directly.
|
||||
* Formatters generally cannot be persisted as they typically contain instances of `Paint` that cannot be serialized directly..
|
||||
|
||||
Due to these limitations we suggest storing `XYSeries` data into an array or `ArrayList` and using that to
|
||||
instantiate your `XYSeries`. The DemoApp's [Time Series Example](../demoapp/src/main/java/com/androidplot/demos/TimeSeriesActivity.java)
|
||||
contains a full source example.
|
||||
@@ -0,0 +1,598 @@
|
||||
_This documentation is auto generated from [attrs.xml](../androidplot-core/src/main/res/values/attrs.xml)._
|
||||
|
||||
# Androidplot XML Attributes
|
||||
Attributes are broken down by element followed by either their type or list of accepted values.
|
||||
Supported Elements:
|
||||
|
||||
* [Plot](#Plot)
|
||||
* [XYPlot](#XYPlot)
|
||||
* [PieChart](#PieChart)
|
||||
|
||||
## Plot
|
||||
Plot's attrs are available in all Plot types.
|
||||
|
||||
### markupEnabled
|
||||
__boolean__
|
||||
|
||||
### renderMode
|
||||
* use_background_thread
|
||||
* use_main_thread
|
||||
|
||||
### marginTop
|
||||
__dimension__
|
||||
|
||||
### marginBottom
|
||||
__dimension__
|
||||
|
||||
### marginLeft
|
||||
__dimension__
|
||||
|
||||
### marginRight
|
||||
__dimension__
|
||||
|
||||
### paddingTop
|
||||
__dimension__
|
||||
|
||||
### paddingBottom
|
||||
__dimension__
|
||||
|
||||
### paddingLeft
|
||||
__dimension__
|
||||
|
||||
### paddingRight
|
||||
__dimension__
|
||||
|
||||
### title
|
||||
__dimension__
|
||||
|
||||
### titleTextSize
|
||||
__string__
|
||||
|
||||
### titleTextColor
|
||||
__dimension__
|
||||
|
||||
### backgroundColor
|
||||
__color__
|
||||
|
||||
### borderColor
|
||||
__color__
|
||||
|
||||
### borderThickness
|
||||
__color__
|
||||
|
||||
## XYPlot
|
||||
XML attributes for the [XYPlot](xyplot.md) class.
|
||||
|
||||
### previewMode
|
||||
TODO
|
||||
|
||||
### domainStepMode
|
||||
* subdivide
|
||||
* increment_by_val
|
||||
* increment_by_pixels
|
||||
|
||||
### domainStep
|
||||
__dimension|float|integer__
|
||||
|
||||
### rangeStepMode
|
||||
* subdivide
|
||||
* increment_by_val
|
||||
* increment_by_pixels
|
||||
|
||||
### rangeStep
|
||||
__dimension|float|integer__
|
||||
|
||||
### domainTitle
|
||||
__string__
|
||||
|
||||
### domainTitleTextColor
|
||||
__color__
|
||||
|
||||
### domainTitleTextSize
|
||||
__dimension__
|
||||
|
||||
### domainTitleHeightMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### domainTitleWidthMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### domainTitleHeight
|
||||
__dimension|float|integer__
|
||||
|
||||
### domainTitleWidth
|
||||
__dimension|float|integer__
|
||||
|
||||
### domainTitleHorizontalPositioning
|
||||
* absolute_from_left
|
||||
* absolute_from_right
|
||||
* absolute_from_center
|
||||
* relative_from_left
|
||||
* relative_from_right
|
||||
* relative_from_center
|
||||
|
||||
`HorizontalPositioning` component of the `HorizontalPosition` of the `TextLabelWidget`
|
||||
that displays the domain title.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### domainTitleVerticalPositioning
|
||||
* absolute_from_top
|
||||
* absolute_from_bottom
|
||||
* absolute_from_center
|
||||
* relative_from_top
|
||||
* relative_from_bottom
|
||||
* relative_from_center
|
||||
|
||||
`VerticalPositioning` component of the `VerticalPosition` of the `TextLabelWidget`
|
||||
that displays the domain title.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### domainTitleHorizontalPosition
|
||||
__dimension|float|integer__
|
||||
|
||||
`float` value component of the `HorizontalPosition` of the `TextLabelWidget`
|
||||
that displays the domain title.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### domainTitleVerticalPosition
|
||||
__dimension|float|integer__
|
||||
|
||||
`float` value component of the `VerticalPosition` of the `TextLabelWidget`
|
||||
that displays the domain title.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### domainTitleAnchor
|
||||
* top_middle
|
||||
* left_top
|
||||
* left_middle
|
||||
* left_bottom
|
||||
* right_top
|
||||
* right_middle
|
||||
* right_bottom
|
||||
* bottom_middle
|
||||
* center
|
||||
|
||||
### domainTitleVisible
|
||||
__boolean__
|
||||
|
||||
### rangeTitle
|
||||
__string__
|
||||
|
||||
### rangeTitleTextColor
|
||||
__color__
|
||||
|
||||
### rangeTitleTextSize
|
||||
__dimension__
|
||||
|
||||
### rangeTitleHeightMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### rangeTitleWidthMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### rangeTitleHeight
|
||||
__dimension|float|integer__
|
||||
|
||||
### rangeTitleWidth
|
||||
__dimension|float|integer__
|
||||
|
||||
### rangeTitleHorizontalPositioning
|
||||
* absolute_from_left
|
||||
* absolute_from_right
|
||||
* absolute_from_center
|
||||
* relative_from_left
|
||||
* relative_from_right
|
||||
* relative_from_center
|
||||
|
||||
### rangeTitleVerticalPositioning
|
||||
* absolute_from_top
|
||||
* absolute_from_bottom
|
||||
* absolute_from_center
|
||||
* relative_from_top
|
||||
* relative_from_bottom
|
||||
* relative_from_center
|
||||
|
||||
### rangeTitleHorizontalPosition
|
||||
__dimension|float|integer__
|
||||
|
||||
### rangeTitleVerticalPosition
|
||||
__dimension|float|integer__
|
||||
|
||||
### rangeTitleAnchor
|
||||
* top_middle
|
||||
* left_top
|
||||
* left_middle
|
||||
* left_bottom
|
||||
* right_top
|
||||
* right_middle
|
||||
* right_bottom
|
||||
* bottom_middle
|
||||
* center
|
||||
|
||||
### rangeTitleVisible
|
||||
__boolean__
|
||||
|
||||
### drawGridOnTop
|
||||
__boolean__
|
||||
<br/>
|
||||
(default is false) When set to true, grid lines are drawn on top of rendered series data
|
||||
instead of underneath.
|
||||
|
||||
### graphHeightMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### graphWidthMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### graphHeight
|
||||
__dimension|float|integer__
|
||||
|
||||
### graphWidth
|
||||
__dimension|float|integer__
|
||||
|
||||
### graphRotation
|
||||
* none
|
||||
* ninety_degrees
|
||||
* negative_ninety_degrees
|
||||
* one_hundred_eighty_degrees
|
||||
|
||||
### graphHorizontalPositioning
|
||||
* absolute_from_left
|
||||
* absolute_from_right
|
||||
* absolute_from_center
|
||||
* relative_from_left
|
||||
* relative_from_right
|
||||
* relative_from_center
|
||||
|
||||
`HorizontalPositioning` component of the `HorizontalPosition` of the `XYGraphWidget`.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### graphVerticalPositioning
|
||||
* absolute_from_top
|
||||
* absolute_from_bottom
|
||||
* absolute_from_center
|
||||
* relative_from_top
|
||||
* relative_from_bottom
|
||||
* relative_from_center
|
||||
|
||||
`VerticalPositioning` component of the `VerticalPosition` of the `XYGraphWidget`.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### graphHorizontalPosition
|
||||
__dimension|float|integer__
|
||||
|
||||
`float` value component of the `HorizontalPosition` of the `XYGraphWidget`.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### graphVerticalPosition
|
||||
__dimension|float|integer__
|
||||
|
||||
`float` value component of the `VerticalPosition` of the `XYGraphWidget`.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### graphAnchor
|
||||
* top_middle
|
||||
* left_top
|
||||
* left_middle
|
||||
* left_bottom
|
||||
* right_top
|
||||
* right_middle
|
||||
* right_bottom
|
||||
* bottom_middle
|
||||
* center
|
||||
|
||||
### graphVisible
|
||||
__boolean__
|
||||
|
||||
### graphMarginTop
|
||||
__dimension__
|
||||
|
||||
### graphMarginBottom
|
||||
__dimension__
|
||||
|
||||
### graphMarginLeft
|
||||
__dimension__
|
||||
|
||||
### graphMarginRight
|
||||
__dimension__
|
||||
|
||||
### graphPaddingTop
|
||||
__dimension__
|
||||
|
||||
### graphPaddingBottom
|
||||
__dimension__
|
||||
|
||||
### graphPaddingLeft
|
||||
__dimension__
|
||||
|
||||
### graphPaddinRight
|
||||
__dimension__
|
||||
|
||||
### gridClippingEnabled
|
||||
__boolean__
|
||||
|
||||
### gridInsetTop
|
||||
__dimension__
|
||||
|
||||
### gridInsetBottom
|
||||
__dimension__
|
||||
|
||||
### gridInsetLeft
|
||||
__dimension__
|
||||
|
||||
### gridInsetRight
|
||||
__dimension__
|
||||
|
||||
### lineLabelInsetTop
|
||||
__dimension__
|
||||
<br/>
|
||||
Top edge of a rectangle relative to the XYGraphWidget
|
||||
border upon which line labels will be anchored.
|
||||
|
||||
### lineLabelInsetBottom
|
||||
__dimension__
|
||||
<br/>
|
||||
Bottom edge of a rectangle relative to the XYGraphWidget
|
||||
border upon which line labels will be anchored.
|
||||
|
||||
### lineLabelInsetLeft
|
||||
__dimension__
|
||||
<br/>
|
||||
Left edge of a rectangle relative to the XYGraphWidget
|
||||
border upon which line labels will be anchored.
|
||||
|
||||
### lineLabelInsetRight
|
||||
__dimension__
|
||||
<br/>
|
||||
Right edge of a rectangle relative to the XYGraphWidget
|
||||
border upon which line labels will be anchored.
|
||||
|
||||
### lineLabels
|
||||
* top
|
||||
* bottom
|
||||
* left
|
||||
* right
|
||||
|
||||
Enable line labels on one or more edge of the graph. For example, to enable labels on the left
|
||||
and bottom edges:
|
||||
```
|
||||
ap:lineLabels="left|bottom"
|
||||
```
|
||||
|
||||
### lineLabelAlignTop
|
||||
* left
|
||||
* center
|
||||
* right
|
||||
|
||||
Text alignment of line labels drawn on top edge of the plot. This alignment is applied relative
|
||||
to the line label insets defined by `lineLabelInsetTop`.
|
||||
|
||||
### lineLabelAlignBottom
|
||||
* left
|
||||
* center
|
||||
* right
|
||||
|
||||
Text alignment of line labels drawn on bottom edge of the plot. This alignment is applied relative
|
||||
to the line label insets defined by `lineLabelInsetBottom`.
|
||||
|
||||
### lineLabelAlignLeft
|
||||
* left
|
||||
* center
|
||||
* right
|
||||
|
||||
Text alignment of line labels drawn on left edge of the plot. This alignment is applied relative
|
||||
to the line label insets defined by `lineLabelInsetLeft`.
|
||||
|
||||
### lineLabelAlignRight
|
||||
* left
|
||||
* center
|
||||
* right
|
||||
|
||||
Text alignment of line labels drawn on right edge of the plot. This alignment is applied relative
|
||||
to the line label insets defined by `lineLabelInsetRight`.
|
||||
|
||||
### lineLabelRotationTop
|
||||
__float__
|
||||
<br/>
|
||||
Angle at which line labels on the plot's top edge are drawn.
|
||||
|
||||
### lineLabelRotationBottom
|
||||
__float__
|
||||
<br/>
|
||||
Angle at which line labels on the plot's bottom edge are drawn.
|
||||
|
||||
### lineLabelRotationLet
|
||||
__float__
|
||||
<br/>
|
||||
Angle at which line labels on the plot's left edge are drawn.
|
||||
|
||||
### lineLabelRotationRight
|
||||
__float__
|
||||
<br/>
|
||||
Angle at which line labels on the plot's right edge are drawn.
|
||||
|
||||
### domainLineThickness
|
||||
__dimension__
|
||||
|
||||
### rangeLineThickness
|
||||
__dimension__
|
||||
|
||||
### domainLineColor
|
||||
__color__
|
||||
|
||||
### rangeLineColor
|
||||
__color__
|
||||
|
||||
### domainOriginLineThickness
|
||||
__dimension__
|
||||
|
||||
### rangeOriginLineThickness
|
||||
__dimension__
|
||||
|
||||
### domainOriginLineColor
|
||||
__color__
|
||||
|
||||
### rangeOriginLineColor
|
||||
__color__
|
||||
|
||||
### lineLabelTextSizeTop
|
||||
__dimension__
|
||||
|
||||
### lineLabelTextSizeBottom
|
||||
__dimension__
|
||||
|
||||
### lineLabelTextSizeLeft
|
||||
__dimension__
|
||||
|
||||
### lineLabelTextSizeRight
|
||||
__dimension__
|
||||
|
||||
### lineLabelTextColorTop
|
||||
__color__
|
||||
|
||||
### lineLabelTextColorBottom
|
||||
__color__
|
||||
|
||||
### lineLabelTextColorLeft
|
||||
__color__
|
||||
|
||||
### lineLabelTextColorRight
|
||||
__color__
|
||||
|
||||
### lineExtensionTop
|
||||
__dimension__
|
||||
|
||||
### lineExtensionBottom
|
||||
__dimension__
|
||||
|
||||
### lineExtensionLeft
|
||||
__dimension__
|
||||
|
||||
### lineExtensionRight
|
||||
__dimension__
|
||||
|
||||
### gridBackgroundColor
|
||||
__color__
|
||||
<br/>
|
||||
background color of the grid portion of the XYGraphWidget
|
||||
|
||||
### graphBackgroundColor
|
||||
__color__
|
||||
<br/>
|
||||
background color of the XYGraphWidget
|
||||
|
||||
### legendHeightMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### legendWidthMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### legendHeight
|
||||
__dimension|float|integer__
|
||||
|
||||
### legendWidth
|
||||
__dimension|float|integer__
|
||||
|
||||
### legendHorizontalPositioning
|
||||
`HorizontalPositioning` component of the `HorizontalPosition` of the `XYLegendWidget`.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
* absolute_from_left
|
||||
* absolute_from_right
|
||||
* absolute_from_center
|
||||
* relative_from_left
|
||||
* relative_from_right
|
||||
* relative_from_center
|
||||
|
||||
### legendVerticalPositioning
|
||||
`VerticalPositioning` component of the `VerticalPosition` of the `XYLegendWidget`.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
* absolute_from_top
|
||||
* absolute_from_bottom
|
||||
* absolute_from_center
|
||||
* relative_from_top
|
||||
* relative_from_bottom
|
||||
* relative_from_center
|
||||
|
||||
### legendHorizontalPosition
|
||||
__dimension|float|integer__
|
||||
|
||||
`float` value component of the `HorizontalPosition` of the `XYLegendWidget`.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### legendVerticalPosition
|
||||
__dimension|float|integer__
|
||||
|
||||
`float` value component of the `VerticalPosition` of the `XYLegendWidget`.
|
||||
See [Positioning Widgets](plot_composition.md#positioning-widgets) documentation.
|
||||
|
||||
### legendAnchor
|
||||
* top_middle
|
||||
* left_top
|
||||
* left_middle
|
||||
* left_bottom
|
||||
* right_top
|
||||
* right_middle
|
||||
* right_bottom
|
||||
* bottom_middle
|
||||
* center
|
||||
|
||||
### legendTextSize
|
||||
__dimension__
|
||||
|
||||
### legendTextColor
|
||||
__color__
|
||||
|
||||
### legendIconHeightMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### legendIconWidthMode
|
||||
* absolute
|
||||
* relative
|
||||
* fill
|
||||
|
||||
### legendIconHeight
|
||||
__dimension|float|integer__
|
||||
|
||||
### legendIconWidth
|
||||
__dimension|float|integer__
|
||||
|
||||
### legendVisible
|
||||
__boolean__
|
||||
|
||||
### pieBorderThickness
|
||||
__dimension__
|
||||
<br/>
|
||||
Determines how far beyond the graph's edge each domain grid line will extend.
|
||||
|
||||
### pieBorderThickness
|
||||
__dimension__
|
||||
<br/>
|
||||
Determines how far beyond the graph's edge each range grid line will extend.
|
||||
|
||||
## PieChart
|
||||
TODO
|
||||
|
||||
### pieBorderColor
|
||||
__color__
|
||||
|
||||
### pieBorderThickness
|
||||
__dimension__
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# Bar Charts
|
||||
Bar Charts are drawn with `BarRenderer` by converting xy values of an `XYSeries` into
|
||||
vertical bars. The height of the vertical bar is calculated from the yVal and the base
|
||||
of the bar is calculated from the plot's range origin value.
|
||||
|
||||

|
||||
|
||||
# Basic Usage
|
||||
Rendering an `XYSeries` as a bar chart is as simple as adding the series to an `XYPlot` with an
|
||||
instance of `BarFormatter`:
|
||||
|
||||
```java
|
||||
// create a bar formatter with a red fill color and a white outline:
|
||||
BarFormatter bf = new BarFormatter(Color.RED, Color.WHITE);
|
||||
plot.addSeries(series, bf);
|
||||
```
|
||||
|
||||
# BarRenderer
|
||||
Unlike most other renderers, much of the visual configuration of a bar chart is configured through it's `BarRenderer`.
|
||||
`BarRenderer` provides methods for setting how the width of each bar should be calculated, the space between each `Bar`
|
||||
and what style of visual grouping to use.
|
||||
|
||||
|
||||
##### Getting the BarRenderer Instance
|
||||
Many of the topics below require access to the `BarRenderer` instance to be set. Each instance of
|
||||
`XYPlot` contains it's own unique `Renderer` instances. To retrieve the `BarRenderer`
|
||||
instance from an `XYPlot`:
|
||||
|
||||
```java
|
||||
BarRenderer renderer = plot.getRenderer(BarRenderer.class);
|
||||
```
|
||||
|
||||
# BarGroup
|
||||
A `BarGroup` is automatically generated to group values from one or more series by their index values.
|
||||
All `Bar` instances belong to a `BarGroup`, even if there is only a single `XYSeries` that exists.
|
||||
|
||||
A common use case of bar charts is to represent a group of two or more values for a given interval as
|
||||
individual bars, for example the number of wins and losses for a baseball team for every month over the course
|
||||
of a year.
|
||||
|
||||
To model this in Androidplot, create two instances of `XYSeries`; one for wins and one for losses, each
|
||||
with exactly 12 elements (one for each day of the month):
|
||||
|
||||
```java
|
||||
XYSeries wins = new SimpleXYSeries(SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "wins", 3, 4, 5, 3, 2, 3, 5, 6, 2, 1, 3, 1);
|
||||
XYSeries losses = new SimpleXYSeries(SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "losses", 0, 1, 1, 0, 1, 0, 0, 0, 2, 1, 0, 1);
|
||||
```
|
||||
|
||||
Each series is then added to the plot with it's own formatter:
|
||||
|
||||
```java
|
||||
// draw wins bars with a green fill:
|
||||
BarFormatter winsFormatter = new BarFormatter(Color.GREEN, Color.BLACK);
|
||||
plot.addSeries(wins, winsFormatter);
|
||||
|
||||
// draw losses bars with a red fill:
|
||||
BarFormatter lossesFormatter = new BarFormatter(Color.RED, Color.BLACK);
|
||||
plot.addSeries(losses, lossesFormatter);
|
||||
```
|
||||
|
||||
The pairs of wins/losses bars are then drawn side-by-side for each of the 12 indexes. Androidplot
|
||||
knows to do this because `BarRenderer` (the renderer used to draw series associated with a `BarFormatter`)
|
||||
extends [GroupRenderer](grouprenderer.md).
|
||||
|
||||
# BarRenderer Styles
|
||||
`BarRenderer` provides three grouping styles that may be used when rendering two or more XYSeries:
|
||||
`OVERLAID`, `STACKED`, `SIDE_BY_SIDE`
|
||||
|
||||
##### OVERLAID (default)
|
||||
Bars in the same grouping are overlaid on each-other, the bars being drawn by yVal in descending order.
|
||||
|
||||

|
||||
|
||||
|
||||
To use:
|
||||
```java
|
||||
barRenderer.setBarOrientation(BarRenderer.BarOrientation.OVERLAID);
|
||||
```
|
||||
|
||||
##### STACKED
|
||||
Bars in the same group are stacked on top of each-other. Limitations:
|
||||
* Range Origin must be set to 0.
|
||||
* All `XYSeries` must contain no negative values.
|
||||
|
||||

|
||||
|
||||
To use:
|
||||
```java
|
||||
barRenderer.setBarOrientation(BarRenderer.BarOrientation.STACKED);
|
||||
```
|
||||
|
||||
##### SIDE_BY_SIDE
|
||||
Bars in the same group are drawn next to one another.
|
||||
|
||||

|
||||
|
||||
To use:
|
||||
```java
|
||||
barRenderer.setBarOrientation(BarRenderer.BarOrientation.SIDE_BY_SIDE);
|
||||
```
|
||||
|
||||
By default there is no spacing between bars in the same `BarGroup` in this mode. You can add spacing
|
||||
by setting a left and right margin on your BarFormatter instances:
|
||||
|
||||
```java
|
||||
barFormatter.setMarginLeft(PixelUtils.dpToPix(1));
|
||||
barFormatter.setMarginRight(PixelUtils.dpToPix(1));
|
||||
```
|
||||
|
||||
# BarGroup Widths & Spacing
|
||||
When configuring BarGroup widths and spacing, there are two mutually exclusive methods that can be used;
|
||||
`FIXED_WIDTH` and `FIXED_GAP`.
|
||||
|
||||

|
||||
|
||||
##### FIXED_WIDTH
|
||||
The exact size of the `BarGroup` is specified in pixels and the space between each `BarGroup`
|
||||
is dynamically calculated based on that size.
|
||||
|
||||
```java
|
||||
barRenderer.setBarGroupWidth(BarRenderer.BarGroupWidthMode.FIXED_WIDTH, PixelUtils.dpToPix(25));
|
||||
```
|
||||
##### FIXED_GAP
|
||||
The exact size of the "gap" between each `BarGroup` is specified in pixels and the size of each `BarGroup`
|
||||
is dynamically calculated based on that spacing.
|
||||
|
||||
```java
|
||||
barRenderer.setBarGroupWidth(BarRenderer.BarGroupWidthMode.FIXED_GAP, PixelUtils.dpToPix(5));
|
||||
```
|
||||
|
||||
# Example
|
||||
See the DemoApp's [bar chart example source](../demoapp/src/main/java/com/androidplot/demos/BarPlotExampleActivity.java).
|
||||
@@ -0,0 +1,53 @@
|
||||
# Bubble Charts
|
||||
A `BubbleChart` is a two dimensional representation of three dimensional data
|
||||
on an `XYPlot`, where the xy values are drawn as a circle with a radius representing the zVal.
|
||||
|
||||

|
||||
|
||||
# Basic Usage
|
||||
The first step in creating a `BubbleChart` is to define the data to be plotted. We'll start
|
||||
by creating an instance of `BubbleSeries`:
|
||||
|
||||
Using the implicit iVal for x:
|
||||
|
||||
```java
|
||||
BubbleSeries series1 = new BubbleSeries(
|
||||
Arrays.asList(new Number[]{3, 5, 2, 3, 6}), // xCoordinate
|
||||
Arrays.asList(new Number[]{1, 5, 2, 2, 3}), "s1"); // yCoordinate
|
||||
```
|
||||
|
||||
Or it's equivalent four argument counterpart:
|
||||
|
||||
```java
|
||||
BubbleSeries bubbleSeries = new BubbleSeries(
|
||||
Arrays.asList(new Number[]{0, 1, 2, 3, 4}), // xCoordinate
|
||||
Arrays.asList(new Number[]{3, 5, 2, 3, 6}), // yCoordinate
|
||||
Arrays.asList(new Number[]{1, 5, 2, 2, 3}), // zVal (corresponds to radius)
|
||||
"s1");
|
||||
```
|
||||
|
||||
Next, create a `Formatter` defining the fill and outline colors of the bubbles:
|
||||
|
||||
|
||||
```java
|
||||
// draw bubbles with a green fill and white outline:
|
||||
BubbleFormatter formatter = new BubbleFormatter(Color.GREEN, Color.WHITE)
|
||||
```
|
||||
|
||||
Finally, add the `BubbleSeries` to our plot as you would any other `XYSeries` instance:
|
||||
|
||||
```java
|
||||
plot.addSeries(bubbleSeries, formatter);
|
||||
```
|
||||
|
||||
# BubbleScaleMode
|
||||
By default, `BubbleRenderer` scales each rendered bubble radius using the square root of it's corresponding
|
||||
zVal, preventing apparent size differences in each bubble radius from being visually misleading. See: https://en.wikipedia.org/wiki/Bubble_chart#Choosing_bubble_sizes_correctly
|
||||
|
||||
If you'd prefer to use a linear scale:
|
||||
|
||||
```java
|
||||
plot.getRenderer(BubbleRenderer.class).setBubbleScaleMode(BubbleRenderer.BubbleScaleMode.LINEAR);
|
||||
```
|
||||
# Example
|
||||
Check out the [bubble chart example source](../demoapp/src/main/java/com/androidplot/demos/BubbleChartActivity.java) for a full source example of a bubble chart.
|
||||
@@ -0,0 +1,77 @@
|
||||
# Candlestick Charts
|
||||
Candlestick charts are a special kind of `XYPlot` usually used for rendering financial information.
|
||||
Each "candlestick" is composed of 4 values: open, close, high and low.
|
||||
|
||||

|
||||
|
||||
Androidplot's implementation of candlestick charts uses four separate `XYSeries` instances to represent
|
||||
the candlestick values; each series corresponds to one of the four values that composes each "candlestick".
|
||||
|
||||
For example:
|
||||
|
||||
```java
|
||||
Number[] highVals = new Number[] {12, 10, 15, 8, 7};
|
||||
Number[] lowVals = new Number[] {3, 1, 5, 0, 2};
|
||||
Number[] openVals = new Number[] {5, 2, 7, 5, 3};
|
||||
Number[] closeVals = new Number[] {7, 9, 6, 0, 4};
|
||||
```
|
||||
|
||||
Using the values above, the first candlestick model would be `{high=12, low=3, open=5, close=7}`,
|
||||
the second would be `{high=10, low=1, open=2, close=7}` and so on.
|
||||
|
||||
There are a few constraints that must be satisfied before we can create XYSeries from the data above and add them to Androidplot:
|
||||
|
||||
* Each series must be of the same size.
|
||||
* Each series must have the same x(i); getX(i) must return the same value for each series.
|
||||
* There must be exactly four series, added in the precise order: high, low, open, close.
|
||||
* The series data must make sense; each candlestick's high must be equal to or greater than all other
|
||||
values in the candlestick, and each candlestick's low must be less than or equal to all other values.
|
||||
* Each candlestick series belonging to the same candlestick chart must use the same `CandlestickFormatter`
|
||||
instance when being added to the XYPlot.
|
||||
|
||||
While it's possible to satisfy these constraints by creating each of the four `XYSeries` required by a
|
||||
candlestick chart, adding them in order using the same formatter, many projects will find it simpler
|
||||
to interact with the data as though it were a single series of candlestick values. To makr this easier,
|
||||
two convenience classes: `CandlestickSeries` and `CandlestickMaker`. Here's how they are used together to add a candlestick chart to an `XYPlot`:
|
||||
|
||||
```java
|
||||
CandlestickSeries candlestickSeries = new CandlestickSeries(
|
||||
new CandlestickSeries.Item(1, 10, 2, 9),
|
||||
new CandlestickSeries.Item(4, 18, 6, 5),
|
||||
new CandlestickSeries.Item(3, 11, 5, 10),
|
||||
new CandlestickSeries.Item(2, 17, 2, 15),
|
||||
new CandlestickSeries.Item(6, 11, 11, 7),
|
||||
new CandlestickSeries.Item(8, 16, 10, 15));
|
||||
|
||||
CandlestickFormatter formatter = new CandlestickFormatter();
|
||||
|
||||
// add the candlestick series data to the plot:
|
||||
CandlestickMaker.make(plot, formatter, candlestickSeries);
|
||||
```
|
||||
|
||||
It's necessary to use `CandlestickMaker` to add the `CandlestickSeries` (via "make") to the
|
||||
`XYPlot` as `CandlestickSeries` does not and cannot implement the `XYSeries` interface.
|
||||
|
||||
|
||||
[A full source example is available here](../demoapp/src/main/java/com/androidplot/demos/CandlestickChartActivity.java).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# Contributing Soure Code
|
||||
Contributions are always welcome! If you've got an idea for a specific feature and would like feedback
|
||||
on implementation or if you want to contribute but don't know where to start, feel free to [
|
||||
start a topic in the Forums](https://groups.google.com/forum/#!forum/androidplot). If you already have
|
||||
a feature or bugfix to submit, take a look at the code style notes below and then submit a Pull Request.
|
||||
|
||||
## Code Style
|
||||
For familiarity and simplicity, Androidplot uses [Android's code style guide](https://source.android.com/source/code-style.html).
|
||||
In particular:
|
||||
|
||||
* Indentations are 4 spaces each - no tab characters.
|
||||
* Braces do not go on their own line; they go on the same line as the code before them.
|
||||
* Line length should be a max of 100 characters.
|
||||
* Don't catch generic Exception and don't ignore caught exceptions.
|
||||
* Classes and methods should be documented with standard Javadoc comments.
|
||||
|
||||
## Pull Requests
|
||||
If you have code changes you'd like to share with the project, issue a [Pull Request](https://help.github.com/articles/about-pull-requests/) against the master
|
||||
branch of Androidplot. Please make sure that:
|
||||
|
||||
* Difficult to follow logical statements, etc. are reasonably documented.
|
||||
* Commented out lines, unused methods / dead code blocks have been removed.
|
||||
* Unit Tests have have been refactored appropriately and all pass.
|
||||
* A clear description of the change is included in the Pull Request.
|
||||
|
||||
Adding Unit Tests for new methods / functionality is highly encouraged.
|
||||
|
||||
# Git Newcomers
|
||||
If you're new to Git, this section will show you the basics of checking out a local copy of the project and building it.
|
||||
|
||||
## Clone
|
||||
Androidplot is hosted on Github. If you've got a git client installed, you can either
|
||||
[fork](https://help.github.com/articles/fork-a-repo/) the project into your own
|
||||
github account, or you can clone the project to your workstation using this command:
|
||||
|
||||
```
|
||||
git clone https://github.com/halfhp/androidplot.git
|
||||
```
|
||||
|
||||
You can also [download an ZIP](https://github.com/halfhp/androidplot/archive/master.zip) of the master branch of Androidplot.
|
||||
|
||||
## Build
|
||||
Androidplot is a Gradle project, which makes building incredibly easy. To perform a full build (runs tests,
|
||||
generates javadocs and builds the library and demo app) from the command line:
|
||||
|
||||
```
|
||||
./gradlew test assemble
|
||||
```
|
||||
You can also of course use the IDE of your choice instead. [Android Studio](https://developer.android.com/studio/index.html) is highly recommended.
|
||||
|
||||
## Useful Links
|
||||
If you're new to Git these links will get you started:
|
||||
|
||||
* [Setting up Git](https://help.github.com/articles/set-up-git/) Start here if you don't have a Git client installed.
|
||||
* [Pro Git (free eBook)](https://git-scm.com/book/en/v2) - _The_ book to read when it comes to learning Git
|
||||
* [Git Reference](https://git-scm.com/docs) - Good set of links for general reference
|
||||
@@ -0,0 +1,101 @@
|
||||
# Custom Renderers
|
||||
Androidplot renderers can be extended with extra functionality in the form of custom renderers.
|
||||
For the example below we'll look at creating a custom implementation of BarRenderer that will
|
||||
draw bars with rounded edges. While this example demonstrates an `XYPlot`, the steps apply to
|
||||
`PieChart` etc. as well.
|
||||
|
||||
## Create the Formatter
|
||||
The first step to creating a custom renderer is defining it's `Formatter`. Aside from providing
|
||||
the visual configuration used by the `Renderer` to draw series data, it's also used by Androidplot
|
||||
to map a series to a specific renderer type and if necessary, obtain a new instance of that renderer.
|
||||
Here's the most basic implementation:
|
||||
|
||||
```java
|
||||
class RoundedBarFormatter extends BarFormatter {
|
||||
|
||||
{
|
||||
// for now we'll hardcode some formatting values.
|
||||
// a real implementation would probably provide a constructor instead
|
||||
getBorderPaint().setColor(Color.WHITE);
|
||||
getFillPaint().setColor(Color.RED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<RoundedBarRenderer> getRendererClass() {
|
||||
return RoundedBarRenderer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoundedBarRenderer doGetRendererInstance(XYPlot xyPlot) {
|
||||
return new RoundedBarRenderer(xyPlot);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Create the Renderer
|
||||
All we want to do here is tweak the way `BarRenderer` behaves a little so we'll use it as our base class:
|
||||
|
||||
```java
|
||||
class RoundedBarRenderer extends BarRenderer<RoundedBarFormatter> {
|
||||
|
||||
public RoundedBarRenderer(XYPlot plot) {
|
||||
super(plot);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBar(Canvas canvas, Bar<RoundedBarFormatter> bar, RectF rect) {
|
||||
// TODO this is where we'll add our custom behavior
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the case of our RoundedBarFormatter, the behavior we need to change all exits within the
|
||||
`drawBar(Canvas, Bar, RectF)` method. The existing implementation uses `Canvas.drawRect(...)` to
|
||||
draw bars. We could use a stroke with rounded edges, but this would cause the edges on both the top
|
||||
and the bottom to be rounded, which won't look right. We'll draw using a path instead:
|
||||
|
||||
```java
|
||||
@Override
|
||||
protected void drawBar(Canvas canvas, Bar<RoundedBarFormatter> bar, RectF rect) {
|
||||
|
||||
// skip nulls:
|
||||
if(bar.getY() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoundedBarFormatter formatter = getFormatter(bar.i, bar.series);
|
||||
if(formatter == null) {
|
||||
formatter = bar.formatter;
|
||||
}
|
||||
|
||||
// don't need to draw if the bar lacks height or width:
|
||||
if (rect.height() > 0 && rect.width() > 0) {
|
||||
final Path path = new Path();
|
||||
final float arcHeightPx = 20;
|
||||
final float adjustedTop = rect.top + arcHeightPx;
|
||||
final RectF cap = new RectF(rect.left, rect.top, rect.right,rect.top + 2 * arcHeightPx);
|
||||
|
||||
// start at bottom-left and move clock-wise around the shape:
|
||||
path.moveTo(rect.left, rect.bottom);
|
||||
path.lineTo(rect.left, adjustedTop);
|
||||
path.arcTo(cap, 180, 180, false);
|
||||
path.lineTo(rect.right, rect.bottom);
|
||||
path.close();
|
||||
|
||||
canvas.drawPath(path, formatter.getFillPaint());
|
||||
canvas.drawPath(path, formatter.getBorderPaint());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Use It
|
||||
Using the new custom renderer is as easy as adding a series to a plot using `RoundedBarFormatter`:
|
||||
|
||||
```java
|
||||
plot.addSeries(series1, new RoundedBarFormatter(Color.RED));
|
||||
plot.addSeries(series2, new RoundedBarFormatter(Color.BLUE));
|
||||
```
|
||||
|
||||
Here's what this would look like used in the demo app's `SimpleXYPlotActivity`:
|
||||
|
||||

|
||||
@@ -0,0 +1,88 @@
|
||||
# Plotting Dynamic Data
|
||||
One of Androidplot's core focuses is on plotting dynamically changing data in real-time. Special care has
|
||||
been put into the design of the library to provide solutions for various scenarios and synchronization concerns.
|
||||
|
||||
# Background Rendering
|
||||
By default, Androidplot does all of it's rendering on the UI thread. While this is fine for most applications,
|
||||
it can cause performance issues when rendering larger datasets or when continuously redrawing dynamic data.
|
||||
To resolve this issue, Androidplot provides a background rendering mode that can be enabled programmatically in
|
||||
your Java source or via XML:
|
||||
|
||||
**Programmatically:**
|
||||
```java
|
||||
plot.setRenderMode(Plot.RenderMode.USE_BACKGROUND_THREAD);
|
||||
```
|
||||
|
||||
**XML:**
|
||||
```xml
|
||||
ap:renderMode="use_background_thread"
|
||||
```
|
||||
|
||||
In general, if your plot is continuously redrawing the plot, you should use background rendering.
|
||||
|
||||
#Rendering Dynamic Data
|
||||
There are two general approaches to dynamically rendering data: event driven and render loops. Each has
|
||||
pros and cons and often times, the application might force you to use one approach over the other, however
|
||||
90% of the time using a render loop is the better approach.
|
||||
|
||||
In both cases the redraw is triggered by invoking `Plot.redraw().`
|
||||
|
||||
## Render Loops
|
||||
A render loop is basically a continuous loop of calls to a render routine. This loop might
|
||||
include logic for updating the data being plotted, or it might simply focus on maintaining a stable refresh rate.
|
||||
Androidplot provides a convenience utility, Redrawer which provides a basic implementation of a render loop
|
||||
running on a fixed frequency. Check out the [ECG demo source](../demoapp/src/main/java/com/androidplot/demos/ECGExample.java) for a working example.
|
||||
|
||||
## Event Driven Redraws
|
||||
Sometimes it's more efficient to only redraw the plot as a result of an event such as a GPS update, button click, etc.
|
||||
Event driven updates are as simple as invoking `Plot.redraw()` from the callback handling the event of interest,
|
||||
after the data being plotted has been updated. While it's possible for the event triggering the redraw
|
||||
to fire at a faster rate than the plot is capable of redrawing, no special care needs to be taken as Androidplot
|
||||
ignores subsequent invocations of redraw() when a previous invocation is already active.
|
||||
|
||||
# Synchronization
|
||||
A major challenge of plotting dynamic data is the need to render an accurate representation of the data
|
||||
as it existed at a specific point in time. This is not a trivial problem and the right solution depends
|
||||
greatly on the specific details of the project. Presented here are a list of items to keep in mind
|
||||
along with general best practices and approaches to solving more common problems.
|
||||
|
||||
The most common scenario is when your data model is being dynamically updated by a background thread.
|
||||
Regardless of whether or not you use background rendering here, invoking plot.redraw() is asynchronous
|
||||
and your background thread can easily loop around and start altering values while your plot is half way through
|
||||
rendering the previous set of values. The result of a race condition is indeterminate; if the size of your data
|
||||
changed the app could crash from an IndexOutOfBoundsException, or a bogus representation of your data might
|
||||
be rendered to the display.
|
||||
|
||||
To prevent the race condition, changes to the data model must be synchronized with Androidplot's
|
||||
rendering loop. A PlotListener can be used to detect when a Plot begins and ends a redraw and a read-write
|
||||
can be used to protect the model (typically any series data being drawn):
|
||||
|
||||
```java
|
||||
plot.addListener(new PlotListener() {
|
||||
@Override
|
||||
public void onBeforeDraw(Plot source, Canvas canvas) {
|
||||
// write-lock each active series for writes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterDraw(Plot source, Canvas canvas) {
|
||||
// unlock any locked series
|
||||
}
|
||||
});
|
||||
```
|
||||
Note that if your custom series implements the PlotListener interface, it's onBeforeDraw and onAfterDraw
|
||||
methods will be automatically called when the series is rendered, without the need for adding it
|
||||
as a listener to the plot. SimpleXYSeries provides a reference implementation of this synchronization
|
||||
technique.
|
||||
|
||||
In-depth usage of thread synchronization and read-write locks is beyond scope for this doc but you can
|
||||
check out the source code of the SimpleXYSeries class for a functional example of ReentrantReadWriteLock
|
||||
being used to synchronize an XYSeries implementation.
|
||||
|
||||
# Examples
|
||||
Androidplot provides a few full-source examples of how to dynamically plot data as demonstrated
|
||||
in the [demo app](https://play.google.com/store/apps/details?id=com.androidplot.demos&hl=en).
|
||||
|
||||
* [Plotting Realtime Orientation Sensor Data](../demoapp/src/main/java/com/androidplot/demos/OrientationSensorExampleActivity.java)
|
||||
* [An ECG Example](../demoapp/src/main/java/com/androidplot/demos/ECGExample.java)
|
||||
* [A simple dynamic XYPlot](../demoapp/src/main/java/com/androidplot/demos/DynamicXYPlotActivity.java)
|
||||
@@ -0,0 +1,18 @@
|
||||
# GroupRenderer
|
||||
`GroupRenderer` is a special implementation of `XYSeriesRenderer` that combines multiple instances
|
||||
of `XYSeries` into a single virtual series of s higher dimension. Examples of `GroupRenderer` are:
|
||||
|
||||
* BarRenderer
|
||||
* CandlestickRenderer
|
||||
|
||||
Let's take a quick look at `CandlestickRenderer`. A candlestick chart is basically a two two dimensional
|
||||
representation of a complex value; for every value of x a single candlestick is drawn, but there are
|
||||
four values (dimensions) that make up each candlestick:
|
||||
|
||||
* open
|
||||
* close
|
||||
* high
|
||||
* low
|
||||
|
||||
When a series is added to the plot with a formatter associated with a renderer that extends `GroupRenderer`,
|
||||
all series added with formatters of the same type are automatically "grouped" together during rendering.
|
||||
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 420 KiB |
@@ -0,0 +1,7 @@
|
||||
# About Androidplot Screenshots
|
||||
Screenshots should be added to this directory for each new plot type. These screens should
|
||||
conform to the following guidelines:
|
||||
|
||||
* Screenshots framed in Nexus5x, no glare, no shadows
|
||||
* Horizontal screen dimensions: 950w * 484h
|
||||
* Vertical screen dimensions 484w * 950h
|
||||
|
After Width: | Height: | Size: 207 KiB |
|
After Width: | Height: | Size: 206 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 196 KiB |
|
After Width: | Height: | Size: 191 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 288 KiB |
|
After Width: | Height: | Size: 190 KiB |
|
After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 228 KiB |
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 193 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
@@ -0,0 +1,52 @@
|
||||
# Androidplot Documentation
|
||||
|
||||
When working with Androidplot, your best resource
|
||||
is the [DemoApp's example source code](../demoapp) as it's kept up to date for every release.
|
||||
|
||||
If you can't find an answer feel free to ask a question on Stack Overflow using the
|
||||
[Androidplot tag](http://stackoverflow.com/questions/tagged/androidplot).
|
||||
|
||||
# Tutorials
|
||||
These tutorials are roughly in the order that they should be read. Quickstart will get your app
|
||||
up and running with a basic xy plot. Plot Composition explains the common anatomy of all plots
|
||||
in the Androidplot library and lays the foundation for future topics. The tutorials discuss
|
||||
specific plot types explaining styling and other advanced topics.
|
||||
|
||||
* [Quickstart](quickstart.md) :star:
|
||||
* [Quickstart (YouTube Video)](https://www.youtube.com/watch?v=wEFkzQY_wWI) :movie_camera:
|
||||
* [Plot Composition](plot_composition.md)
|
||||
* [The Legend](legend.md)
|
||||
* [XY Plots](xyplot.md)
|
||||
* [Bar Charts](barchart.md)
|
||||
* [Candlestick Charts](candlestick.md)
|
||||
* [Pie Charts](piechart.md)
|
||||
* [Bubble Charts](bubblechart.md)
|
||||
* [Dynamic Plots](dynamicdata.md)
|
||||
* [Advanced XY Plot Topics](advanced_xy_plot.md)
|
||||
* [Custom Renderers](custom_renderer.md)
|
||||
|
||||
# Examples
|
||||
Source code examples of the various plot types.
|
||||
|
||||
* [An XYPlot](../demoapp/src/main/java/com/androidplot/demos/SimpleXYPlotActivity.java)
|
||||
* [A dynamic XYPlot](../demoapp/src/main/java/com/androidplot/demos/DynamicXYPlotActivity.java)
|
||||
* [Panning & Zooming](../demoapp/src/main/java/com/androidplot/demos/TouchZoomExampleActivity.java)
|
||||
* [Step Chart](../demoapp/src/main/java/com/androidplot/demos/StepChartExampleActivity.java)
|
||||
* [Candlestick Chart](../demoapp/src/main/java/com/androidplot/demos/CandlestickChartActivity.java)
|
||||
* [Scatter Plot](../demoapp/src/main/java/com/androidplot/demos/ScatterPlotActivity.java)
|
||||
* [Bar Chart](../demoapp/src/main/java/com/androidplot/demos/BarPlotExampleActivity.java)
|
||||
* [Pie Chart](../demoapp/src/main/java/com/androidplot/demos/SimplePieChartActivity.java)
|
||||
* [An ECG Example](../demoapp/src/main/java/com/androidplot/demos/ECGExample.java)
|
||||
* [f(x) Plot](../demoapp/src/main/java/com/androidplot/demos/FXPlotExampleActivity.java)
|
||||
|
||||
# XML Attributes
|
||||
A complete list of XML attributes is [available here](attrs.md).
|
||||
# Javadoc
|
||||
The latest Javadocs are [available here](https://javadoc.io/doc/com.androidplot/androidplot-core).
|
||||
|
||||
# Release Notes
|
||||
Full release notes are [available here](release_notes.md)
|
||||
|
||||
# Contributing
|
||||
_If you see something that isn't right or want to contribute, please [make a pull-request](https://help.github.com/articles/creating-a-pull-request/) - these docs
|
||||
live the main repo in the top-level `/docs` directory. For more info, see the [Contributing Source Code](docs/contributing.md) doc.
|
||||
@@ -0,0 +1,63 @@
|
||||
# <a name="legend"></a> The Legend
|
||||
For `Plot` types that support it, the legend displays a list of elements in the plot along with
|
||||
a color coded icon. The color coded icon is automatically generated using the colors and line styles
|
||||
used to render the associated item. In the case of a `Series`, this is the `Formatter` you associated
|
||||
with the `Series` when you added it to your `Plot`.
|
||||
|
||||
# Showing / Hiding the Legend
|
||||
Depending on the `Plot` type(s) you are using, the legend may or may not be visible by default. To
|
||||
can enable / disable the legend:
|
||||
|
||||
```java
|
||||
plot.getLegend().setVisible(true|false);
|
||||
```
|
||||
|
||||
# Hiding Series Items
|
||||
You can tell Androidplot not to generate a legend item for a `Series` by configuring it's associated
|
||||
`Formatter`:
|
||||
|
||||
```java
|
||||
formatter.setLegendIconEnabled(false);
|
||||
```
|
||||
|
||||
## The TableModel
|
||||
The `TableModel` controls how and where each item in the legend is drawn. Androidplot provides two
|
||||
default implementations; `DynamicTableModel` and `FixedTableModel` (detailed below). All `TableModel` implementations
|
||||
organize elements into a grid. This grid is populated with items based on the order which it's corresponding
|
||||
series was added to the plot. This ordering can be further controlled by setting the `TableModel`'s
|
||||
`TableOrder` param to either [ROW_MAJOR](https://en.wikipedia.org/wiki/Row-major_order) (items are added left-to-right, top-down)
|
||||
or `COLUMN_MAJOR` (items are added top-down, left-to-right).
|
||||
|
||||
### DynamicTableModel
|
||||
The `DynamicTableModel` takes a desired of numbered rows and columns and evenly subdivides the `LegendWidget`'s
|
||||
visible space into cells. For example, A 2x2 legend using `ROW_MAJOR` ordering:
|
||||
|
||||
```java
|
||||
plot.getLegend().setTableModel(new DynamicTableModel(2, 2, TableOrder.ROW_MAJOR));
|
||||
```
|
||||
|
||||
### FixedTableModel
|
||||
The `FixedTableModel` takes a desired size of each cell in pixels and adds cells using the specified `TableOrder`.
|
||||
It automatically wraps to the next row or column (based on `TableOrder`) when the cell being added
|
||||
exceeds the legend's available space on a given axis. For example, A `FixedTableModel` using 300w*100h cells and
|
||||
a TableOrder of `COLUMN_MAJOR`:
|
||||
|
||||
```java
|
||||
plot.getLegend().setTableModel(new FixedTableModel(PixelUtils.dpToPix(300),
|
||||
PixelUtils.dpToPix(100), TableOrder.COLUMN_MAJOR));
|
||||
```
|
||||
|
||||
# Sorting Legend Entries
|
||||
You can control the order of Legend entries by setting a custom `Comparator` on the legend:
|
||||
|
||||
```java
|
||||
Comparator<...> myComparator = ...
|
||||
plot.getLegend().setLegendItemComparator(myComparator);
|
||||
```
|
||||
|
||||
Using a custom `Comparator` in conjunction with `ROW_MAJOR` and `COLUMN_MAJOR` properties on the `TableModel`
|
||||
(show above) gives you full control over the display ordering of your legend entries.
|
||||
|
||||
# Positioning and Resizing
|
||||
The legend is just an implementation of a Widget and is positioned and resized in the same ways
|
||||
that all Widget instances are positioned. See the [Plot Composition](plot_composition.md) doc for details.
|
||||
@@ -0,0 +1,104 @@
|
||||
# Pie Charts
|
||||
Like all other primary chart and graph classes in Androidplot, `PieChart` is simply a composition
|
||||
of widgets along with convenience methods. The real work is actually done by `PieWidget`.
|
||||
|
||||

|
||||
|
||||
# Basic Usage
|
||||
Pie charts are composed of one or more values called Segments which combines a vaue and a label:
|
||||
|
||||
```java
|
||||
Segment segment = new Segment("my segment", 10);
|
||||
```
|
||||
|
||||
Displaying a `Segment` to a pie chart also requires a `SegmentFormatter`. `SegmentFormatter` is what defines
|
||||
the visual characteristics of the associated `Segment`; color, border thickness,
|
||||
segment offset, label text style (if any) etc. The below code instantiates a new `SegmentFormatter`
|
||||
with a segment color of red:
|
||||
|
||||
```java
|
||||
SegmentFormatter formatter = new SegmentFormatter(Color.RED);
|
||||
```
|
||||
|
||||
Finally, the `Segment` must be added to the pie chart along with it's `SegmentFormatter`:
|
||||
|
||||
```java
|
||||
pie.addSegment(segment, formatter);
|
||||
```
|
||||
|
||||
# Donut Size
|
||||
By default, `PieChart` draws it's self as a ring. The amount of empty space in the middle of
|
||||
the pie is called the `donutSize`. Setting a `donutSize` of 0 causes the `PieChart` to draw it's
|
||||
self as a full circle.
|
||||
|
||||

|
||||
|
||||
Setting `donutSize` programmatically:
|
||||
|
||||
```java
|
||||
// draw pie with an empty inner space radius equal to 50% of the pie's radius.
|
||||
pieRenderer.setDonutSize(0.5, PieRenderer.DonutMode.PERCENT);
|
||||
|
||||
// donut size may also be expressed in pixels:
|
||||
pieRenderer.setDonutSize(PixelUtils.dpToPix(30), PieRenderer.DonutMode.PIXELS);
|
||||
```
|
||||
|
||||
# Segment Orientation
|
||||
Each `Segment` is drawn in the order it was added to the `PieChart` clockwise from `startDegs`
|
||||
which by default is 0.
|
||||
|
||||

|
||||
|
||||
Using the image above, to move Segment0 to the Northeast quadrant
|
||||
of the pie (currently occupied by Segment3) `startDeg` should be set to 90:
|
||||
|
||||
```java
|
||||
pie.getRenderer(PieRenderer.class).setStartDegs(90);
|
||||
```
|
||||
# Extent
|
||||
The `extentDegs` value determines the number of degrees running clockwise from `startDegs` that
|
||||
represent 100% of the pie chart. The formal description is a little obtuse but is easy to understand
|
||||
through example. You could for instance use `extentDegs` in conjunction with `startDegs` to represent
|
||||
the full pie as a gauge:
|
||||
|
||||
```java
|
||||
// start the first segment at 5 degrees;
|
||||
pie.getRenderer(PieRenderer.class).setStartDegs(165);
|
||||
pie.getRenderer(PieRenderer.class).setExtentDegs(150);
|
||||
```
|
||||
Which produces a pie chart profile like this:
|
||||
|
||||

|
||||
|
||||
# SegmentFormatter
|
||||
As mentioned above, `SegmentFormatter` defines how a `Segment` is visually represented in a `PieChart`.
|
||||
In addition to basic color / border line styling params, there are several parameters available
|
||||
to visually distinguish a segment:
|
||||
|
||||
## Offset
|
||||
Value in pixels used to "shift" the position of the segment outward relative to the center of the `PieChart`.
|
||||
The visual effect is equivalent to cutting up a pie and dragging one piece out and away from the rest of the pie:
|
||||
|
||||

|
||||
|
||||
## RadialInset
|
||||
Value in degrees used to shrink the radial edges of the segment inward. The visual effect is equivalent
|
||||
to shaving the edges off of a slice of pie, resulting in a narrower slice of pie:
|
||||
|
||||

|
||||
|
||||
## InnerInset
|
||||
Value in pixels used to shrink the inner section of the pie. The visual effect is equivalent to
|
||||
cutting the tip off of a slice of pie:
|
||||
|
||||

|
||||
|
||||
## OuterInset
|
||||
Value in pixels used to shrink the outer edge of the pie. The visual effect is equivalent to evenly
|
||||
shaving the crust off of a slice of pie:
|
||||
|
||||

|
||||
|
||||
See the DemoApp's
|
||||
[pie chart example source](../demoapp/src/main/java/com/androidplot/demos/SimplePieChartActivity.java) for a comprehensive usage example.
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
# Plot Composition
|
||||
All plots in Androidplot inherit from the abstract base class `Plot` which provides common behaviors
|
||||
for all `Plot` implementations.
|
||||
|
||||
# Widgets
|
||||
Plots are composed of one or more Widgets. A `Widget` is an abstraction of a visual
|
||||
component that may be positioned and scaled within the visible area of a Plot. For example,
|
||||
an `XYPlot` is typically composed of these 5 `Widgets`:
|
||||
|
||||
* Title
|
||||
* Graph
|
||||
* Domain Label
|
||||
* Range Label
|
||||
* [Legend](legend.md)
|
||||
|
||||
All implementations of `Plot` will contain at least one default `Widget` providing the core
|
||||
behavior encapsulated by that `Plot`. In addition to moving and scaling a `Widget`, developers may
|
||||
also extend them and replace the `Plot` instance's default instance with the derived implementation in order to
|
||||
get custom behavior.
|
||||
|
||||
# The LayoutManager
|
||||
The `LayoutManager` provides the logic for visually positioning and scaling Widgets; all `Plot` implementations
|
||||
contain an instance of `LayoutManager` that can be retrieved via `Plot.getLayoutManager()`.
|
||||
|
||||
## Z-Indexing
|
||||
Z-indexing is a 2D drawing concept which associates each drawable entity with a value that determines
|
||||
which elements get drawn onto the screen first, producing the visual effect that certain elements appear
|
||||
on top of others.
|
||||
|
||||
While Androidplot uses the term "z-index" it's implemented internally as a linked list to prevent the possibility
|
||||
of duplicate index values and therefore ensuring that `Widget` drawing order is always explicit.
|
||||
The [Layerable](../androidplot-core/src/main/java/com/androidplot/util/Layerable.java) interface
|
||||
defines methods used for manipulating the z-index of a `Widget`.
|
||||
|
||||
## Adding & Removing Widgets
|
||||
New `Widget` instances can be added either to the front or back of the z-index using these methods:
|
||||
|
||||
* `LayoutManager.addToTop(Widget)`
|
||||
* `LayoutManager.addToBottom(Widget)`
|
||||
|
||||
## Positioning Widgets
|
||||
Once a Widget has been added to the LayoutManager, it's position within the Plot can be adjusted via
|
||||
`Widget.position(...)`. This method takes a layout style and value for the x and y dimension and an
|
||||
optional anchor position from which the layout modes will be applied.
|
||||
|
||||
### HorizontalPosition & VerticalPosition
|
||||
These define the part of the Plot from which Widget will be positioned using relative or absolute units.
|
||||
|
||||
* XPosition - Supports positioning in relation to the Plot's left edge, right edge or horizontal center.
|
||||
* YPosition - Supports positioning in relation to the Plot's top edge, bottom edge or vertical center.
|
||||
|
||||
|
||||
#### Absolute Positioning
|
||||
Absolute positioning means that positions are expressed as an absolute pixel offset from the specified
|
||||
edge or center point.
|
||||
|
||||
#### Relative Positioning
|
||||
Relative positions are expressed as a ratio of the total size of the Plot along the given axis. This
|
||||
ration must fall within the range of -1 to 1.
|
||||
|
||||
**Example #1: A relative XPosition of 1 and YPosition of 0.5 in a 100Hx200W pixel Plot**
|
||||
|
||||
x = 1 * 200 = 200
|
||||
|
||||
y = 0.5 * 100 = 50
|
||||
|
||||
**Example #2: An absolute XPosition of 50 and an absolute YPosition of 25 in a 100Hx200W pixel Plot**
|
||||
|
||||
x = 50
|
||||
|
||||
y = 25
|
||||
|
||||
#### Anchors
|
||||
The Anchor param specifies the point on the Widget from which the XPosition and YPosition calculations will be applied.
|
||||
Using example #1 above, an Anchor value of `Anchor.LEFT_TOP` means that the top left corner of the Widget
|
||||
would be positioned at the screen coordinate [200, 50].
|
||||
|
||||
#### Examples
|
||||
The examples below illustrate positioning an `XYGraphWidget` of an `XYPlot`.
|
||||
|
||||
xml:
|
||||
```xml
|
||||
ap:graphAnchor="right_bottom"
|
||||
ap:graphHorizontalPositioning="absolute_from_right"
|
||||
ap:graphHorizontalPosition="0dp"
|
||||
ap:graphVerticalPositioning="relative_from_bottom"
|
||||
ap:graphVerticalPosition="0dp"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().position(
|
||||
0, HorizontalPositioning.ABSOLUTE_FROM_RIGHT,
|
||||
0, VerticalPositioning.RELATIVE_TO_BOTTOM);
|
||||
```
|
||||

|
||||
***
|
||||
|
||||
xml:
|
||||
```xml
|
||||
ap:graphAnchor="right_bottom"
|
||||
ap:graphHorizontalPositioning="absolute_from_right"
|
||||
ap:graphHorizontalPosition="10dp"
|
||||
ap:graphVerticalPositioning="relative_from_bottom"
|
||||
ap:graphVerticalPosition="10dp"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().position(
|
||||
PixelUtils.dpToPix(10), HorizontalPositioning.ABSOLUTE_FROM_RIGHT,
|
||||
PixelUtils.dpToPix(10), VerticalPositioning.RELATIVE_TO_BOTTOM);
|
||||
```
|
||||

|
||||
***
|
||||
|
||||
xml:
|
||||
```xml
|
||||
ap:graphAnchor="right_bottom"
|
||||
ap:graphHorizontalPositioning="absolute_from_left"
|
||||
ap:graphHorizontalPosition="0dp"
|
||||
ap:graphVerticalPositioning="relative_from_top"
|
||||
ap:graphVerticalPosition="0dp"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().position(
|
||||
0, HorizontalPositioning.ABSOLUTE_FROM_LEFT,
|
||||
0, VerticalPositioning.RELATIVE_TO_TOP);
|
||||
```
|
||||

|
||||
***
|
||||
|
||||
xml:
|
||||
```xml
|
||||
ap:graphAnchor="center"
|
||||
ap:graphHorizontalPositioning="absolute_from_center"
|
||||
ap:graphHorizontalPosition="0dp"
|
||||
ap:graphVerticalPositioning="absolute_from_center"
|
||||
ap:graphVerticalPosition="0dp"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().position(
|
||||
0, HorizontalPositioning.ABSOLUTE_FROM_CENTER,
|
||||
0, VerticalPositioning.ABSOLUTE_FROM_CENTER);
|
||||
```
|
||||

|
||||
|
||||
|
||||
## Sizing Widgets
|
||||
The size and shape of a `Widget` is controlled by it's `setSize(Size)` method.
|
||||
|
||||
### Size
|
||||
The `Size` parameter of `Widget.setSize(Size)` defines the height and width of the associated Widget.
|
||||
It is composed of two `SizeMetric` instances; one for height and one for width.
|
||||
`Size` provides two constructors: `Size(SizeMetric, SizeMetric)` or
|
||||
`Size(int, SizeMode, int, SizeMode)`. Constructor params represent height and width respectively.
|
||||
|
||||
### SizeMetric
|
||||
A `SizeMetric` is composed of a `SizeMode` and a float value. There are three kinds of `SizeMode`:
|
||||
|
||||
* ABSOLUTE - float value defines the size metric as an absolute value in pixels.
|
||||
* RELATIVE - float value defines the size of the metric relative to the size of the containing Plot along
|
||||
the associated axis, in the range of 0.0 to 1.0.
|
||||
* FILL - float value defines an absolute value in pixels to subtract from the size of the containing
|
||||
Plot along the associated axis and the SizeMetric "fills" the difference.
|
||||
|
||||
#### Examples
|
||||
The examples below illustrate positioning an `XYGraphWidget` of an `XYPlot` and
|
||||
assume centered positioning is applied as described in the [Positioning Widgets](#positioning-widgets) section above.
|
||||
|
||||
xml:
|
||||
```xml
|
||||
ap:graphHeightMode="absolute"
|
||||
ap:graphHeight="100dp"
|
||||
ap:graphWidthMode="absolute"
|
||||
ap:graphWidth="100dp"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().setSize(new Size(
|
||||
PixelUtils.dpToPix(100), SizeMode.ABSOLUTE,
|
||||
PixelUtils.dpToPix(100), SizeMode.ABSOLUTE));
|
||||
```
|
||||

|
||||
***
|
||||
xml:
|
||||
```xml
|
||||
ap:graphHeightMode="absolute"
|
||||
ap:graphHeight="150dp"
|
||||
ap:graphWidthMode="absolute"
|
||||
ap:graphWidth="100dp"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().setSize(new Size(
|
||||
PixelUtils.dpToPix(150), SizeMode.ABSOLUTE,
|
||||
PixelUtils.dpToPix(100), SizeMode.ABSOLUTE));
|
||||
```
|
||||

|
||||
***
|
||||
xml:
|
||||
```xml
|
||||
ap:graphHeightMode="relative"
|
||||
ap:graphHeight="1.0"
|
||||
ap:graphWidthMode="absolute"
|
||||
ap:graphWidth="100dp"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().setSize(new Size(
|
||||
1.0f, SizeMode.RELATIVE,
|
||||
PixelUtils.dpToPix(100), SizeMode.ABSOLUTE));
|
||||
```
|
||||

|
||||
***
|
||||
xml:
|
||||
```xml
|
||||
ap:graphHeightMode="absolute"
|
||||
ap:graphHeight="100dp"
|
||||
ap:graphWidthMode="relative"
|
||||
ap:graphWidth="0.75"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().setSize(new Size(
|
||||
PixelUtils.dpToPix(100), SizeMode.ABSOLUTE,
|
||||
0.75f, SizeMode.RELATIVE));
|
||||
```
|
||||

|
||||
***
|
||||
xml:
|
||||
```xml
|
||||
ap:graphHeightMode="fill"
|
||||
ap:graphHeight="50dp"
|
||||
ap:graphWidthMode="fill"
|
||||
ap:graphWidth="50dp"
|
||||
```
|
||||
java:
|
||||
```java
|
||||
plot.getGraph().setSize(new Size(
|
||||
PixelUtils.dpToPix(50), SizeMode.FILL,
|
||||
PixelUtils.dpToPix(50), SizeMode.FILL));
|
||||
```
|
||||

|
||||
|
||||
## Margins and Padding
|
||||
Every widget has a margin, padding and an optional border that can be drawn around it. These params behave
|
||||
very similarly to those defined in the [CSS Box Model](http://www.w3schools.com/css/css_boxmodel.asp).
|
||||
|
||||
## Markup Mode
|
||||
If you're having trouble visualizing the effects of tweaking margins and padding, you can enable
|
||||
markup mode which will highlight these spaces on each widget, as well as draw a green line around it's
|
||||
absolute border.
|
||||
|
||||
To turn markup mode on for a plot programmatically:
|
||||
|
||||
```java
|
||||
plot.setMarkupEnabled(true);
|
||||
```
|
||||
|
||||
Or via XML:
|
||||
|
||||
```xml
|
||||
ap:markupEnabled="true"
|
||||
```
|
||||
|
||||
This is what it looks like:
|
||||
|
||||

|
||||
|
||||
# Formatters, Renderers and Series Data
|
||||
Each Plot specifies the type of Series it supports; XYPlots support XYSeries, PieCharts support Segment, etc.
|
||||
In all cases, the Series encapsulates the numeric model of the data being represented by the Plot.
|
||||
|
||||
## Formatters
|
||||
The Plot keeps a mapping between Series
|
||||
data and the Formatter instance provided by the user that is to be used to render that data. It is the
|
||||
Formatter that tells Androiplot which Renderer to use to draw the Series along with which colors, line thicknesses,
|
||||
text style, etc. to apply while drawing.
|
||||
|
||||
## Renderers
|
||||
The Renderer is what renders Series data onto a Plot. Users can provide their own custom rendering behavior
|
||||
by writing their own Renderer implementation along with a custom Formatter telling Androidplot about the
|
||||
Renderer via the `Formatter.getRendererClass()` method. See [Custom Renderer](custom_rnderer.md) documentation.
|
||||
|
||||
# XML Styling
|
||||
Androidplot supports an increasing number of XML attributes. The two best resources for learning about
|
||||
these attributes is the [demo app source code](../demoapp) and [attrs.xml](../androidplot-core/src/main/res/values/attrs.xml) file which
|
||||
contains the exhaustive list of available attributes.
|
||||
@@ -0,0 +1,205 @@
|
||||
# Quickstart
|
||||
|
||||

|
||||
|
||||
This tutorial will walk you through Adding Androidplot as a dependency and displaying an XYPlot with
|
||||
two data series. You can view this sample on your own device or emulator by installing the
|
||||
[Demo App](https://play.google.com/store/apps/details?id=com.androidplot.demos) on your device and
|
||||
clicking on the Simple XY Plot Example. Full source [available here](../demoapp/src/main/java/com/androidplot/demos/SimpleXYPlotActivity.java).
|
||||
|
||||
You can also watch this tutorial in video form on [Youtube](https://youtu.be/wEFkzQY_wWI).
|
||||
|
||||
# Add the Dependency
|
||||
To use the library in your gradle project add the following to your build.gradle:
|
||||
|
||||
```groovy
|
||||
dependencies {
|
||||
implementation "com.androidplot:androidplot-core:1.5.10"
|
||||
}
|
||||
```
|
||||
|
||||
*NOTE: As of version 1.5.8 Androidplot has migrated over from the Android Support Libraries to androidx.
|
||||
If you have a very old project and experience issues, may need to stay on version 1.5.7*
|
||||
|
||||
If you’re using Proguard obfuscation (Projects created by Android Studio do by default) you’ll also
|
||||
want add this to your proguard-rules.pro file:
|
||||
|
||||
`-keep class com.androidplot.** { *; }`
|
||||
|
||||
# Create your Activity XML Layout
|
||||
Once you’ve got an Android project skeleton created, create **res/layout/simple_xy_plot_example.xml**
|
||||
and add an XYPlot view:
|
||||
```xml
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:ap="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<com.androidplot.xy.XYPlot
|
||||
style="@style/APDefacto.Dark"
|
||||
android:id="@+id/plot"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
ap:title="A Simple XY Plot"
|
||||
ap:rangeTitle="range"
|
||||
ap:domainTitle="domain"
|
||||
ap:lineLabels="left|bottom"
|
||||
ap:lineLabelRotationBottom="-45"/>
|
||||
</LinearLayout>
|
||||
```
|
||||
This example uses a default style to decorate the plot. The full list of XML styleable attributes is
|
||||
[available here](attrs.md). While new attributes are added regularly,
|
||||
not all configurable properties are yet available.
|
||||
|
||||
If something you need is missing, use [Fig Syntax](https://github.com/halfhp/fig)
|
||||
directly within your Plot's XML, prefixing each property with "androidPlot". Example:
|
||||
|
||||
```xml
|
||||
androidPlot.title="My Plot"
|
||||
```
|
||||
|
||||
Add these files to your **/res/xml** directory:
|
||||
|
||||
#### /res/xml/line_point_formatter_with_labels.xml
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<config
|
||||
linePaint.strokeWidth="5dp"
|
||||
linePaint.color="#00AA00"
|
||||
vertexPaint.color="#007700"
|
||||
vertexPaint.strokeWidth="20dp"
|
||||
fillPaint.color="#00000000"
|
||||
pointLabelFormatter.textPaint.color="#CCCCCC"/>
|
||||
```
|
||||
|
||||
#### /res/xml/line_point_formatter_with_labels_2.xml
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<config
|
||||
linePaint.strokeWidth="5dp"
|
||||
linePaint.color="#0000AA"
|
||||
vertexPaint.strokeWidth="20dp"
|
||||
vertexPaint.color="#000099"
|
||||
fillPaint.color="#00000000"
|
||||
pointLabelFormatter.textPaint.color="#CCCCCC"/>
|
||||
```
|
||||
|
||||
# Create an Activity
|
||||
Now let's create an Activity to display the XYPlot we just defined in `simple_xy_plot_example.xml`.
|
||||
The basic steps are:
|
||||
|
||||
1. Create an instance of Series and populate it with data to be displayed.
|
||||
2. Register one or more series with the plot instance along with a Formatter to describing how the series should look when drawn.
|
||||
3. Draw the Plot
|
||||
|
||||
Since we're working with XY data, we’ll use XYPlot, SimpleXYSeries (which is an
|
||||
implementation of the XYSeries interface) and LineAndPointFormatter:
|
||||
|
||||
```java
|
||||
import android.app.Activity;
|
||||
import android.graphics.*;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.androidplot.util.PixelUtils;
|
||||
import com.androidplot.xy.SimpleXYSeries;
|
||||
import com.androidplot.xy.XYSeries;
|
||||
import com.androidplot.xy.*;
|
||||
|
||||
import java.text.FieldPosition;
|
||||
import java.text.Format;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A simple XYPlot
|
||||
*/
|
||||
public class SimpleXYPlotActivity extends Activity {
|
||||
|
||||
private XYPlot plot;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.simple_xy_plot_example);
|
||||
|
||||
// initialize our XYPlot reference:
|
||||
plot = (XYPlot) findViewById(R.id.plot);
|
||||
|
||||
// create a couple arrays of y-values to plot:
|
||||
final Number[] domainLabels = {1, 2, 3, 6, 7, 8, 9, 10, 13, 14};
|
||||
Number[] series1Numbers = {1, 4, 2, 8, 4, 16, 8, 32, 16, 64};
|
||||
Number[] series2Numbers = {5, 2, 10, 5, 20, 10, 40, 20, 80, 40};
|
||||
|
||||
// turn the above arrays into XYSeries':
|
||||
// (Y_VALS_ONLY means use the element index as the x value)
|
||||
XYSeries series1 = new SimpleXYSeries(
|
||||
Arrays.asList(series1Numbers), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Series1");
|
||||
XYSeries series2 = new SimpleXYSeries(
|
||||
Arrays.asList(series2Numbers), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Series2");
|
||||
|
||||
// create formatters to use for drawing a series using LineAndPointRenderer
|
||||
// and configure them from xml:
|
||||
LineAndPointFormatter series1Format =
|
||||
new LineAndPointFormatter(this, R.xml.line_point_formatter_with_labels);
|
||||
|
||||
LineAndPointFormatter series2Format =
|
||||
new LineAndPointFormatter(this, R.xml.line_point_formatter_with_labels_2);
|
||||
|
||||
// add an "dash" effect to the series2 line:
|
||||
series2Format.getLinePaint().setPathEffect(new DashPathEffect(new float[] {
|
||||
|
||||
// always use DP when specifying pixel sizes, to keep things consistent across devices:
|
||||
PixelUtils.dpToPix(20),
|
||||
PixelUtils.dpToPix(15)}, 0));
|
||||
|
||||
// just for fun, add some smoothing to the lines:
|
||||
// see: http://androidplot.com/smooth-curves-and-androidplot/
|
||||
series1Format.setInterpolationParams(
|
||||
new CatmullRomInterpolator.Params(10, CatmullRomInterpolator.Type.Centripetal));
|
||||
|
||||
series2Format.setInterpolationParams(
|
||||
new CatmullRomInterpolator.Params(10, CatmullRomInterpolator.Type.Centripetal));
|
||||
|
||||
// add a new series' to the xyplot:
|
||||
plot.addSeries(series1, series1Format);
|
||||
plot.addSeries(series2, series2Format);
|
||||
|
||||
plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.BOTTOM).setFormat(new Format() {
|
||||
@Override
|
||||
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
|
||||
int i = Math.round(((Number) obj).floatValue());
|
||||
return toAppendTo.append(domainLabels[i]);
|
||||
}
|
||||
@Override
|
||||
public Object parseObject(String source, ParsePosition pos) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
One potentially confusing section of the code above are the initializations of LineAndPointFormatter
|
||||
You probably noticed that they take a mysterious reference to an xml resource file. This is actually
|
||||
using [Fig](https://github.com/halfhp/fig) to configure the instance properties from XML.
|
||||
|
||||
If you'd prefer to avoid the XML and keep everything in Java, just replace the code:
|
||||
|
||||
```java
|
||||
LineAndPointFormatter series1Format =
|
||||
new LineAndPointFormatter(this, R.xml.line_point_formatter_with_labels);
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```java
|
||||
LineAndPointFormatter series1Format = new LineAndPointFormatter(Color.RED, Color.GREEN, Color.BLUE, null);
|
||||
```
|
||||
|
||||
In general XML configuration should be used over programmatic configuration when possible as it produces
|
||||
more flexibility in terms of defining properties by screen density etc.. For more details on how to
|
||||
programmatically configure Formatters etc. consult the latest Javadocs.
|
||||
|
||||
# Whats Next?
|
||||
Learn about [Plot Composition](plot_composition.md) or continue with [XYPlots](xyplot.md).
|
||||
@@ -0,0 +1,173 @@
|
||||
# Androidplot Versioning
|
||||
For details on what to expect in general when updating to a new version of Androiplot, check out the
|
||||
[versioning doc](versioning.md).
|
||||
|
||||
# 1.5.10
|
||||
* Update project to use latest gradle / build tools
|
||||
* (#114) fix `setLinesPerRangeLabel` & `setLinesPerDomainLabel`
|
||||
|
||||
# 1.5.9
|
||||
* (#107) Fix ambiguous ordinal for render mode attributes
|
||||
* (#104) Fix issue with background rendering in RecyclerView.
|
||||
* Adds a RecyclerView example to demo app.
|
||||
|
||||
# 1.5.8
|
||||
* Maintenance release - update dependences, get off jcenter, etc.
|
||||
|
||||
# 1.5.7
|
||||
* (#94) Potential fix / better error logging for a crash caused by a buffered canvas resize with illegal arguments.
|
||||
* (#93) Fix Android 9 compiler warnings.
|
||||
* (#83) Fix NPE when attempting to recycle an already null buffered canvas instance.
|
||||
* Remove unused `PlotRenderException`.
|
||||
* Added `IN_ORDER` BarRenderer mode.
|
||||
|
||||
# 1.5.6
|
||||
* Adds convenience methods for saving / restoring `PanZoom` state.
|
||||
* (#80) Targets SDK 28, fixing compatibility issues.
|
||||
|
||||
# 1.5.5
|
||||
|
||||
* (#76) Fixed a bug that could cause a deadlock when grid steps are much larger than actual plot range.
|
||||
* (#78) Fixed a bug where setting insets on XYGraphWidget would have no effect after the plot was drawn.
|
||||
* XYGraphWidget.drawMarkerText is now marked `protected`.
|
||||
|
||||
# 1.5.4
|
||||
|
||||
* (#69) Fixed a bug in `SimpleXYPlot` preventing the resizing of `Y_VALS_ONLY` formatted series.
|
||||
* (#73) Fixed a bug where dynamically resizing a Plot (by marking a sibling view as `GONE`, etc.) would not resize the graph widget.
|
||||
|
||||
# 1.5.3
|
||||
|
||||
* Minor cleanup of Widget example source.
|
||||
* (#67) Fixed Javadoc link
|
||||
|
||||
# 1.5.2
|
||||
|
||||
_This version is pickier than it's predecessors about proper XML configuration. Where
|
||||
previous versions would silently ignore illegal XML attrs, a `RuntimeException` will be thrown._
|
||||
* Added [sizing documentation](plot_composition.md#sizing-widgets)
|
||||
* Added [custom renderer documentation](custom_renderer.md)
|
||||
* Fixed (#61) Bug in `XYGraphWidget.screenToSeriesY(...)`.
|
||||
* Fixed (#63) Fixed compatibility issue with Gradle 3.x.x that caused issues with XML parsing.
|
||||
|
||||
# 1.5.1
|
||||
|
||||
* (#52) Fixed minor NPE issue
|
||||
* (#55) Fixed bug with `PieRenderer.getContainingSegment` not working for very large segments.
|
||||
|
||||
# 1.5.0
|
||||
|
||||
_Updates to legend functionality in this version may result in changes to the display order
|
||||
of legend items in some cases. A custom `Comparator` can be used to resolve this if necessary;
|
||||
see the [legend doc](legend.md) for implementation details._
|
||||
|
||||
* Added [legend doc](legend.md)
|
||||
* Added legend support to `PieChart`
|
||||
* Added configurable legend item sorting
|
||||
* (#45) Auto range boundaries calculation fix for when using a fixed domain range and a `FastXYSeries`
|
||||
* Minor Performance Optimizations
|
||||
|
||||
# 1.4.3
|
||||
|
||||
* (#39) `FastLineAndPointRenderer` now renders vertices for legend items.
|
||||
* Added [XML Attrs reference doc](attrs.md).
|
||||
|
||||
# 1.4.2
|
||||
|
||||
* (#32) New step mode: `INCREMENT_BY_FIT`.
|
||||
* (#33) `PanZoom` support for `INCREMENT_BY_FIT`.
|
||||
* (#34) Removed examples and documentation for serializing `SeriesRegistry` to preserve state.
|
||||
|
||||
# 1.4.1
|
||||
|
||||
* (#26) Fixed an NPE issue when drawing null values with a `PointLabeler`.
|
||||
* Fixed a broken link in Quickstart doc.
|
||||
|
||||
# 1.4.0
|
||||
|
||||
* Moderate refactor of `PieRenderer`. [Documentation](piechart.md) has been updated to reflect these changes.
|
||||
* Major refactor of `BarRenderer`. [Documentation](barchart.md) has been updated to reflect these changes.
|
||||
* Added `ScalingXYSeries` which wraps other instances of `XYSeries` to be dynamically scaled. This is
|
||||
particularly useful for creating animated intros using `XYSeries` data.
|
||||
* Added [AnimatedXYPlotActivity](../demoapp/src/main/java/com/androidplot/demos/AnimatedXYPlotActivity.java)
|
||||
demonstrating the use of `ScalingXYSeries` to create an animated intro.
|
||||
* `XYPlot.getXVal(..)` and `XYPlot.getYVal(...)` methods have been deprecated and will be removed in 1.5.0.
|
||||
`XYPlot.screenToSeries(...)` and `XYPlot.seriesToScreen(...)` should be used instead.
|
||||
* Domain and range cursors are now disabled by default. To enable, set a valid cursor position using
|
||||
`XYGraphWidget.setCursorPosition(float, float)`. Cursor position values are expressed in screen coordinates;
|
||||
you can convert between screen and series values using `XYPlot.screenToSeries(...)` and `XYPlot.seriesToScreen(...)`.
|
||||
|
||||
# 1.3.1
|
||||
|
||||
* Added [NormedXYSeries](advanced_xy_plot.md#normedxyseries) wrapper to simplify the process of normalizing xy series data.
|
||||
* Added [DualScaleActivity](../demoapp/src/main/java/com/androidplot/demos/DualScaleActivity.java)
|
||||
demonstrating `NormedXYSeries` usage to present dual range scales.
|
||||
* LineAndPointRenderer options for cases where two or mode series' of different size have been added.
|
||||
* Fixed a bug causing points scrolled off-screen to occasionally accumulate and render along the left edge of the graph.
|
||||
* Fixed a bug that could cause render jitter when extreme zoom levels were applied.
|
||||
* Fixed a bug that prevented `PanZoom` from working properly on plots with an undefined outer limit.
|
||||
|
||||
# 1.3.0
|
||||
|
||||
* Added sampling support. See the [Advanced XY Plot](advanced_xy_plot.md) doc for details.
|
||||
* PanZoom performance enhancements & bug fixes. If you're currently using PanZoom you'll likely need to
|
||||
update your code as the interface has slightly changed.
|
||||
* Added leakcanary to DemoApp for debug builds.
|
||||
* More unit test coverage
|
||||
* Fixed a bug that prevented an instance of a given series from being added more than once, even
|
||||
when a unique formatter is supplied.
|
||||
* Added `Formatter.getLegendIconEnabled()` and `Formatter.setLegendIconEnabled(boolean)`, used to enable / disable drawing legend items for individual
|
||||
series / formatter pairs.
|
||||
* Added `XYGraphWidget.Edge.NONE` to be used with `XYGraphWidget.setLineLabelEdges(Edge...)` to disable all edges.
|
||||
|
||||
# 1.2.2
|
||||
|
||||
* BarRenderer / BarFormatter cleanup
|
||||
* More documentation!
|
||||
* Bounds and XYBounds have been merged into Region and RectRegion respectively.
|
||||
* ValPixConverter has been removed and it's functionality migrated to Region and RectRegion.
|
||||
* Added Region.transform(...) and RectRegion.transform(...)
|
||||
* Added Region.ratio(...) and RectRegion.ratio(...)
|
||||
* XYPlot.getCalculatedMinX(), XYPlot.getCalculatedMaxX(), XYPlot.getCalculatedMinY() and XYPlot.getCalculatedMinY()
|
||||
have been replaced with XYPlot.getBounds().
|
||||
* Configurator has become it's own library - [Fig!](https://github.com/halfhp/fig)
|
||||
* New constructors have been added to Formatters to simplify XML configuration via Fig.
|
||||
* Added Jacoco code coverage reporting
|
||||
|
||||
# 1.2.1
|
||||
|
||||
### Pie Chart Enhancements
|
||||
Pie chart has been updated with new methods and format attributes to improve segment
|
||||
selection and highlighting functionality:
|
||||
|
||||
* Added `offset`, `radialInset`, `innerInset` and `outerInset` properties to SegmentFormatter.
|
||||
See the [pie chart documentation](piechart.md) for usage details.
|
||||
* Updated PieRenderer to support the new SegmentFormatter properties.
|
||||
* SimplePieChartActivity has been updated to provide an interactive demo of some of these new features.
|
||||
|
||||
### Misc
|
||||
|
||||
* Added `Plot.getListeners()` method.
|
||||
* Added FastLineAndPointRenderer, updated OrientationSensorExampleActivity to use it.
|
||||
* Updated to target SDK 24, removed sdkmanager dependency, and other misc. updates to project deps etc.
|
||||
* Lots of additions and updates to documentation
|
||||
* Added CircleCI support
|
||||
|
||||
# 1.1.0
|
||||
|
||||
* Added drawGridOnTop param to XYGraphWidget; when set to true, grid lines will be drawn on top of rendered series data. (default is false)
|
||||
* Added PanZoom class providing one-line configuration of pan/zoom behavior for instances of XYPlot. See TouchZoomExampleActivity for a usage example.
|
||||
* Removed InteractiveXYPlot as PanZoom makes it obsolete.
|
||||
|
||||
# 1.0.0
|
||||
|
||||
This is a factor of several core elements of the Androidplot lib. The general theme was to
|
||||
make class and method names more intuitive and to make xml styling more powerful.
|
||||
|
||||
* Major refactor of XYGraphWidget
|
||||
* Tick renamed to Line
|
||||
* Extensible Label Formatters
|
||||
* getXXXWidget methods renamed to simply getXXX
|
||||
* Per-edge tick extensions
|
||||
* Moved documentation into vcs. Docs from 1.0 forward will be maintained here. (TODO)
|
||||
* plot label xml param renamed to title
|
||||
@@ -0,0 +1,15 @@
|
||||
# Versioning
|
||||
Androidplot's versioning scheme is Major.Minor.Rev. For example, in the version 1.3.2 the Major is 1
|
||||
the Minor is 3 and the Rev is 2.
|
||||
|
||||
Revisional releases (releases where only the Rev value has increased from the previous release, ie 1.3.1 -> 1.3.2)
|
||||
may include new features and bug fixes but will be fully backwards compatible with releases of the same minor version.
|
||||
**Updating to the latest revisional release should require no code changes in your app.**
|
||||
|
||||
Minor Releases (releases where the Minor value has increased but the Major value has not) may contain
|
||||
new features, bug fixes, removed methods deprecated in the previous minor release
|
||||
and other moderate refactoring. **Updating to a new minor release may require code changes in your app.**
|
||||
|
||||
Major releases (releases where the Major value has increased) are typically complete rewrites of core
|
||||
elements of the library. Unless otherwise specified in the release notes, **updating to a new major release
|
||||
will require significant code changes to your app.**
|
||||
@@ -0,0 +1,391 @@
|
||||
# XYPlot
|
||||
An `XYPlot` renders one or more XYSeries onto an instance of XYGraphWidget. It also includes two instances
|
||||
of `TextLabelWidget` used to display an optional title for the domain and range axis, and an instance
|
||||
of [XYLegendWidget](#legend) which by default will automatically display legend items for each `XYSeries` added to the plot.
|
||||
|
||||

|
||||
|
||||
# XYSeries
|
||||
`XYSeries` is the interface Androidplot uses to retrieve your numeric data. You may either create your own
|
||||
implementation of `XYSeries` or use `SimpleXYSeries` if you don't have tight performance requirements or
|
||||
if your numeric data is easily accessed as an array or list of values.
|
||||
|
||||
## SimpleXYSeries
|
||||
As a convenience, Androidplot provides an all-purpose implementation of the `XYSeries` interface called
|
||||
`SimpleXYSeries`. `SimpleXYSeries` is used to wrap your raw data with an implementation of the `XYSeries` interface.
|
||||
|
||||
You can supply your data in several ways:
|
||||
|
||||
As a list of y-vals (x = i for each supplied y-val):
|
||||
```java
|
||||
Number[] yVals = {1, 4, 2, 8, 4, 16, 8, 32, 16, 64};
|
||||
XYSeries series1 = new SimpleXYSeries(
|
||||
Arrays.asList(yVals), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "my series");
|
||||
```
|
||||
|
||||
An interleaved list of x/y value pairs (x[0] = 1, y[0] = 4, x[1] = 2, y[1] = 8, ...):
|
||||
```java
|
||||
Number[] yVals = {1, 4, 2, 8, 4, 16, 8, 32, 16, 64};
|
||||
XYSeries series1 = new SimpleXYSeries(
|
||||
Arrays.asList(yVals), SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED, "my series");
|
||||
```
|
||||
|
||||
Separate lists of x-vals and y-vals:
|
||||
```java
|
||||
Number[] xVals = {1, 4, 2, 8, 4, 16, 8, 32, 16, 64};
|
||||
Number[] yVals = {5, 2, 10, 5, 20, 10, 40, 20, 80, 40};
|
||||
XYSeries series = new SimpleXYSeries(xVals, yVals, "my series");
|
||||
```
|
||||
|
||||
Keep in mind that `SimpleXYSeries` is designed to be easy to use for a broad number of applications; it's not
|
||||
optimized for any specific scenario; if you are dynamically displaying data that needs to be refreshed more than several
|
||||
times a second, consider building your own implementation of `XYSeries` designed for your app's
|
||||
specific needs.
|
||||
|
||||
# The Graph
|
||||
`XYGraphWidget` encapsulates XYPlot's graphing functionality. Given an instance of `XYPlot`, a reference
|
||||
to `XYGraphWidget` can be retrieve via `XYPlot.getGraph()`.
|
||||
|
||||
## Domain & Range Boundaries
|
||||
By default, Androidplot will analyze all `XYSeries` instances registered with the `XYPlot`, determine the
|
||||
min/max values for domain and range and adjust the `XYPlot` boundaries to match those values. If your
|
||||
plot contains dynamic data, especially if your plot can periodically contain either no series data
|
||||
or data with no resolution on one or both axis (all identical values for either x or y) then you may
|
||||
want to manually set your `XYPlot`'s domain and range boundaries.
|
||||
|
||||
To set your plot's boundaries use:
|
||||
|
||||
* `XYPlot.setDomainBoundaries(Number value, BoundaryMode mode)`
|
||||
* `XYPlot.setRangeBoundaries(Number value, BoundaryMode mode)`
|
||||
|
||||
Note that the value argument is only used when setting `BoundaryMode.FIXED`. For all other
|
||||
modes, pass in null.
|
||||
|
||||
### BoundaryMode
|
||||
Androidplot provides four boundary modes:
|
||||
|
||||
#### FIXED
|
||||
The plot's boundaries on the specified axis are fixed to user defined values.
|
||||
|
||||
#### AUTO (default)
|
||||
The plot's boundaries auto adjust to the min/max values for the defined axis.
|
||||
|
||||
#### GROW
|
||||
The plot's boundaries automatically increase to the max value encountered by the plot. The initial
|
||||
determines the starting boundaries from which the `BoundaryMode.GROW` behavior will be based.
|
||||
|
||||
#### SHRINK
|
||||
The plot's boundaries automatically shrink to the min value encountered by the plot. The initial
|
||||
determines the starting boundaries from which the shrink behavior will be based.
|
||||
|
||||
## Domain & Range Lines
|
||||
These are the horizontal lines drawn on a graph. These lines are configured via:
|
||||
|
||||
* `XYPlot.setDomainStep(StepMode mode, Number value)`
|
||||
* `XYPlot.setRangeStep(StepMode, Number value)`
|
||||
|
||||
Androidplot provides these step modes:
|
||||
|
||||
### Subdivide
|
||||
When using `StepMode.SUBDIVIDE`, the graph is subdivided into the specified number of sections.
|
||||
|
||||
### IncrementByValue
|
||||
`StepMode.INCREMENT_BY_VALUE` instructs Androidplot draw grid lines at the specified interval. This
|
||||
is the most commonly used modes as is produces an easy to read result.
|
||||
|
||||
### IncrementByPixels
|
||||
`StepMode.INCREMENT_BY_PIXELS` behaves identically to `StepMode.INCREMENT_BY_VALUE` except that
|
||||
the increment quantity is expressed in pixels.
|
||||
|
||||
## Domain & Range Labels
|
||||
Androidplot supports labeling domain values on either or both the top and bottom graph edges
|
||||
and range values on either or both the left and right graph edges. Most default styles show labels
|
||||
only on the left and bottom edges.
|
||||
|
||||
### Line Label Insets
|
||||
Insets are used to control where line labels are drawn in relation to the graph space. The Insets instance
|
||||
can be obtained via `XYPlot.getGraph().getLineLabelInsets()`. For example, to
|
||||
move the range labels on the left of the graph further to the left by 5dp:
|
||||
|
||||
xml
|
||||
```xml
|
||||
ap:lineLabelInsetLeft="-5dp"
|
||||
```
|
||||
|
||||
java
|
||||
```java
|
||||
plot.getGraph().getLineLabelInsets().setLeft(PixelUtils.dpToPix(-5));
|
||||
```
|
||||
|
||||
### Dual Axis Labels
|
||||
Androidplot provides methods for enabling / disabling axis labels along all edges of the graph. By
|
||||
default, only the left and bottom edge labels are enabled. To enable labels on the right edge:
|
||||
|
||||
xml
|
||||
```xml
|
||||
ap:lineLabels="left|bottom|right"
|
||||
```
|
||||
|
||||
java
|
||||
```java
|
||||
plot.getGraph().setLineLabelEdges(
|
||||
XYGraphWidget.Edge.BOTTOM,
|
||||
XYGraphWidget.Edge.LEFT,
|
||||
XYGraphWidget.Edge.RIGHT);
|
||||
```
|
||||
|
||||
Once the edge has been enabled, text formatting can be controlled by enabling a custom formatter
|
||||
for the desired edge:
|
||||
|
||||
```java
|
||||
plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.RIGHT).setFormat(new Format() {
|
||||
@Override
|
||||
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
|
||||
// obj contains the raw Number value representing the position of the label being drawn.
|
||||
// customize the labeling however you want here:
|
||||
int i = Math.round(((Number) obj).floatValue());
|
||||
return toAppendTo.append(i + " thingies");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseObject(String source, ParsePosition pos) {
|
||||
// unused
|
||||
return null;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
You're likely also going to need to normalize your series data in order to get it to display properly. To help simplify
|
||||
this step, Androidplot provides [NormedXYSeries](advanced_xy_plot.md#normedxyseries)
|
||||
which can be used to wrap any `XYSeries` to provide the normalized representation of it's data.
|
||||
|
||||
There's a full [reference implementation](../demoapp/src/main/java/com/androidplot/demos/DualScaleActivity.java)
|
||||
of a dual scale plot using a custom `Formatter` and `NormedXYSeries` in the DemoApp.
|
||||
|
||||
|
||||
### Line Label Interval
|
||||
Androidplot allows you to configure the interval at which labels are rendered for domain and range lines:
|
||||
|
||||
* `XYPlot.getGraph().setLinesPerDomainLabel(int interval)`
|
||||
* `XYPlot.getGraph().setLinesPerRangeLabel(int interval)`
|
||||
|
||||
### LineLabelStyle
|
||||
The styling of the line labels drawn on each edge of the graph is controlled by it's associated style.
|
||||
this style contains params that control:
|
||||
|
||||
* Paint used to draw labels (determines, color, font size, etc.)
|
||||
* Format used to draw text (can be NumberFormat, etc.)
|
||||
* Rotation of the label text
|
||||
|
||||
To get the style used to draw the left edge (range) labels:
|
||||
|
||||
```java
|
||||
plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.LEFT);
|
||||
```
|
||||
|
||||
### LineLabelRenderer
|
||||
If you need to implement special rendering behavior for your line labels, such as drawing graphics, symbols, etc.
|
||||
you can create a custom renderer by extending LineLabelRenderer and injecting it into the graph:
|
||||
|
||||
```java
|
||||
plot.getGraph().setLineLabelRenderer(XYGraphWidget.Edge.LEFT, customLineLabelRenderer);
|
||||
```
|
||||
|
||||
[f(x) plot example source](../demoapp/src/main/java/com/androidplot/demos/FXPlotExampleActivity.java)
|
||||
provides an example of this kind of customization.
|
||||
|
||||
# Pan & Zoom
|
||||
You can enable pan/zoom behavior on any instance of XYPlot using the PanZoom class like this:
|
||||
|
||||
```java
|
||||
PanZoom.attach(plot);
|
||||
```
|
||||
|
||||
The default behavior is to enable horizontal and vertical panning an to zoom using uniform scaling.
|
||||
If you want to override this behavior use the three argument form of `PanZoom.attach(Plot)`. For example,
|
||||
to enable pan and zoom (stretch) on the horizontal axis only:
|
||||
|
||||
```java
|
||||
PanZoom.attach(plot, PanZoom.Pan.HORIZONTAL, PanZoom.Zoom.STRETCH_HORIZONTAL);
|
||||
```
|
||||
|
||||
Pan and zoom operations abide by your plot's defined outer limits limits. If no such limits have been set
|
||||
then the plot will pan and zoom on both axes infinitely. To set the plot's outer limits:
|
||||
|
||||
```java
|
||||
// cap pan/zoom limits for panning and zooming to a 100x100 space:
|
||||
plot.getOuterLimits().set(0, 100, 0, 100);
|
||||
```
|
||||
|
||||
# Saving & Restoring PanZoom State
|
||||
The `PanZoom` class provides convenience methods for saving and restoring state from your `Activity`:
|
||||
|
||||
```java
|
||||
// save the current pan/zoom state
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle bundle) {
|
||||
bundle.putSerializable("pan-zoom-state", panZoom.getState());
|
||||
}
|
||||
|
||||
// restore the previously saved pan/zoom state
|
||||
@Override
|
||||
public void onRestoreInstanceState(Bundle bundle) {
|
||||
PanZoom.State state = (PanZoom.State) bundle.getSerializable("pan-zoom-state");
|
||||
panZoom.setState(state);
|
||||
plot.redraw();
|
||||
}
|
||||
```
|
||||
|
||||
For a more detailed look at pan & zoom behavior, check out the [Touch Zoom Example source code](../demoapp/src/main/java/com/androidplot/demos/TouchZoomExampleActivity.java).
|
||||
|
||||
# Series Renderers
|
||||
There are several renderers available for XYPlots:
|
||||
|
||||
* LineAndPointRenderer
|
||||
* BarRenderer
|
||||
* CandlestickRenderer
|
||||
|
||||
When you add a new series to your plot, you tell Androidplot how to render it by passing
|
||||
in a subclass of `XYSeriesFormatter` that corresponds to the desired renderer. For example, to use
|
||||
`LineAndPointRenderer`, you'd register your series with an instance of `LineAndPointFormatter`:
|
||||
|
||||
```java
|
||||
LineAndPointFormatter format = new LineAndPointFormatter();
|
||||
plot.addSeries(series, format);
|
||||
```
|
||||
|
||||
If you need special behavior not provided by an existing renderer you can create
|
||||
your own by either extending `XYSeriesRenderer` or one of the above implementations. You'll also need
|
||||
to create a matching implementation of `XYSeriesFormatter` that returns your renderer's class
|
||||
from it's `getRendererClass()` method.
|
||||
|
||||
## LineAndPointRenderer
|
||||
`LineAndPointRenderer` is the go-to renderer when it comes to `XYSeries`. It provides the most robust
|
||||
feature set of any `XYSeriesRenderer` and has been the most carefully optimized for performance. Having
|
||||
said that, `LineAndPointRenderer` isn't always the best tool for the job. Androidplot includes two
|
||||
additional variations of `LineAndPointRenderer`:
|
||||
|
||||
* **FastLineAndPointRenderer** - intended for use in apps displaying large amounts of dynamic data where
|
||||
fast refresh rates are important.
|
||||
* **AdvancedLineAndPointRenderer** - provides capabilities for dynamically coloring individual line
|
||||
segments, etc. See the [ECGExample source](../demoapp/src/main/java/com/androidplot/demos/ECGExample.java)
|
||||
in the demo app for a complete example.
|
||||
|
||||
### Labeling Points
|
||||
Most implementations of `XYSeriesRenderer` support labeling rendered points with text. This functionality
|
||||
is activated by setting the `PointLabelFormatter` property in the associated `XYSeriesFormatter`. For
|
||||
example, to enable point labels for a `LineAndPointFormatter`:
|
||||
|
||||
// create a new `PointLabelFormatter` with a text size of 12sp and a color of red:
|
||||
|
||||
```java
|
||||
PointLabelFormatter plf = new PointLabelFormatter();
|
||||
plf.getTextPaint().setTextSize(PixelUtils.spToPix(12));
|
||||
plf.getTextPaint().setColor(Color.RED);
|
||||
lineAndPointFormatter.setPointLabelFormatter(plf);
|
||||
```
|
||||
|
||||
By default this will enable labels for all points using a string representation of the yVal of each
|
||||
point. This behavior can be customized by setting a custom instance of `PointLabeler` on the `XYSeriesFormatter`:
|
||||
|
||||
```java
|
||||
formatter.setPointLabeler(new PointLabeler() {
|
||||
@Override
|
||||
public String getLabel(XYSeries series, int index) {
|
||||
// draw labels on even indexes only:
|
||||
if(index % 2 == 0) {
|
||||
return "Y=" + series.getY(index).doubleValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## BarRenderer
|
||||
See the [barcharts documentation](barchart.md).
|
||||
|
||||
## CandlestickRenderer
|
||||
See the [candlestick documentation](candlestick.md)
|
||||
|
||||
# Drawing Smooth Lines
|
||||
Smooth lines can be created by applying the
|
||||
[Catmull-Rom interpolator](http://androidplot.com/smooth-curves-and-androidplot/) to your series' Format.
|
||||
|
||||
# The Legend <a name="legend"></a>
|
||||
By default, Androidplot will automatically produce a legend for your `XYPlot`. See [the legend](legend.md) doc
|
||||
for usage details.
|
||||
|
||||
# Graph Rotation
|
||||
Androidplot provides the `Widget.setRotation(Widget.Rotation)` method for controlling the orientation
|
||||
of Widgets. For example, if you wanted to create a bar graph where the bars extended across the screen
|
||||
from left to right:
|
||||
|
||||
xml
|
||||
```xml
|
||||
ap:graphRotation="ninety_degrees"
|
||||
```
|
||||
|
||||
java
|
||||
```java
|
||||
plot.getGraph().setRotation(Widget.Rotation.NINETY_DEGREES);
|
||||
```
|
||||
|
||||
# Optimization Tips
|
||||
Here are a few suggestions to improve performance when plotting dynamic data:
|
||||
|
||||
* Create your own implementation of `XYSeries` to work with your data in it's rawest form.
|
||||
* Use `FastLineAndPointRenderer` instead of `LineAndPointRenderer`:
|
||||
|
||||
```java
|
||||
plot.addSeries(azimuthHistorySeries,
|
||||
new FastLineAndPointRenderer.Formatter(
|
||||
Color.rgb(100, 100, 200), null, null, null));
|
||||
```
|
||||
|
||||
* Consider averaging or subsampling very large datasets before rendering. If you have the time and
|
||||
inclination, [the LTTB algorithm](http://skemman.is/stream/get/1946/15343/37285/3/SS_MSthesis.pdf) is
|
||||
particularly well suited for downsampling `XYSeries` data.
|
||||
* If possible, avoid rendering vertices (points).
|
||||
* Disable anti-aliasing on your `XYSeriesFormatter`'s paint values:
|
||||
|
||||
```java
|
||||
LineAndPointFormatter format = new LineAndPointFormatter(...);
|
||||
format.getLinePaint().setAntiAlias(false);
|
||||
```
|
||||
# Converting Values
|
||||
Because the coordinate system used by your `XYSeries` data is almost always different than the screen
|
||||
coordinate system upon which the data is rendered, you'll often need to convert from one system to
|
||||
the other. `XYPlot` provides convenience methods for this purpose:
|
||||
|
||||
## Screen to Series Conversion
|
||||
```java
|
||||
// x
|
||||
float screenX = ...
|
||||
Number x = plot.screenToSeriesX(screenX);
|
||||
|
||||
// y
|
||||
float screenY = ...
|
||||
Number y = plot.screenToSeriesY(screenY);
|
||||
|
||||
// x and y
|
||||
PointF screenCoords = ...
|
||||
XYCoords xy = plot.screenToSeries(screenCoords)
|
||||
```
|
||||
|
||||
## Series to Screen Conversion
|
||||
```java
|
||||
// x
|
||||
Number x = ...
|
||||
float screenX = plot.seriesToScreenX(x);
|
||||
|
||||
// y
|
||||
Number y = ...
|
||||
float screenY = plot.seriesToScreenY(y);
|
||||
|
||||
// x and y
|
||||
XYCoords xy = ...
|
||||
PointF screenCoords = plot.series.Screen(xy);
|
||||
```
|
||||
|
||||
# Whats Next?
|
||||
Explore [Advanced XYPlot Topics](advanced_xy_plot.md)
|
||||