• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 package com.github.mikephil.charting.data;
3 
4 import java.util.ArrayList;
5 import java.util.List;
6 
7 /**
8  * The DataSet class represents one group or type of entries (Entry) in the
9  * Chart that belong together. It is designed to logically separate different
10  * groups of values inside the Chart (e.g. the values for a specific line in the
11  * LineChart, or the values of a specific group of bars in the BarChart).
12  *
13  * @author Philipp Jahoda
14  */
15 public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
16 
17     /**
18      * the entries that this DataSet represents / holds together
19      */
20     protected List<T> mEntries;
21 
22     /**
23      * maximum y-value in the value array
24      */
25     protected float mYMax = -Float.MAX_VALUE;
26 
27     /**
28      * minimum y-value in the value array
29      */
30     protected float mYMin = Float.MAX_VALUE;
31 
32     /**
33      * maximum x-value in the value array
34      */
35     protected float mXMax = -Float.MAX_VALUE;
36 
37     /**
38      * minimum x-value in the value array
39      */
40     protected float mXMin = Float.MAX_VALUE;
41 
42 
43     /**
44      * Creates a new DataSet object with the given values (entries) it represents. Also, a
45      * label that describes the DataSet can be specified. The label can also be
46      * used to retrieve the DataSet from a ChartData object.
47      *
48      * @param entries
49      * @param label
50      */
DataSet(List<T> entries, String label)51     public DataSet(List<T> entries, String label) {
52         super(label);
53         this.mEntries = entries;
54 
55         if (mEntries == null)
56             mEntries = new ArrayList<T>();
57 
58         calcMinMax();
59     }
60 
61     @Override
calcMinMax()62     public void calcMinMax() {
63 
64         mYMax = -Float.MAX_VALUE;
65         mYMin = Float.MAX_VALUE;
66         mXMax = -Float.MAX_VALUE;
67         mXMin = Float.MAX_VALUE;
68 
69         if (mEntries == null || mEntries.isEmpty())
70             return;
71 
72         for (T e : mEntries) {
73             calcMinMax(e);
74         }
75     }
76 
77     @Override
calcMinMaxY(float fromX, float toX)78     public void calcMinMaxY(float fromX, float toX) {
79         mYMax = -Float.MAX_VALUE;
80         mYMin = Float.MAX_VALUE;
81 
82         if (mEntries == null || mEntries.isEmpty())
83             return;
84 
85         int indexFrom = getEntryIndex(fromX, Float.NaN, Rounding.DOWN);
86         int indexTo = getEntryIndex(toX, Float.NaN, Rounding.UP);
87 
88         if (indexTo < indexFrom) return;
89 
90         for (int i = indexFrom; i <= indexTo; i++) {
91 
92             // only recalculate y
93             calcMinMaxY(mEntries.get(i));
94         }
95     }
96 
97     /**
98      * Updates the min and max x and y value of this DataSet based on the given Entry.
99      *
100      * @param e
101      */
calcMinMax(T e)102     protected void calcMinMax(T e) {
103 
104         if (e == null)
105             return;
106 
107         calcMinMaxX(e);
108 
109         calcMinMaxY(e);
110     }
111 
calcMinMaxX(T e)112     protected void calcMinMaxX(T e) {
113 
114         if (e.getX() < mXMin)
115             mXMin = e.getX();
116 
117         if (e.getX() > mXMax)
118             mXMax = e.getX();
119     }
120 
calcMinMaxY(T e)121     protected void calcMinMaxY(T e) {
122 
123         if (e.getY() < mYMin)
124             mYMin = e.getY();
125 
126         if (e.getY() > mYMax)
127             mYMax = e.getY();
128     }
129 
130     @Override
getEntryCount()131     public int getEntryCount() {
132         return mEntries.size();
133     }
134 
135     /**
136      * This method is deprecated.
137      * Use getEntries() instead.
138      *
139      * @return
140      */
141     @Deprecated
getValues()142     public List<T> getValues() {
143         return mEntries;
144     }
145 
146     /**
147      * Returns the array of entries that this DataSet represents.
148      *
149      * @return
150      */
getEntries()151     public List<T> getEntries() {
152         return mEntries;
153     }
154 
155     /**
156      * This method is deprecated.
157      * Use setEntries(...) instead.
158      *
159      * @param values
160      */
161     @Deprecated
setValues(List<T> values)162     public void setValues(List<T> values) {
163         setEntries(values);
164     }
165 
166     /**
167      * Sets the array of entries that this DataSet represents, and calls notifyDataSetChanged()
168      *
169      * @return
170      */
setEntries(List<T> entries)171     public void setEntries(List<T> entries) {
172         mEntries = entries;
173         notifyDataSetChanged();
174     }
175 
176     /**
177      * Provides an exact copy of the DataSet this method is used on.
178      *
179      * @return
180      */
copy()181     public abstract DataSet<T> copy();
182 
183     /**
184      *
185      * @param dataSet
186      */
copy(DataSet dataSet)187     protected void copy(DataSet dataSet) {
188         super.copy(dataSet);
189     }
190 
191     @Override
toString()192     public String toString() {
193         StringBuffer buffer = new StringBuffer();
194         buffer.append(toSimpleString());
195         for (int i = 0; i < mEntries.size(); i++) {
196             buffer.append(mEntries.get(i).toString() + " ");
197         }
198         return buffer.toString();
199     }
200 
201     /**
202      * Returns a simple string representation of the DataSet with the type and
203      * the number of Entries.
204      *
205      * @return
206      */
toSimpleString()207     public String toSimpleString() {
208         StringBuffer buffer = new StringBuffer();
209         buffer.append("DataSet, label: " + (getLabel() == null ? "" : getLabel()) + ", entries: " + mEntries.size() +
210                 "\n");
211         return buffer.toString();
212     }
213 
214     @Override
getYMin()215     public float getYMin() {
216         return mYMin;
217     }
218 
219     @Override
getYMax()220     public float getYMax() {
221         return mYMax;
222     }
223 
224     @Override
getXMin()225     public float getXMin() {
226         return mXMin;
227     }
228 
229     @Override
getXMax()230     public float getXMax() {
231         return mXMax;
232     }
233 
234     @Override
addEntryOrdered(T e)235     public void addEntryOrdered(T e) {
236 
237         if (e == null)
238             return;
239 
240         if (mEntries == null) {
241             mEntries = new ArrayList<T>();
242         }
243 
244         calcMinMax(e);
245 
246         if (mEntries.size() > 0 && mEntries.get(mEntries.size() - 1).getX() > e.getX()) {
247             int closestIndex = getEntryIndex(e.getX(), e.getY(), Rounding.UP);
248             mEntries.add(closestIndex, e);
249         } else {
250             mEntries.add(e);
251         }
252     }
253 
254     @Override
clear()255     public void clear() {
256         mEntries.clear();
257         notifyDataSetChanged();
258     }
259 
260     @Override
addEntry(T e)261     public boolean addEntry(T e) {
262 
263         if (e == null)
264             return false;
265 
266         List<T> values = getEntries();
267         if (values == null) {
268             values = new ArrayList<>();
269         }
270 
271         calcMinMax(e);
272 
273         // add the entry
274         return values.add(e);
275     }
276 
277     @Override
removeEntry(T e)278     public boolean removeEntry(T e) {
279 
280         if (e == null)
281             return false;
282 
283         if (mEntries == null)
284             return false;
285 
286         // remove the entry
287         boolean removed = mEntries.remove(e);
288 
289         if (removed) {
290             calcMinMax();
291         }
292 
293         return removed;
294     }
295 
296     @Override
getEntryIndex(Entry e)297     public int getEntryIndex(Entry e) {
298         return mEntries.indexOf(e);
299     }
300 
301     @Override
getEntryForXValue(float xValue, float closestToY, Rounding rounding)302     public T getEntryForXValue(float xValue, float closestToY, Rounding rounding) {
303 
304         int index = getEntryIndex(xValue, closestToY, rounding);
305         if (index > -1)
306             return mEntries.get(index);
307         return null;
308     }
309 
310     @Override
getEntryForXValue(float xValue, float closestToY)311     public T getEntryForXValue(float xValue, float closestToY) {
312         return getEntryForXValue(xValue, closestToY, Rounding.CLOSEST);
313     }
314 
315     @Override
getEntryForIndex(int index)316     public T getEntryForIndex(int index) {
317         return mEntries.get(index);
318     }
319 
320     @Override
getEntryIndex(float xValue, float closestToY, Rounding rounding)321     public int getEntryIndex(float xValue, float closestToY, Rounding rounding) {
322 
323         if (mEntries == null || mEntries.isEmpty())
324             return -1;
325 
326         int low = 0;
327         int high = mEntries.size() - 1;
328         int closest = high;
329 
330         while (low < high) {
331             int m = (low + high) / 2;
332 
333             final float d1 = mEntries.get(m).getX() - xValue,
334                     d2 = mEntries.get(m + 1).getX() - xValue,
335                     ad1 = Math.abs(d1), ad2 = Math.abs(d2);
336 
337             if (ad2 < ad1) {
338                 // [m + 1] is closer to xValue
339                 // Search in an higher place
340                 low = m + 1;
341             } else if (ad1 < ad2) {
342                 // [m] is closer to xValue
343                 // Search in a lower place
344                 high = m;
345             } else {
346                 // We have multiple sequential x-value with same distance
347 
348                 if (d1 >= 0.0) {
349                     // Search in a lower place
350                     high = m;
351                 } else if (d1 < 0.0) {
352                     // Search in an higher place
353                     low = m + 1;
354                 }
355             }
356 
357             closest = high;
358         }
359 
360         if (closest != -1) {
361             float closestXValue = mEntries.get(closest).getX();
362             if (rounding == Rounding.UP) {
363                 // If rounding up, and found x-value is lower than specified x, and we can go upper...
364                 if (closestXValue < xValue && closest < mEntries.size() - 1) {
365                     ++closest;
366                 }
367             } else if (rounding == Rounding.DOWN) {
368                 // If rounding down, and found x-value is upper than specified x, and we can go lower...
369                 if (closestXValue > xValue && closest > 0) {
370                     --closest;
371                 }
372             }
373 
374             // Search by closest to y-value
375             if (!Float.isNaN(closestToY)) {
376                 while (closest > 0 && mEntries.get(closest - 1).getX() == closestXValue)
377                     closest -= 1;
378 
379                 float closestYValue = mEntries.get(closest).getY();
380                 int closestYIndex = closest;
381 
382                 while (true) {
383                     closest += 1;
384                     if (closest >= mEntries.size())
385                         break;
386 
387                     final Entry value = mEntries.get(closest);
388 
389                     if (value.getX() != closestXValue)
390                         break;
391 
392                     if (Math.abs(value.getY() - closestToY) <= Math.abs(closestYValue - closestToY)) {
393                         closestYValue = closestToY;
394                         closestYIndex = closest;
395                     }
396                 }
397 
398                 closest = closestYIndex;
399             }
400         }
401 
402         return closest;
403     }
404 
405     @Override
getEntriesForXValue(float xValue)406     public List<T> getEntriesForXValue(float xValue) {
407 
408         List<T> entries = new ArrayList<T>();
409 
410         int low = 0;
411         int high = mEntries.size() - 1;
412 
413         while (low <= high) {
414             int m = (high + low) / 2;
415             T entry = mEntries.get(m);
416 
417             // if we have a match
418             if (xValue == entry.getX()) {
419                 while (m > 0 && mEntries.get(m - 1).getX() == xValue)
420                     m--;
421 
422                 high = mEntries.size();
423 
424                 // loop over all "equal" entries
425                 for (; m < high; m++) {
426                     entry = mEntries.get(m);
427                     if (entry.getX() == xValue) {
428                         entries.add(entry);
429                     } else {
430                         break;
431                     }
432                 }
433 
434                 break;
435             } else {
436                 if (xValue > entry.getX())
437                     low = m + 1;
438                 else
439                     high = m - 1;
440             }
441         }
442 
443         return entries;
444     }
445 
446     /**
447      * Determines how to round DataSet index values for
448      * {@link DataSet#getEntryIndex(float, float, Rounding)} DataSet.getEntryIndex()}
449      * when an exact x-index is not found.
450      */
451     public enum Rounding {
452         UP,
453         DOWN,
454         CLOSEST,
455     }
456 }