View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.perf.impl.chart;
33  
34  import java.io.Serializable;
35  import java.time.ZoneId;
36  import java.time.format.DateTimeFormatter;
37  import java.util.ArrayList;
38  import java.util.Collections;
39  import java.util.List;
40  import javax.annotation.Nullable;
41  import javax.annotation.concurrent.Immutable;
42  import org.jfree.chart.axis.TickUnits;
43  import org.jfree.data.DomainOrder;
44  import org.jfree.data.general.DatasetChangeListener;
45  import org.jfree.data.general.DatasetGroup;
46  import org.jfree.data.xy.XYZDataset;
47  import org.spf4j.base.Arrays;
48  import org.spf4j.base.ComparablePair;
49  import org.spf4j.perf.impl.Quanta;
50  
51  @Immutable
52  final class QuantizedXYZDatasetImpl implements XYZDataset, Serializable {
53  
54    private static final long serialVersionUID = 1L;
55  
56    private final double[] x;
57    private final double[] y;
58    private final double[] z;
59    private final double minValue;
60    private final double maxValue;
61    private final ArrayList<ComparablePair<Quanta, Integer>> quantas;
62    private final double[][] data;
63    private final long startTimeMillis;
64    private final long stepMillis;
65  
66    QuantizedXYZDatasetImpl(final String[] dataSources, final double[][] pdata,
67            final long startTimeMillis, final long step) {
68      this.data = pdata;
69      this.startTimeMillis = startTimeMillis;
70      this.stepMillis = step;
71      quantas = new ArrayList<>(dataSources.length);
72      for (int i = 0; i < dataSources.length; i++) {
73        String ds = dataSources[i];
74        if (ds.startsWith("Q")) {
75          Quanta quanta = new Quanta(ds);
76          quantas.add(ComparablePair.of(quanta, i));
77        }
78      }
79      Collections.sort(quantas);
80      final int nrQuantas = quantas.size();
81      int seriesSize = nrQuantas * data.length;
82      x = new double[seriesSize];
83      y = new double[seriesSize];
84      z = new double[seriesSize];
85      double lMinValue = Double.POSITIVE_INFINITY;
86      double lMaxValue = Double.NEGATIVE_INFINITY;
87  
88      int k = 0;
89  
90      for (int j = 0; j < nrQuantas; j++) {
91        ComparablePair<Quanta, Integer> pair = quantas.get(j);
92        double[] values = Arrays.getColumn(data, pair.getSecond());
93        for (int i = 0; i < values.length; i++) {
94          x[k] = i; //timestamps[i]*1000;
95          y[k] = j; //(double) pair.getFirst().getClosestToZero();
96          double zval = values[i];
97          z[k] = zval;
98          if (zval > lMaxValue) {
99            lMaxValue = zval;
100         }
101         if (zval < lMinValue) {
102           lMinValue = zval;
103         }
104         k++;
105       }
106     }
107     this.minValue = lMinValue;
108     this.maxValue = lMaxValue;
109 
110   }
111 
112   @Override
113   public Number getZ(final int series, final int item) {
114     return z[item];
115   }
116 
117   @Override
118   public double getZValue(final int series, final int item) {
119     return z[item];
120   }
121 
122   @Override
123   public DomainOrder getDomainOrder() {
124     return DomainOrder.ASCENDING;
125   }
126 
127   @Override
128   public int getItemCount(final int series) {
129     return x.length;
130   }
131 
132   @Override
133   public Number getX(final int series, final int item) {
134     return x[item];
135   }
136 
137   @Override
138   public double getXValue(final int series, final int item) {
139     return x[item];
140   }
141 
142   @Override
143   public Number getY(final int series, final int item) {
144     return y[item];
145   }
146 
147   @Override
148   public double getYValue(final int series, final int item) {
149     return y[item];
150   }
151 
152   @Override
153   public int getSeriesCount() {
154     return 1;
155   }
156 
157   @Override
158   public Comparable getSeriesKey(final int series) {
159     return "RrdXYZDataset";
160   }
161 
162   @Override
163   public int indexOf(final Comparable seriesKey) {
164     return 0;
165   }
166 
167   @Override
168   public void addChangeListener(final DatasetChangeListener listener) {
169     // nothing
170   }
171 
172   @Override
173   public void removeChangeListener(final DatasetChangeListener listener) {
174     // nothing
175   }
176 
177   @Override
178   @Nullable
179   public DatasetGroup getGroup() {
180     return null;
181   }
182 
183   @Override
184   public void setGroup(final DatasetGroup group) {
185     // nothing
186   }
187 
188   public double getMaxValue() {
189     return maxValue;
190   }
191 
192   public double getMinValue() {
193     return minValue;
194   }
195 
196   public List<ComparablePair<Quanta, Integer>> getQuantas() {
197     return Collections.unmodifiableList(quantas);
198   }
199 
200   public TickUnits createXTickUnits() {
201     TickUnits tux = new TickUnits();
202     if (data.length == 0) {
203       return tux;
204     }
205     ZoneId systemDefault = ZoneId.systemDefault();
206     final DateTimeFormatter formatter = DateTimeFormatter
207           .ofPattern("yyyyMMdd'T'HH:mm:ss").withZone(systemDefault);
208     final DateTimeFormatter shortFormat = DateTimeFormatter
209           .ofPattern("yyyyMMdd'T'HH").withZone(systemDefault);
210     final DateTimeFormatter mediumFormat = DateTimeFormatter
211           .ofPattern("yyyyMMdd'T'HH:mm").withZone(systemDefault);
212     final long[] timestamps = new long[data[0].length];
213     long time = startTimeMillis;
214     for (int i = 0; i < timestamps.length; i++) {
215       timestamps[i] = time;
216       time += stepMillis;
217     }
218     tux.add(new TimestampTickUnitImpl(1, timestamps, stepMillis, formatter)); // base
219     long nr = 5000L / stepMillis;
220     if (nr > 1) {
221       tux.add(new TimestampTickUnitImpl(nr, timestamps, stepMillis, formatter));
222     }
223 
224     nr = 15000L / stepMillis;
225     if (nr > 1) {
226       tux.add(new TimestampTickUnitImpl(nr, timestamps, stepMillis, formatter));
227     }
228     // minute
229     nr = 60000L / stepMillis;
230     if (nr > 1) {
231       tux.add(new TimestampTickUnitImpl(nr, timestamps, stepMillis, mediumFormat));
232     }
233     // 15 minute
234     nr = 900000L / stepMillis;
235     if (nr > 1) {
236       tux.add(new TimestampTickUnitImpl(nr, timestamps, stepMillis, mediumFormat));
237     }
238     // hour
239     nr = 3600000L / stepMillis;
240     if (nr > 1) {
241       tux.add(new TimestampTickUnitImpl(nr, timestamps, stepMillis, shortFormat));
242     }
243     // 6 hour
244     nr = 21600000L / stepMillis;
245     if (nr > 1) {
246       tux.add(new TimestampTickUnitImpl(nr, timestamps, stepMillis, shortFormat));
247     }
248 
249     return tux;
250   }
251 
252   public TickUnits createYTickUnits() {
253     TickUnits tu = new TickUnits();
254     final List<ComparablePair<Quanta, Integer>> lquantas = this.getQuantas();
255     tu.add(new QuantizedNumberTickUnit(1, lquantas));
256     return tu;
257   }
258 
259   @Override
260   public String toString() {
261     return "QuantizedXYZDatasetImpl{" + "x=" + java.util.Arrays.toString(x)
262             + ", y=" + java.util.Arrays.toString(y) + ", z=" + java.util.Arrays.toString(z)
263             + ", minValue=" + minValue + ", maxValue=" + maxValue + ", quantas=" + quantas
264             + ", data=" + java.util.Arrays.toString(data)
265             + ", startTimeMillis=" + startTimeMillis + ", stepMillis=" + stepMillis + '}';
266   }
267 
268 }