blob: c3d43ecafa3d143f33cd37d9c137606e78dff276 [file] [log] [blame]
package com.github.mikephil.charting.data;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import com.github.mikephil.charting.components.YAxis.AxisDependency;
import com.github.mikephil.charting.interfaces.datainterfaces.datasets.IDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.github.mikephil.charting.formatter.DefaultValueFormatter;
import com.github.mikephil.charting.utils.Utils;
import com.github.mikephil.charting.formatter.ValueFormatter;
import java.util.ArrayList;
import java.util.List;
/**
* The DataSet class represents one group or type of entries (Entry) in the
* Chart that belong together. It is designed to logically separate different
* groups of values inside the Chart (e.g. the values for a specific line in the
* LineChart, or the values of a specific group of bars in the BarChart).
*
* @author Philipp Jahoda
*/
public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
/**
* the entries that this dataset represents / holds together
*/
protected List<T> mYVals = null;
/**
* List representing all colors that are used for this DataSet
*/
protected List<Integer> mColors = null;
/**
* label that describes the DataSet or the data the DataSet represents
*/
private String mLabel = "DataSet";
/**
* flag that indicates if the DataSet is visible or not
*/
private boolean mVisible = true;
/**
* if true, y-values are drawn on the chart
*/
protected boolean mDrawValues = true;
/**
* the color used for the value-text
*/
private int mValueColor = Color.BLACK;
/**
* the size of the value-text labels
*/
private float mValueTextSize = 17f;
/**
* the typeface used for the value text
*/
private Typeface mValueTypeface;
/**
* custom formatter that is used instead of the auto-formatter if set
*/
protected transient ValueFormatter mValueFormatter;
/**
* this specifies which axis this DataSet should be plotted against
*/
protected AxisDependency mAxisDependency = AxisDependency.LEFT;
/**
* if true, value highlightning is enabled
*/
protected boolean mHighlightEnabled = true;
/**
* Creates a new DataSet object with the given values it represents. Also, a
* label that describes the DataSet can be specified. The label can also be
* used to retrieve the DataSet from a ChartData object.
*
* @param yVals
* @param label
*/
public DataSet(List<T> yVals, String label) {
this.mLabel = label;
this.mYVals = yVals;
if (mYVals == null)
mYVals = new ArrayList<T>();
mColors = new ArrayList<Integer>();
// default color
mColors.add(Color.rgb(140, 234, 255));
calcMinMax(mYVals, mLastStart, mLastEnd);
}
/**
* Use this method to tell the data set that the underlying data has changed
*/
public void notifyDataSetChanged() {
calcMinMax(mYVals, mLastStart, mLastEnd);
}
/**
* Returns the average value across all entries in this DataSet.
*
* @return
*/
public float getAverage() {
return (float) getYValueSum() / (float) getValueCount();
}
@Override
public int getEntryCount() {
return mYVals.size();
}
/**
* Returns the value of the Entry object at the given xIndex. Returns
* Float.NaN if no value is at the given x-index. INFORMATION: This method
* does calculations at runtime. Do not over-use in performance critical
* situations.
*
* @param xIndex
* @return
*/
public float getYValForXIndex(int xIndex) {
Entry e = getEntryForXIndex(xIndex);
if (e != null && e.getXIndex() == xIndex)
return e.getVal();
else
return Float.NaN;
}
@Override
public T getEntryForXIndex(int x) {
int index = getEntryIndex(x);
if (index > -1)
return mYVals.get(index);
return null;
}
/**
* Returns the first Entry index found at the given xIndex with binary
* search. If the no Entry at the specified x-index is found, this method
* returns the index at the closest x-index. Returns -1 if no Entry object
* at that index. INFORMATION: This method does calculations at runtime. Do
* not over-use in performance critical situations.
*
* @param x
* @return
*/
public int getEntryIndex(int x) {
int low = 0;
int high = mYVals.size() - 1;
int closest = -1;
while (low <= high) {
int m = (high + low) / 2;
if (x == mYVals.get(m).getXIndex()) {
while (m > 0 && mYVals.get(m - 1).getXIndex() == x)
m--;
return m;
}
if (x > mYVals.get(m).getXIndex())
low = m + 1;
else
high = m - 1;
closest = m;
}
return closest;
}
/**
* Returns all Entry objects at the given xIndex. INFORMATION: This method
* does calculations at runtime. Do not over-use in performance critical
* situations.
*
* @param x
* @return
*/
public List<T> getEntriesForXIndex(int x) {
List<T> entries = new ArrayList<T>();
int low = 0;
int high = mYVals.size() - 1;
while (low <= high) {
int m = (high + low) / 2;
T entry = mYVals.get(m);
if (x == entry.getXIndex()) {
while (m > 0 && mYVals.get(m - 1).getXIndex() == x)
m--;
high = mYVals.size();
for (; m < high; m++) {
entry = mYVals.get(m);
if (entry.getXIndex() == x) {
entries.add(entry);
} else {
break;
}
}
}
if (x > entry.getXIndex())
low = m + 1;
else
high = m - 1;
}
return entries;
}
@Override
public List<T> getYVals() {
return mYVals;
}
@Override
public float getYMin() {
return mYMin;
}
@Override
public float getYMax() {
return mYMax;
}
/**
* Returns the number of entries this DataSet holds.
*
* @return
*/
public int getValueCount() {
return mYVals.size();
}
/**
* The xIndex of an Entry object is provided. This method returns the actual
* index in the Entry array of the DataSet. IMPORTANT: This method does
* calculations at runtime, do not over-use in performance critical
* situations.
*
* @param xIndex
* @return
*/
public int getIndexInEntries(int xIndex) {
for (int i = 0; i < mYVals.size(); i++) {
if (xIndex == mYVals.get(i).getXIndex())
return i;
}
return -1;
}
/**
* Provides an exact copy of the DataSet this method is used on.
*
* @return
*/
public abstract DataSet<T> copy();
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(toSimpleString());
for (int i = 0; i < mYVals.size(); i++) {
buffer.append(mYVals.get(i).toString() + " ");
}
return buffer.toString();
}
/**
* Returns a simple string representation of the DataSet with the type and
* the number of Entries.
*
* @return
*/
public String toSimpleString() {
StringBuffer buffer = new StringBuffer();
buffer.append("DataSet, label: " + (mLabel == null ? "" : mLabel) + ", entries: " + mYVals.size() + "\n");
return buffer.toString();
}
/**
* Sets the label string that describes the DataSet.
*
* @return
*/
public void setLabel(String label) {
mLabel = label;
}
@Override
public String getLabel() {
return mLabel;
}
/**
* Set the visibility of this DataSet. If not visible, the DataSet will not
* be drawn to the chart upon refreshing it.
*
* @param visible
*/
public void setVisible(boolean visible) {
mVisible = visible;
}
/**
* Returns true if this DataSet is visible inside the chart, or false if it
* is currently hidden.
*
* @return
*/
public boolean isVisible() {
return mVisible;
}
@Override
public AxisDependency getAxisDependency() {
return mAxisDependency;
}
/**
* Set the y-axis this DataSet should be plotted against (either LEFT or
* RIGHT). Default: LEFT
*
* @param dependency
*/
public void setAxisDependency(AxisDependency dependency) {
mAxisDependency = dependency;
}
/**
* set this to true to draw y-values on the chart NOTE (for bar and
* linechart): if "maxvisiblecount" is reached, no values will be drawn even
* if this is enabled
*
* @param enabled
*/
public void setDrawValues(boolean enabled) {
this.mDrawValues = enabled;
}
/**
* returns true if y-value drawing is enabled, false if not
*
* @return
*/
public boolean isDrawValuesEnabled() {
return mDrawValues;
}
/**
* Adds an Entry to the DataSet dynamically.
* Entries are added to the end of the list.
* This will also recalculate the current minimum and maximum
* values of the DataSet and the value-sum.
*
* @param e
*/
@SuppressWarnings("unchecked")
public void addEntry(Entry e) {
if (e == null)
return;
float val = e.getVal();
if (mYVals == null) {
mYVals = new ArrayList<T>();
}
if (mYVals.size() == 0) {
mYMax = val;
mYMin = val;
} else {
if (mYMax < val)
mYMax = val;
if (mYMin > val)
mYMin = val;
}
// add the entry
mYVals.add((T) e);
}
/**
* Adds an Entry to the DataSet dynamically.
* Entries are added to their appropriate index respective to it's x-index.
* This will also recalculate the current minimum and maximum
* values of the DataSet and the value-sum.
*
* @param e
*/
@SuppressWarnings("unchecked")
public void addEntryOrdered(Entry e) {
if (e == null)
return;
float val = e.getVal();
if (mYVals == null) {
mYVals = new ArrayList<T>();
}
if (mYVals.size() == 0) {
mYMax = val;
mYMin = val;
} else {
if (mYMax < val)
mYMax = val;
if (mYMin > val)
mYMin = val;
}
if (mYVals.size() > 0 && mYVals.get(mYVals.size() - 1).getXIndex() > e.getXIndex()) {
int closestIndex = getEntryIndex(e.getXIndex());
if (mYVals.get(closestIndex).getXIndex() < e.getXIndex())
closestIndex++;
mYVals.add(closestIndex, (T) e);
return;
}
mYVals.add((T) e);
}
/**
* Removes an Entry from the DataSets entries array. This will also
* recalculate the current minimum and maximum values of the DataSet and the
* value-sum. Returns true if an Entry was removed, false if no Entry could
* be removed.
*
* @param e
*/
public boolean removeEntry(T e) {
if (e == null)
return false;
// remove the entry
boolean removed = mYVals.remove(e);
if (removed) {
calcMinMax(mYVals, mLastStart, mLastEnd);
}
return removed;
}
/**
* Removes the Entry object that has the given xIndex from the DataSet.
* Returns true if an Entry was removed, false if no Entry could be removed.
*
* @param xIndex
*/
public boolean removeEntry(int xIndex) {
T e = getEntryForXIndex(xIndex);
return removeEntry(e);
}
/**
* Removes the first Entry (at index 0) of this DataSet from the entries array.
* Returns true if successful, false if not.
*
* @return
*/
public boolean removeFirst() {
T entry = mYVals.remove(0);
boolean removed = entry != null;
if (removed) {
calcMinMax(mYVals, mLastStart, mLastEnd);
}
return removed;
}
/**
* Removes the last Entry (at index size-1) of this DataSet from the entries array.
* Returns true if successful, false if not.
*
* @return
*/
public boolean removeLast() {
if (mYVals.size() <= 0)
return false;
T entry = mYVals.remove(mYVals.size() - 1);
boolean removed = entry != null;
if (removed) {
calcMinMax(mYVals, mLastStart, mLastEnd);
}
return removed;
}
/** BELOW THIS COLOR HANDLING */
/**
* Sets the colors that should be used fore this DataSet. Colors are reused
* as soon as the number of Entries the DataSet represents is higher than
* the size of the colors array. If you are using colors from the resources,
* make sure that the colors are already prepared (by calling
* getResources().getColor(...)) before adding them to the DataSet.
*
* @param colors
*/
public void setColors(List<Integer> colors) {
this.mColors = colors;
}
/**
* Sets the colors that should be used fore this DataSet. Colors are reused
* as soon as the number of Entries the DataSet represents is higher than
* the size of the colors array. If you are using colors from the resources,
* make sure that the colors are already prepared (by calling
* getResources().getColor(...)) before adding them to the DataSet.
*
* @param colors
*/
public void setColors(int[] colors) {
this.mColors = ColorTemplate.createColors(colors);
}
/**
* Sets the colors that should be used fore this DataSet. Colors are reused
* as soon as the number of Entries the DataSet represents is higher than
* the size of the colors array. You can use
* "new int[] { R.color.red, R.color.green, ... }" to provide colors for
* this method. Internally, the colors are resolved using
* getResources().getColor(...)
*
* @param colors
*/
public void setColors(int[] colors, Context c) {
List<Integer> clrs = new ArrayList<Integer>();
for (int color : colors) {
clrs.add(c.getResources().getColor(color));
}
mColors = clrs;
}
/**
* Adds a new color to the colors array of the DataSet.
*
* @param color
*/
public void addColor(int color) {
if (mColors == null)
mColors = new ArrayList<Integer>();
mColors.add(color);
}
/**
* Sets the one and ONLY color that should be used for this DataSet.
* Internally, this recreates the colors array and adds the specified color.
*
* @param color
*/
public void setColor(int color) {
resetColors();
mColors.add(color);
}
@Override
public List<Integer> getColors() {
return mColors;
}
/**
* Returns the color at the given index of the DataSet's color array.
* Performs a IndexOutOfBounds check by modulus.
*
* @param index
* @return
*/
public int getColor(int index) {
return mColors.get(index % mColors.size());
}
/**
* Returns the first color (index 0) of the colors-array this DataSet
* contains.
*
* @return
*/
public int getColor() {
return mColors.get(0);
}
/**
* Resets all colors of this DataSet and recreates the colors array.
*/
public void resetColors() {
mColors = new ArrayList<Integer>();
}
/**
* If set to true, value highlighting is enabled which means that values can
* be highlighted programmatically or by touch gesture.
*
* @param enabled
*/
public void setHighlightEnabled(boolean enabled) {
mHighlightEnabled = enabled;
}
@Override
public boolean isHighlightEnabled() {
return mHighlightEnabled;
}
/**
* Returns the position of the provided entry in the DataSets Entry array.
* Returns -1 if doesn't exist.
*
* @param e
* @return
*/
public int getEntryPosition(Entry e) {
for (int i = 0; i < mYVals.size(); i++) {
if (e.equalTo(mYVals.get(i)))
return i;
}
return -1;
}
/**
* Sets the formatter to be used for drawing the values inside the chart. If
* no formatter is set, the chart will automatically determine a reasonable
* formatting (concerning decimals) for all the values that are drawn inside
* the chart. Use chart.getDefaultValueFormatter() to use the formatter
* calculated by the chart.
*
* @param f
*/
public void setValueFormatter(ValueFormatter f) {
if (f == null)
return;
else
mValueFormatter = f;
}
/**
* Returns the formatter used for drawing the values inside the chart.
*
* @return
*/
public ValueFormatter getValueFormatter() {
if (mValueFormatter == null)
return new DefaultValueFormatter(1);
return mValueFormatter;
}
/**
* If this component has no ValueFormatter or is only equipped with the
* default one (no custom set), return true.
*
* @return
*/
public boolean needsDefaultFormatter() {
if (mValueFormatter == null)
return true;
if (mValueFormatter instanceof DefaultValueFormatter)
return true;
return false;
}
/**
* Sets the color the value-labels of this DataSet should have.
*
* @param color
*/
public void setValueTextColor(int color) {
mValueColor = color;
}
public int getValueTextColor() {
return mValueColor;
}
/**
* Sets a Typeface for the value-labels of this DataSet.
*
* @param tf
*/
public void setValueTypeface(Typeface tf) {
mValueTypeface = tf;
}
public Typeface getValueTypeface() {
return mValueTypeface;
}
/**
* Sets the text-size of the value-labels of this DataSet in dp.
*
* @param size
*/
public void setValueTextSize(float size) {
mValueTextSize = Utils.convertDpToPixel(size);
}
/**
* Returns the text-size of the labels that are displayed above the values.
*
* @return
*/
public float getValueTextSize() {
return mValueTextSize;
}
@Override
public boolean contains(Entry e) {
for (Entry entry : mYVals) {
if (entry.equals(e))
return true;
}
return false;
}
/**
* Removes all values from this DataSet and recalculates min and max value.
*/
public void clear() {
mYVals.clear();
mLastStart = 0;
mLastEnd = 0;
notifyDataSetChanged();
}
}