Skip to content

Commit

Permalink
Highlight enhancements
Browse files Browse the repository at this point in the history
There are certain cases (ie. bubbles) which make sense to have multiple
values per xIndex.
This fixes that - and adds more granular highlight for Combined Chart.
  • Loading branch information
danielgindi committed May 1, 2016
1 parent a3e4450 commit a002634
Show file tree
Hide file tree
Showing 20 changed files with 499 additions and 144 deletions.
22 changes: 17 additions & 5 deletions MPChartLib/src/com/github/mikephil/charting/charts/Chart.java
Original file line number Diff line number Diff line change
Expand Up @@ -556,15 +556,24 @@ public void highlightValues(Highlight[] highs) {
* @param dataSetIndex
*/
public void highlightValue(int xIndex, int dataSetIndex) {
highlightValue(xIndex, dataSetIndex, true);
}

/**
* Highlights the value at the given x-index in the given DataSet. Provide
* -1 as the x-index or dataSetIndex to undo all highlighting.
*
* @param xIndex
* @param dataSetIndex
*/
public void highlightValue(int xIndex, int dataSetIndex, boolean callListener) {

if (xIndex < 0 || dataSetIndex < 0 || xIndex >= mData.getXValCount()
|| dataSetIndex >= mData.getDataSetCount()) {

highlightValues(null);
highlightValue(null, callListener);
} else {
highlightValues(new Highlight[]{
new Highlight(xIndex, dataSetIndex)
});
highlightValue(new Highlight(xIndex, dataSetIndex), callListener);
}
}

Expand Down Expand Up @@ -598,7 +607,10 @@ public void highlightValue(Highlight high, boolean callListener) {
Log.i(LOG_TAG, "Highlighted: " + high.toString());

e = mData.getEntryForHighlight(high);
if (e == null || e.getXIndex() != high.getXIndex()) {
if (e == null ||
e.getXIndex() != high.getXIndex() ||
(!Float.isNaN(high.getValue()) &&
e.getVal() != high.getValue())) {
mIndicesToHighlight = null;
high = null;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ public List<SelectionDetail> getSelectionDetailsAtIndex(int xIndex) {

// extract all y-values from all DataSets at the given x-index
final float yVal = dataSet.getYValForXIndex(xIndex);
if (yVal == Float.NaN)
if (Float.isNaN(yVal))
continue;

vals.add(new SelectionDetail(yVal, i, dataSet));
Expand Down
16 changes: 13 additions & 3 deletions MPChartLib/src/com/github/mikephil/charting/data/ChartData.java
Original file line number Diff line number Diff line change
Expand Up @@ -472,9 +472,19 @@ protected String[] getDataSetLabels() {
public Entry getEntryForHighlight(Highlight highlight) {
if (highlight.getDataSetIndex() >= mDataSets.size())
return null;
else
return mDataSets.get(highlight.getDataSetIndex()).getEntryForXIndex(
highlight.getXIndex());
else {
// The value of the highlighted entry could be NaN -
// if we are not interested in highlighting a specific value.

List<?> entries = mDataSets.get(highlight.getDataSetIndex())
.getEntriesForXIndex(highlight.getXIndex());
for (Object entry : entries)
if (((Entry)entry).getVal() == highlight.getValue() ||
Float.isNaN(highlight.getValue()))
return (Entry)entry;

return null;
}
}

/**
Expand Down
34 changes: 34 additions & 0 deletions MPChartLib/src/com/github/mikephil/charting/data/CombinedData.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

package com.github.mikephil.charting.data;

import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarLineScatterCandleBubbleDataSet;

import java.util.ArrayList;
Expand Down Expand Up @@ -118,4 +119,37 @@ public void notifyDataChanged() {

init(); // recalculate everything
}

/**
* Get the Entry for a corresponding highlight object
*
* @param highlight
* @return the entry that is highlighted
*/
@Override
public Entry getEntryForHighlight(Highlight highlight) {

List<ChartData> dataObjects = getAllData();

if (highlight.getDataIndex() >= dataObjects.size())
return null;

ChartData data = dataObjects.get(highlight.getDataIndex());

if (highlight.getDataSetIndex() >= data.getDataSetCount())
return null;
else {
// The value of the highlighted entry could be NaN -
// if we are not interested in highlighting a specific value.

List<?> entries = data.getDataSetByIndex(highlight.getDataSetIndex())
.getEntriesForXIndex(highlight.getXIndex());
for (Object entry : entries)
if (((Entry)entry).getVal() == highlight.getValue() ||
Float.isNaN(highlight.getValue()))
return (Entry)entry;

return null;
}
}
}
27 changes: 22 additions & 5 deletions MPChartLib/src/com/github/mikephil/charting/data/DataSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,20 @@ public float getYValForXIndex(int xIndex) {
return Float.NaN;
}

@Override
public float[] getYValsForXIndex(int xIndex) {

List<T> entries = getEntriesForXIndex(xIndex);

float[] yVals = new float[entries.size()];
int i = 0;

for (T e : entries)
yVals[i++] = e.getVal();

return yVals;
}

/**
* Returns all Entry objects at the given xIndex. INFORMATION: This method
* does calculations at runtime. Do not over-use in performance critical
Expand All @@ -320,6 +334,7 @@ public float getYValForXIndex(int xIndex) {
* @param xIndex
* @return
*/
@Override
public List<T> getEntriesForXIndex(int xIndex) {

List<T> entries = new ArrayList<T>();
Expand All @@ -344,12 +359,14 @@ public List<T> getEntriesForXIndex(int xIndex) {
break;
}
}
}

if (xIndex > entry.getXIndex())
low = m + 1;
else
high = m - 1;
break;
} else {
if (xIndex > entry.getXIndex())
low = m + 1;
else
high = m - 1;
}
}

return entries;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,25 @@ public S getEntryForXIndex(int xIndex, DataSet.Rounding rounding) {
return null;
}

@Override
public List<S> getEntriesForXIndex(int xIndex) {

List<S> entries = new ArrayList<>();

if (mIndexField == null) {
T object = results.get(xIndex);
if (object != null)
entries.add(buildEntryFromResultObject(object, xIndex));
} else {
RealmResults<T> foundObjects = results.where().equalTo(mIndexField, xIndex).findAll();

for (T e : foundObjects)
entries.add(buildEntryFromResultObject(e, xIndex));
}

return entries;
}

@Override
public S getEntryForIndex(int index) {
//DynamicRealmObject o = new DynamicRealmObject(results.get(index));
Expand Down Expand Up @@ -231,6 +250,20 @@ public float getYValForXIndex(int xIndex) {
return Float.NaN;
}

@Override
public float[] getYValsForXIndex(int xIndex) {

List<S> entries = getEntriesForXIndex(xIndex);

float[] yVals = new float[entries.size()];
int i = 0;

for (S e : entries)
yVals[i++] = e.getVal();

return yVals;
}

@Override
public boolean addEntry(S e) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.github.mikephil.charting.highlight;

import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.utils.SelectionDetail;

/**
* Created by Philipp Jahoda on 22/07/15.
Expand All @@ -17,27 +20,44 @@ public BarHighlighter(BarDataProvider chart) {
@Override
public Highlight getHighlight(float x, float y) {

Highlight h = super.getHighlight(x, y);
BarData barData = mChart.getBarData();

if (h == null)
return h;
else {
final int xIndex = getXIndex(x);
final float baseNoSpace = getBase(x);
final int setCount = barData.getDataSetCount();
int dataSetIndex = ((int)baseNoSpace) % setCount;

IBarDataSet set = mChart.getBarData().getDataSetByIndex(h.getDataSetIndex());
if (dataSetIndex < 0) {
dataSetIndex = 0;
} else if (dataSetIndex >= setCount) {
dataSetIndex = setCount - 1;
}

SelectionDetail selectionDetail = getSelectionDetail(xIndex, y, dataSetIndex);
if (selectionDetail == null)
return null;

if (set.isStacked()) {
IBarDataSet set = barData.getDataSetByIndex(dataSetIndex);
if (set.isStacked()) {

// create an array of the touch-point
float[] pts = new float[2];
pts[1] = y;
float[] pts = new float[2];
pts[1] = y;

// take any transformer to determine the x-axis value
mChart.getTransformer(set.getAxisDependency()).pixelsToValue(pts);
// take any transformer to determine the x-axis value
mChart.getTransformer(set.getAxisDependency()).pixelsToValue(pts);

return getStackedHighlight(h, set, h.getXIndex(), h.getDataSetIndex(), pts[1]);
} else
return h;
return getStackedHighlight(selectionDetail,
set,
xIndex,
pts[1]);
}

return new Highlight(
xIndex,
selectionDetail.value,
selectionDetail.dataIndex,
selectionDetail.dataSetIndex,
-1);
}

@Override
Expand All @@ -64,51 +84,68 @@ else if (xIndex >= valCount)
}

@Override
protected int getDataSetIndex(int xIndex, float x, float y) {
protected SelectionDetail getSelectionDetail(int xIndex, float y, int dataSetIndex) {

if (!mChart.getBarData().isGrouped()) {
return 0;
} else {
dataSetIndex = Math.max(dataSetIndex, 0);

float baseNoSpace = getBase(x);
BarData barData = mChart.getBarData();
IDataSet dataSet = barData.getDataSetCount() > dataSetIndex
? barData.getDataSetByIndex(dataSetIndex)
: null;
if (dataSet == null)
return null;

int setCount = mChart.getBarData().getDataSetCount();
int dataSetIndex = (int) baseNoSpace % setCount;
final float yValue = dataSet.getYValForXIndex(xIndex);

if (dataSetIndex < 0)
dataSetIndex = 0;
else if (dataSetIndex >= setCount)
dataSetIndex = setCount - 1;
if (yValue == Double.NaN) return null;

return dataSetIndex;
}
return new SelectionDetail(
yValue,
dataSetIndex,
dataSet);
}

/**
* This method creates the Highlight object that also indicates which value of a stacked BarEntry has been selected.
*
* @param old
* the old highlight object before looking for stacked values
* @param selectionDetail the selection detail to work with looking for stacked values
* @param set
* @param xIndex
* @param dataSetIndex
* @param yValue
* @return
*/
protected Highlight getStackedHighlight(Highlight old, IBarDataSet set, int xIndex, int dataSetIndex, double yValue) {
protected Highlight getStackedHighlight(
SelectionDetail selectionDetail,
IBarDataSet set,
int xIndex,
double yValue) {

BarEntry entry = set.getEntryForXIndex(xIndex);

if (entry == null || entry.getVals() == null)
return old;
if (entry == null)
return null;

if (entry.getVals() == null) {
return new Highlight(xIndex,
entry.getVal(),
selectionDetail.dataIndex,
selectionDetail.dataSetIndex);
}

Range[] ranges = getRanges(entry);
int stackIndex = getClosestStackIndex(ranges, (float) yValue);
if (ranges.length > 0) {
int stackIndex = getClosestStackIndex(ranges, (float)yValue);
return new Highlight(
xIndex,
entry.getPositiveSum() - entry.getNegativeSum(),
selectionDetail.dataIndex,
selectionDetail.dataSetIndex,
stackIndex,
ranges[stackIndex]
);
}

if(ranges.length > 0)
return new Highlight(xIndex, dataSetIndex, stackIndex, ranges[stackIndex]);
else
return null;
return null;
}

/**
Expand Down
Loading

0 comments on commit a002634

Please sign in to comment.