001/* Plot sequences.
002
003 @Copyright (c) 1998-2014 The Regents of the University of California.
004 All rights reserved.
005
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the
009 above copyright notice and the following two paragraphs appear in all
010 copies of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION 2
026 COPYRIGHTENDKEY
027 */
028package ptolemy.actor.lib.gui;
029
030import ptolemy.actor.TypedIOPort;
031import ptolemy.actor.lib.SequenceActor;
032import ptolemy.data.DoubleToken;
033import ptolemy.data.IntToken;
034import ptolemy.data.expr.Parameter;
035import ptolemy.data.type.BaseType;
036import ptolemy.kernel.CompositeEntity;
037import ptolemy.kernel.util.Attribute;
038import ptolemy.kernel.util.IllegalActionException;
039import ptolemy.kernel.util.NameDuplicationException;
040import ptolemy.plot.PlotInterface;
041
042///////////////////////////////////////////////////////////////////
043//// SequencePlotter
044
045/**
046 A sequence plotter.  This plotter contains an instance of the Plot
047 class from the Ptolemy plot package as a public member. Data at
048 the input, which can consist of any number of channels, are plotted
049 on this instance.  Each channel is plotted as a separate data set.
050 The horizontal axis represents the count of the iterations, scaled
051 by the <i>xUnit</i> parameter.  The horizontal increment between
052 samples is given by the <i>xUnit</i> parameter.
053 Its default value is 1.0. The horizontal value
054 of the first sample is given by the <i>xInit</i> parameter.
055 Its default value is 0.0. The input is of type DoubleToken.
056
057 @author  Edward A. Lee, Bart Kienhuis
058 @version $Id$
059 @since Ptolemy II 1.0
060 @Pt.ProposedRating Green (eal)
061 @Pt.AcceptedRating Green (cxh)
062 */
063public class SequencePlotter extends Plotter implements SequenceActor {
064    /** Construct an actor with the given container and name.
065     *  @param container The container.
066     *  @param name The name of this actor.
067     *  @exception IllegalActionException If the actor cannot be contained
068     *   by the proposed container.
069     *  @exception NameDuplicationException If the container already has an
070     *   actor with this name.
071     */
072    public SequencePlotter(CompositeEntity container, String name)
073            throws IllegalActionException, NameDuplicationException {
074        super(container, name);
075
076        // Create the input port and make it a multiport.
077        input = new TypedIOPort(this, "input", true, false);
078        input.setMultiport(true);
079        input.setTypeEquals(BaseType.DOUBLE);
080
081        // set the parameters
082        xInit = new Parameter(this, "xInit", new DoubleToken(0.0));
083        xInit.setTypeEquals(BaseType.DOUBLE);
084        xUnit = new Parameter(this, "xUnit", new DoubleToken(1.0));
085        xUnit.setTypeEquals(BaseType.DOUBLE);
086
087        // Initialize the parameters.
088        // We used to call attributeChanged() here, but FindBugs
089        // reports "Uninitialized read of field method called from constructor of superclass"
090        // in derived classes.
091        _xInit = ((DoubleToken) xInit.getToken()).doubleValue();
092        _xUnit = ((DoubleToken) xUnit.getToken()).doubleValue();
093    }
094
095    ///////////////////////////////////////////////////////////////////
096    ////                     ports and parameters                  ////
097
098    /** Input port, which has type DoubleToken. */
099    public TypedIOPort input;
100
101    /** The increment of the X axis. */
102    public Parameter xUnit;
103
104    /** The start point of the X axis. */
105    public Parameter xInit;
106
107    ///////////////////////////////////////////////////////////////////
108    ////                         public methods                    ////
109
110    /** Notification that an attribute has changed.
111     *  @param attribute The attribute that changed.
112     *  @exception IllegalActionException If the expression of the
113     *   attribute cannot be parsed or cannot be evaluated.
114     */
115    @Override
116    public void attributeChanged(Attribute attribute)
117            throws IllegalActionException {
118        if (attribute == xInit) {
119            _xInit = ((DoubleToken) xInit.getToken()).doubleValue();
120        } else {
121            if (attribute == xUnit) {
122                _xUnit = ((DoubleToken) xUnit.getToken()).doubleValue();
123            } else {
124                super.attributeChanged(attribute);
125            }
126        }
127    }
128
129    /** Reset the x axis counter, and call the base class.
130     *  Also, clear the datasets that this actor will use.
131     *  @exception IllegalActionException If the parent class throws it.
132     */
133    @Override
134    public void initialize() throws IllegalActionException {
135        super.initialize();
136        _xValue = _xInit;
137
138        int width = input.getWidth();
139        _connected = new boolean[width];
140        for (int i = 0; i < width; i++) {
141            _connected[i] = true;
142        }
143    }
144
145    /** Read at most one token from each input channel and plot it as
146     *  a function of the iteration number, scaled by <i>xUnit</i>.
147     *  The first point is plotted at the horizontal position given by
148     *  <i>xInit</i>. The increments on the position are given by
149     *  <i>xUnit</i>. The input data are plotted in postfire() to
150     *  ensure that the data have settled.
151     *  @exception IllegalActionException If there is no director,
152     *   or if the base class throws it.
153     *  @return True if it is OK to continue.
154     */
155    @Override
156    public boolean postfire() throws IllegalActionException {
157        int width = input.getWidth();
158        int offset = ((IntToken) startingDataset.getToken()).intValue();
159
160        for (int i = width - 1; i >= 0; i--) {
161            if (input.hasToken(i)) {
162                DoubleToken curToken = (DoubleToken) input.get(i);
163                if (curToken.isNil()) {
164                    _connected[i] = false;
165                } else {
166                    double curValue = curToken.doubleValue();
167
168                    // NOTE: We assume the superclass ensures this
169                    // cast is safe.
170
171                    ((PlotInterface) plot).addPoint(i + offset, _xValue,
172                            curValue, _connected[i]);
173                    _connected[i] = true;
174                }
175            }
176        }
177
178        _xValue += _xUnit;
179        return super.postfire();
180    }
181
182    ///////////////////////////////////////////////////////////////////
183    ////                         protected members                 ////
184
185    /** X axis counter. */
186    protected double _xValue;
187
188    /** Start of the X axis counter. */
189    protected double _xInit;
190
191    /** Increment of the X axis counter. */
192    protected double _xUnit;
193
194    ///////////////////////////////////////////////////////////////////
195    ////                         private members                   ////
196
197    /** An array of booleans, where if an element is true, then the
198     *  next point that is plotted for that channel will be connected.
199     *  If a channel receives a nil token, then the value for the
200     *  corresponding element will be false, meaning the next point will
201     *  not be connected to the previous point.
202     */
203    boolean[] _connected;
204}