Home | History | Annotate | Download | only in xy
      1 /*
      2  * Copyright 2012 AndroidPlot.com
      3  *
      4  *    Licensed under the Apache License, Version 2.0 (the "License");
      5  *    you may not use this file except in compliance with the License.
      6  *    You may obtain a copy of the License at
      7  *
      8  *        http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  *    Unless required by applicable law or agreed to in writing, software
     11  *    distributed under the License is distributed on an "AS IS" BASIS,
     12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  *    See the License for the specific language governing permissions and
     14  *    limitations under the License.
     15  */
     16 
     17 package com.androidplot.xy;
     18 
     19 import android.graphics.Canvas;
     20 import android.util.Log;
     21 import android.util.Pair;
     22 import com.androidplot.Plot;
     23 import com.androidplot.PlotListener;
     24 
     25 import java.util.LinkedList;
     26 import java.util.List;
     27 import java.util.NoSuchElementException;
     28 import java.util.concurrent.locks.ReentrantReadWriteLock;
     29 
     30 
     31 /**
     32  * A convenience class used to create instances of XYPlot generated from Lists of Numbers.
     33  */
     34 public class SimpleXYSeries implements XYSeries, PlotListener {
     35 
     36     private static final String TAG = SimpleXYSeries.class.getName();
     37 
     38     @Override
     39     public void onBeforeDraw(Plot source, Canvas canvas) {
     40         lock.readLock().lock();
     41     }
     42 
     43     @Override
     44     public void onAfterDraw(Plot source, Canvas canvas) {
     45         lock.readLock().unlock();
     46     }
     47 
     48     public enum ArrayFormat {
     49         Y_VALS_ONLY,
     50         XY_VALS_INTERLEAVED
     51     }
     52 
     53     private volatile LinkedList<Number> xVals = new LinkedList<Number>();
     54     private volatile LinkedList<Number> yVals = new LinkedList<Number>();
     55     private volatile String title = null;
     56     private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
     57 
     58 
     59     public SimpleXYSeries(String title) {
     60         this.title = title;
     61     }
     62     /**
     63      * Generates an XYSeries instance from the List of numbers passed in.  This is a convenience class
     64      * and should only be used for static data models; it is not suitable for representing dynamically
     65      * changing data.
     66      *
     67      * @param model  A List of Number elements comprising the data model.
     68      * @param format Format of the model.  A format of Y_VALS_ONLY means that the array only contains y-values.
     69      *               For this format x values are autogenerated using values of 0 through n-1 where n is the size of the model.
     70      * @param title  Title of the series
     71      */
     72     public SimpleXYSeries(List<? extends Number> model, ArrayFormat format, String title) {
     73         this(title);
     74         setModel(model, format);
     75     }
     76 
     77     public SimpleXYSeries(List<? extends Number> xVals, List<? extends Number> yVals, String title) {
     78         this(title);
     79         if(xVals == null || yVals == null) {
     80             throw new IllegalArgumentException("Neither the xVals nor the yVals parameters may be null.");
     81         }
     82 
     83         if(xVals.size() != yVals.size()) {
     84             throw new IllegalArgumentException("xVals and yVals List parameters must be of the same size.");
     85         }
     86 
     87         this.xVals.addAll(xVals);
     88         this.yVals.addAll(yVals);
     89     }
     90 
     91     /**
     92      * Use index value as xVal, instead of explicit, user provided xVals.
     93      */
     94     public void useImplicitXVals() {
     95         lock.writeLock().lock();
     96         try {
     97             xVals = null;
     98         } finally {
     99             lock.writeLock().unlock();
    100         }
    101     }
    102 
    103     /**
    104      * Use the provided list of Numbers as yVals and their corresponding indexes as xVals.
    105      * @param model A List of Number elements comprising the data model.
    106      * @param format Format of the model.  A format of Y_VALS_ONLY means that the array only contains y-values.
    107      *               For this format x values are autogenerated using values of 0 through n-1 where n is the size of the model.
    108      */
    109     public void setModel(List<? extends Number> model, ArrayFormat format) {
    110 
    111         lock.writeLock().lock();
    112         try {
    113             // empty the current values:
    114             //xVals.clear();
    115             xVals = null;
    116             yVals.clear();
    117 
    118             // make sure the new model has data:
    119             if (model == null || model.size() == 0) {
    120                 return;
    121             }
    122 
    123             switch (format) {
    124 
    125                 // array containing only y-vals. assume x = index:
    126                 case Y_VALS_ONLY:
    127                     for(Number n : model) {
    128                         yVals.add(n);
    129                     }
    130                     /*for (int i = 0; i < model.size(); i++) {
    131                         //xVals.add(i);
    132                         yVals.add(model.get(i));
    133                     }*/
    134                     break;
    135 
    136                 // xy interleaved array:
    137                 case XY_VALS_INTERLEAVED:
    138                     if (xVals == null) {
    139                         xVals = new LinkedList<Number>();
    140                     }
    141                     if (model.size() % 2 != 0) {
    142                         throw new IndexOutOfBoundsException("Cannot auto-generate series from odd-sized xy List.");
    143                     }
    144                     // always need an x and y array so init them now:
    145                     int sz = model.size() / 2;
    146                     for (int i = 0, j = 0; i < sz; i++, j += 2) {
    147                         xVals.add(model.get(j));
    148                         yVals.add(model.get(j + 1));
    149                     }
    150                     break;
    151                 default:
    152                     throw new IllegalArgumentException("Unexpected enum value: " + format);
    153             }
    154         } finally {
    155             lock.writeLock().unlock();
    156         }
    157     }
    158 
    159     /**
    160      * Sets individual x value based on index
    161      * @param value
    162      * @param index
    163      */
    164     public void setX(Number value, int index) {
    165         lock.writeLock().lock();
    166         try {
    167             xVals.set(index, value);
    168         } finally {
    169             lock.writeLock().unlock();
    170         }
    171     }
    172 
    173     /**
    174      * Sets individual y value based on index
    175      * @param value
    176      * @param index
    177      */
    178     public void setY(Number value, int index) {
    179         lock.writeLock().lock();
    180         try {
    181             yVals.set(index, value);
    182         } finally {
    183             lock.writeLock().unlock();
    184         }
    185     }
    186 
    187     /**
    188      * Sets xy values based on index
    189      * @param xVal
    190      * @param yVal
    191      * @param index
    192      */
    193     public void setXY(Number xVal, Number yVal, int index) {
    194         lock.writeLock().lock();
    195         try {
    196             yVals.set(index, yVal);
    197             xVals.set(index, xVal);
    198         } finally {lock.writeLock().unlock();}
    199     }
    200 
    201     public void addFirst(Number x, Number y) {
    202         lock.writeLock().lock();
    203         try {
    204             if (xVals != null) {
    205                 xVals.addFirst(x);
    206             }
    207             yVals.addFirst(y);
    208         } finally {
    209             lock.writeLock().unlock();
    210         }
    211     }
    212 
    213     /**
    214      *
    215      * @return Pair<Number, Number> with first equal to x-val and second equal to y-val.
    216      */
    217     public Pair<Number, Number> removeFirst() {
    218         lock.writeLock().lock();
    219         try {
    220             if (size() <= 0) {
    221                 throw new NoSuchElementException();
    222             }
    223             return new Pair<Number, Number>(xVals != null ? xVals.removeFirst() : 0, yVals.removeFirst());
    224         } finally {
    225             lock.writeLock().unlock();
    226         }
    227     }
    228 
    229     public void addLast(Number x, Number y) {
    230         lock.writeLock().lock();
    231         try {
    232             if (xVals != null) {
    233                 xVals.addLast(x);
    234             }
    235             yVals.addLast(y);
    236         } finally {
    237             lock.writeLock().unlock();
    238         }
    239     }
    240 
    241     /**
    242      *
    243      * @return Pair<Number, Number> with first equal to x-val and second equal to y-val.
    244      */
    245     public Pair<Number, Number> removeLast() {
    246         lock.writeLock().lock();
    247         try {
    248             if (size() <= 0) {
    249                 throw new NoSuchElementException();
    250             }
    251             return new Pair<Number, Number>(xVals != null ? xVals.removeLast() : yVals.size() - 1, yVals.removeLast());
    252         } finally {
    253             lock.writeLock().unlock();
    254         }
    255     }
    256 
    257     @Override
    258     public String getTitle() {
    259         return title;
    260     }
    261 
    262     public void setTitle(String title) {
    263         lock.writeLock().lock();
    264         try {
    265             this.title = title;
    266         } finally {lock.writeLock().unlock();}
    267     }
    268 
    269     @Override
    270     public int size() {
    271         return yVals != null ? yVals.size() : 0;
    272     }
    273 
    274     @Override
    275     public Number getX(int index) {
    276         return xVals != null ? xVals.get(index) : index;
    277     }
    278 
    279     @Override
    280     public Number getY(int index) {
    281         return yVals.get(index);
    282     }
    283 }
    284