source: ether_megapoli/trunk/service/implementation/com/ether/EtherPlotContentServiceImpl.java @ 190

Last change on this file since 190 was 190, checked in by vmipsl, 13 years ago

Servlet _ TimeSerie? :

  • 1 paramètre ok
  • même paramètre sur différentes plateformes ok
  • plusieurs paramètres sur même ou différentes plateformes ok
File size: 19.7 KB
Line 
1package com.ether;
2
3import com.medias.database.objects.Parametre;
4import com.medias.database.objects.Plateforme;
5import gov.noaa.pmel.sgt.Axis;
6import gov.noaa.pmel.sgt.CartesianGraph;
7import gov.noaa.pmel.sgt.Graph;
8import gov.noaa.pmel.sgt.JPane;
9import gov.noaa.pmel.sgt.Layer;
10import gov.noaa.pmel.sgt.LineAttribute;
11import gov.noaa.pmel.sgt.LineCartesianRenderer;
12import gov.noaa.pmel.sgt.LineKey;
13import gov.noaa.pmel.sgt.LinearTransform;
14import gov.noaa.pmel.sgt.PlainAxis;
15import gov.noaa.pmel.sgt.SGLabel;
16import gov.noaa.pmel.sgt.StackedLayout;
17import gov.noaa.pmel.sgt.TimeAxis;
18import gov.noaa.pmel.sgt.dm.SGTMetaData;
19import gov.noaa.pmel.sgt.dm.SimpleLine;
20import gov.noaa.pmel.util.Dimension2D;
21import gov.noaa.pmel.util.GeoDateArray;
22import gov.noaa.pmel.util.Point2D;
23import gov.noaa.pmel.util.Range2D;
24import gov.noaa.pmel.util.SoTPoint;
25import gov.noaa.pmel.util.SoTRange;
26import org.jetbrains.annotations.NotNull;
27import org.jetbrains.annotations.Nullable;
28import org.springframework.beans.factory.annotation.Required;
29
30import java.awt.*;
31import java.util.ArrayList;
32import java.util.Date;
33import java.util.List;
34import java.util.Locale;
35import java.util.Random;
36import java.util.ResourceBundle;
37
38/**
39 * @author vmipsl
40 * @date 05 sept. 2011
41 */
42public class EtherPlotContentServiceImpl
43{
44    /**
45     * First layer contains axes, labels and the first set of data
46     * Others layers contains only the other sets of data
47     *
48     * @param megapoliPlot
49     * @param locale
50     * @return
51     */
52    @Nullable
53    public JPane createTimeSeriePlot( @NotNull final MegapoliPlot megapoliPlot, @NotNull final Integer plotWidth, @NotNull final Integer plotHeight, final Locale locale )
54            throws ServiceException
55    {
56        final JPane mainPane = new JPane( "Time Serie Pane", new Dimension( plotWidth, plotHeight ) );
57        mainPane.setLayout( new StackedLayout() );
58
59        // TODO : revoir les tailles ! mettre en automatique par rapport à plotWidth et plotHeight
60        /*
61        * xsize, ysize are the width and height in physical units
62        * of the Layer graphics region.
63        *
64        * xstart, xend are the start and end points for the TimeAxis
65        * ystart, yend are the start and end points for the Y axis
66        */
67        final double xsize = 5.0;
68        final double ysize = 3.5;
69        final double xstart = 0.3;
70        final double xend = xsize - xstart;
71        final double ystart = 0.5;
72        final double yend = ysize - ystart;
73
74        final Layer layer = new Layer( "First Layer", new Dimension2D( xsize, ysize ) );
75        mainPane.add( layer );
76
77        final Pair<List, List> listPairOfPIdPIdForTwoAxes = extractListPairForAxes( megapoliPlot.getpIdPIdList() );
78        final List<Pair> pIdPIdListForFirstAxis = listPairOfPIdPIdForTwoAxes.getFirstValue();
79        final List<Pair> pIdPIdListForSecondAxis = listPairOfPIdPIdForTwoAxes.getSecondValue();
80
81        final List<SimpleLine> allLines = createLines( pIdPIdListForFirstAxis, megapoliPlot.getBeginDate(), megapoliPlot.getEndDate(), null, locale );
82        final List<SimpleLine> allLinesForSecondAxis = createLines( pIdPIdListForSecondAxis, megapoliPlot.getBeginDate(), megapoliPlot.getEndDate(), 10, locale );
83        List<SimpleLine> lines = extractRealLines( allLines );
84        List<SimpleLine> linesForSecondAxis = extractRealLines( allLinesForSecondAxis );
85
86        final List<SimpleLine> emptyLineToDisplayOnlyInLegend = createEmptyLinesList( allLines, allLinesForSecondAxis, lines );
87        if( lines.isEmpty() )
88        {
89            if( linesForSecondAxis.isEmpty() )
90                return null;
91            else
92            {
93                lines = linesForSecondAxis;
94                linesForSecondAxis = new ArrayList<SimpleLine>();
95            }
96        }
97
98        final SimpleLine firstLine = lines.get( 0 );
99
100        /** ********** AXIS RANGES ********* **/
101        final SoTRange xnRange = firstLine.getXRange();
102        final SoTRange yRange = firstLine.getYRange();
103        for( final SimpleLine line : lines )
104        {
105            yRange.add( line.getYRange() );
106            xnRange.add( line.getXRange() );
107        }
108
109        for( final SimpleLine line : linesForSecondAxis )
110            xnRange.add( line.getXRange() );
111
112        final SoTRange ynRange = Graph.computeRange( yRange, _intervalsNumber );
113
114        // Origin point
115        final SoTPoint originPoint = new SoTPoint( ynRange.getStart(), xnRange.getStart() );
116
117
118        /** ************ AXIS ********** **/
119        // Time axis is the same for the two y-axis
120        final TimeAxis xTimeAxis = createXTimeAxis( xnRange, originPoint );
121        final PlainAxis yLeftAxis = createYAxis( firstLine, ynRange, originPoint, null );
122
123        /** ************ GRAPH ********** **/
124        final CartesianGraph graph = new CartesianGraph( "First Graph" );
125        layer.setGraph( graph );
126
127        final LinearTransform xt = new LinearTransform( new Range2D( xstart, xend ), xnRange );
128        graph.setXTransform( xt );
129        final LinearTransform yt = new LinearTransform( new Range2D( ystart, yend ), ynRange );
130        graph.setYTransform( yt );
131
132        graph.addXAxis( xTimeAxis );
133        graph.addYAxis( yLeftAxis );
134
135        final LineAttribute lineAttribute = createRandomLineAttribute( megapoliPlot.getAxeType() );
136        graph.setData( firstLine, lineAttribute );
137
138        /** *********** LEGEND ********* **/
139        final LineKey lkey = createLineKey( megapoliPlot, ysize, layer, firstLine, graph );
140
141        /** *********** OTHER LAYERS ********* **/
142        // First axis
143        addOtherLinesForOneAxis( megapoliPlot.getAxeType(), mainPane, xsize, ysize, lines, xt, yt, lkey, 1 );
144
145        // Second axis
146        if( !linesForSecondAxis.isEmpty() )
147        {
148            final SimpleLine firstLineForSecondAxis = linesForSecondAxis.get( 0 );
149
150            final SoTRange yRangeForSecondAxis = firstLineForSecondAxis.getYRange();
151            for( final SimpleLine line : linesForSecondAxis )
152                yRangeForSecondAxis.add( line.getYRange() );
153
154            final SoTRange ynRangeForSecondAxis = Graph.computeRange( yRangeForSecondAxis, _intervalsNumber );
155            final SoTPoint endPointForSecondAxis = new SoTPoint( ynRangeForSecondAxis.getStart(), xnRange.getEnd() );
156
157            final PlainAxis yRightAxis = createYAxis( firstLineForSecondAxis, ynRangeForSecondAxis, endPointForSecondAxis, Axis.POSITIVE_SIDE );
158
159            final LinearTransform ytForSecondAxis = new LinearTransform( new Range2D( ystart, yend ), ynRangeForSecondAxis );
160
161            // It transforms the graph with the maximum yAxis
162            if( ytForSecondAxis.getRangeU().end > yt.getRangeU().end )
163                graph.setYTransform( ytForSecondAxis );
164            graph.addYAxis( yRightAxis );
165
166            addOtherLinesForOneAxis( megapoliPlot.getAxeType(), mainPane, xsize, ysize, linesForSecondAxis, xt, ytForSecondAxis, lkey, 0 );
167        }
168        displayLegendForEmptyLines( emptyLineToDisplayOnlyInLegend, lkey, mainPane, xsize, ysize, xt, yt, megapoliPlot.getAxeType() );
169
170        return mainPane;
171    }
172
173    private List<SimpleLine> createEmptyLinesList( final List<SimpleLine> allLines, final List<SimpleLine> allLinesForSecondAxis, final List<SimpleLine> lines )
174    {
175        final List<SimpleLine> emptyLinesList = allLines;
176        emptyLinesList.removeAll( lines );
177        emptyLinesList.addAll( allLinesForSecondAxis );
178        emptyLinesList.removeAll( allLinesForSecondAxis );
179
180        return emptyLinesList;
181    }
182
183    private void displayLegendForEmptyLines( @NotNull final List<SimpleLine> lines, @NotNull final LineKey lkey, @NotNull final JPane mainPane, final double xsize, final double ysize, final LinearTransform xt, final LinearTransform yt, final String axeType )
184    {
185        for( final SimpleLine line : lines )
186        {
187            final Layer otherLayer = new Layer( "Other Layer", new Dimension2D( xsize, ysize ) );
188            mainPane.add( otherLayer );
189            final CartesianGraph otherGraph = new CartesianGraph( "Other Graph", xt, yt );
190            otherLayer.setGraph( otherGraph );
191
192            final LineAttribute otherLineAttribute = createRandomLineAttribute( axeType );
193            otherGraph.setData( line, otherLineAttribute );
194            lkey.addLineGraph( (LineCartesianRenderer) otherGraph.getRenderer(), line.getKeyTitle() );
195        }
196    }
197
198    /**
199     * This method removes from a list the lines with no data
200     *
201     * @param allLines
202     * @return
203     */
204    @NotNull
205    private List<SimpleLine> extractRealLines( @NotNull final List<SimpleLine> allLines )
206    {
207        final List<SimpleLine> lines = new ArrayList<SimpleLine>();
208        for( final SimpleLine line : allLines )
209            if( 0 < line.getYArray().length )
210                lines.add( line );
211
212        return lines;
213    }
214
215    @NotNull
216    public JPane create2DPlot( @NotNull final MegapoliPlot megapoliPlot, @NotNull final Integer plotWidth, @NotNull final Integer plotHeight, @Nullable final Locale locale )
217    {
218        final JPane mainPane = new JPane( "2D Pane", new Dimension( plotWidth, plotHeight ) );
219
220        final ResourceBundle bundle = WebHelper.getBundle( locale );
221
222        final Data realValuesFor2D = BouchonHelper.createRealValuesFor2D();
223//        final double[] parameterValues = (double[]) megapoliPlot.getData().getFirstArray();
224//        final double[] latitudeValues = (double[]) megapoliPlot.getData().getSecondArray();
225//        final double[] longitudeValues = (double[]) megapoliPlot.getData().getThirdArray();
226
227        final double[] parameterValues = (double[]) realValuesFor2D.getFirstArray();
228        final double[] latitudeValues = (double[]) realValuesFor2D.getSecondArray();
229        final double[] longitudeValues = (double[]) realValuesFor2D.getThirdArray();
230
231        return mainPane;
232    }
233
234    @NotNull
235    protected String formatTitle( @Nullable final String title )
236    {
237        if( null == title )
238            return "";
239        else
240        {
241            final String formatTitle = title.replaceAll( "\\n", "<br>" );
242            return "<html>" + formatTitle + "</html>";
243        }
244    }
245
246    /**
247     * This method creates a legend
248     *
249     * @param megapoliPlot
250     * @param ysize
251     * @param layer
252     * @param firstLine
253     * @param graph
254     * @return
255     */
256    @NotNull
257    private LineKey createLineKey( final MegapoliPlot megapoliPlot, final double ysize, final Layer layer, final SimpleLine firstLine, final CartesianGraph graph )
258    {
259        final LineKey lkey = new LineKey();
260        if( !megapoliPlot.isLegendToHide() )
261        {
262            lkey.setId( "Legend" );
263            lkey.setLocationP( new Point2D.Double( 0.1, ysize - 0.1 ) );
264            lkey.setBorderStyle( LineKey.NO_BORDER );
265            lkey.setVAlign( LineKey.TOP );
266            lkey.setHAlign( LineKey.LEFT );
267            layer.addChild( lkey );
268            lkey.addLineGraph( (LineCartesianRenderer) graph.getRenderer(), firstLine.getKeyTitle() );
269        }
270        return lkey;
271    }
272
273    /**
274     * This method creates a x-axis for time serie
275     *
276     * @param xnRange
277     * @param originPoint
278     * @return
279     */
280    @NotNull
281    private TimeAxis createXTimeAxis( final SoTRange xnRange, final SoTPoint originPoint )
282    {
283        final TimeAxis xbot = new TimeAxis( "X-Axis", TimeAxis.AUTO );
284        xbot.setRangeU( xnRange );
285        xbot.setLocationU( originPoint );
286        xbot.setLabelFont( _axisFont );
287        xbot.setLabelHeightP( _heightAxisFont );
288        xbot.setMajorLabelFormat( _majorLabelFormat );
289        return xbot;
290    }
291
292    /**
293     * This method adds layers corresponding to the other lines to display
294     *
295     * @param axeType
296     * @param mainPane
297     * @param xsize
298     * @param ysize
299     * @param lines
300     * @param xt
301     * @param yt
302     * @param lkey
303     * @param indexLineToBegin
304     */
305    private void addOtherLinesForOneAxis( @NotNull final String axeType, @NotNull final JPane mainPane, final double xsize, final double ysize, @NotNull final List<SimpleLine> lines, @NotNull final LinearTransform xt, @NotNull final LinearTransform yt, @NotNull final LineKey lkey, @NotNull final Integer indexLineToBegin )
306    {
307        for( final SimpleLine line : lines.subList( indexLineToBegin, lines.size() ) )
308        {
309            final Layer otherLayer = new Layer( "Other Layer", new Dimension2D( xsize, ysize ) );
310            mainPane.add( otherLayer );
311            final CartesianGraph otherGraph = new CartesianGraph( "Other Graph", xt, yt );
312            otherLayer.setGraph( otherGraph );
313
314            final LineAttribute otherLineAttribute = createRandomLineAttribute( axeType );
315            otherGraph.setData( line, otherLineAttribute );
316            lkey.addLineGraph( (LineCartesianRenderer) otherGraph.getRenderer(), line.getKeyTitle() );
317        }
318    }
319
320    /**
321     * This method creates a vertical axis, set its range in user units and its origin and creates the axis title
322     *
323     * @param line
324     * @param ynRange
325     * @param originPoint
326     * @param labelPosition
327     * @return
328     */
329    @NotNull
330    private PlainAxis createYAxis( final SimpleLine line, final SoTRange ynRange, final SoTPoint originPoint, @Nullable final Integer labelPosition )
331    {
332        final PlainAxis yAxis = new PlainAxis( "Y-Axis" );
333        yAxis.setRangeU( ynRange );
334        yAxis.setLocationU( originPoint );
335        yAxis.setLabelFont( _axisFont );
336        if( null != labelPosition )
337            yAxis.setLabelPosition( labelPosition );
338
339        final String yLabel = line.getYMetaData().getName() + " (" + line.getYMetaData().getUnits() + ")";
340        final SGLabel ytitle = new SGLabel( "Y-Axis Title", yLabel, new Point2D.Double( 0.0, 0.0 ) );
341        ytitle.setFont( _axisFont );
342        ytitle.setHeightP( _heightAxisFont );
343        yAxis.setTitle( ytitle );
344        return yAxis;
345    }
346
347    /**
348     * This method returns a new LineAttribute with a random color
349     *
350     * @param axeType
351     * @return
352     */
353    @NotNull
354    private LineAttribute createRandomLineAttribute( @NotNull final String axeType )
355    {
356        final LineAttribute attr;
357        final Color color = new Color( new Random().nextInt( 256 ), new Random().nextInt( 256 ), new Random().nextInt( 256 ) );
358
359        if( axeType.equals( AxeTypeForFixedPlateform.TIME_POINTS.toString() ) )
360            attr = new LineAttribute( LineAttribute.MARK, 1, color );
361        else
362            attr = new LineAttribute( LineAttribute.SOLID, 1, color );
363
364        attr.setMarkHeightP( _markHeight );
365
366        return attr;
367    }
368
369    /**
370     * This method extracts from a list of <plateformId, parameterId> two lists of <plateformId, parameterId> corresponding for the 2 axes needed for the graph
371     * The second list can be empty, in this case, only one axis is needed
372     *
373     * @param pIdPIdList
374     * @return
375     */
376    @NotNull
377    private Pair<List, List> extractListPairForAxes( @NotNull final List<Pair> pIdPIdList )
378    {
379        final List<Pair<Integer, Integer>> pIdPIdListForFirstAxis = new ArrayList<Pair<Integer, Integer>>();
380        final List<Pair<Integer, Integer>> pIdPIdListForSecondAxis = new ArrayList<Pair<Integer, Integer>>();
381
382        for( final Pair pIdPId : pIdPIdList )
383        {
384            final List<Integer> secondValuesForFirstAxis = EtherHelper.getSecondValues( pIdPIdListForFirstAxis );
385            final Integer parameterId = (Integer) pIdPId.getSecondValue();
386
387            if( pIdPIdListForFirstAxis.isEmpty() || secondValuesForFirstAxis.contains( parameterId ) )
388                pIdPIdListForFirstAxis.add( pIdPId );
389            else
390                pIdPIdListForSecondAxis.add( pIdPId );
391        }
392
393        return new Pair( pIdPIdListForFirstAxis, pIdPIdListForSecondAxis );
394    }
395
396    /**
397     * This method extracts data from BD for the plateform and parameter given as parameters
398     * and creates the corresponded simpleLine
399     * Some lines can be empty if there's no data in this period by example
400     *
401     * @param pIdPIdList
402     * @param beginDate
403     * @param endDate
404     * @param locale
405     * @return
406     * @throws ServiceException
407     */
408    @NotNull
409    private List<SimpleLine> createLines( @NotNull final List<Pair> pIdPIdList, @Nullable final Date beginDate, @Nullable final Date endDate, final Integer delta, final Locale locale )
410            throws ServiceException
411    {
412        final ResourceBundle bundle = WebHelper.getBundle( locale );
413        final String messageData = bundle.getString( "plot.noData" );
414
415        final List<SimpleLine> lines = new ArrayList<SimpleLine>( pIdPIdList.size() );
416        boolean isFirstLine = true;
417
418        for( final Pair<Integer, Integer> pIdPId : pIdPIdList )
419        {
420            final Integer plateformId = pIdPId.getFirstValue();
421            final Integer parameterId = pIdPId.getSecondValue();
422
423//            final Plateforme plateform = _etherService.getPlateformById( plateformId );
424            final Plateforme plateform = BouchonHelper.getPlateformById( plateformId );
425            if( null == plateform )
426                throw new ServiceException( ServiceException.ServiceCode.PLATEFORM_IS_NULL, new Throwable( ServiceException.ServiceCode.PLATEFORM_IS_NULL.toString() ) );
427
428//            final Parametre parametre = _etherService.getParameterById( parameterId );
429            final Parametre parametre = BouchonHelper.getParameterById( parameterId );
430            if( null == parametre )
431                throw new ServiceException( ServiceException.ServiceCode.PARAMETER_IS_NULL, new Throwable( ServiceException.ServiceCode.PARAMETER_IS_NULL.toString() ) );
432
433//            final Data valuesLists = _etherService.getListsByPlateformByParameterByPeriodForTimeSerie( plateformId, parameterId, beginDate, endDate );
434            final Data valuesLists = BouchonHelper.createValuesForTimeSerie( 50, delta );
435
436            final double[] dataArray = (double[]) valuesLists.getFirstArray();
437            final Date[] dateValues = (Date[]) valuesLists.getSecondArray();
438
439            final SimpleLine line = new SimpleLine( new GeoDateArray( dateValues ), dataArray, "legend" );
440            SGTMetaData meta = new SGTMetaData( "", "", false, false );
441            line.setXMetaData( meta );
442            final SGLabel sgLabel;
443            if( 0 < dataArray.length && 0 < dateValues.length )
444                sgLabel = new SGLabel( "Line", plateform.getPlateformeNom() + "-" + parametre.getParametreNom(), new Point2D.Double( 0.0, 0.0 ) );
445            else
446                sgLabel = new SGLabel( "Line", plateform.getPlateformeNom() + "-" + parametre.getParametreNom() + " " + messageData, new Point2D.Double( 0.0, 0.0 ) );
447            line.setKeyTitle( sgLabel );
448
449            if( isFirstLine )
450                meta = new SGTMetaData( parametre.getParametreNom(), parametre.getUnite().getUniteCode(), false, false );
451            else
452                meta = new SGTMetaData( "", "", false, false );
453            line.setYMetaData( meta );
454
455            lines.add( line );
456            isFirstLine = false;
457        }
458        return lines;
459    }
460
461
462    public EtherService getEtherService()
463    {
464        return _etherService;
465    }
466
467    @Required
468    public void setEtherService( final EtherService etherService )
469    {
470        _etherService = etherService;
471    }
472
473    // Dimensions of the jPanes
474    protected static final int MAX_WIDTH = 800;
475    protected static final int MAX_HEIGHT = 700;
476    protected static final int MARGIN_LEFT_RIGHT = 50;
477
478    protected static final int TITLE_FONT_SIZE = 20;
479    protected static final int FONT_SIZE = 12;
480    protected static final int ERROR_FONT_SIZE = 10;
481
482    protected static final Font _axisFont = new Font( "Helvetica", Font.PLAIN, 15 );
483    protected static final double _heightAxisFont = 0.14;
484    protected static final double _markHeight = 0.1;
485    protected static final String _majorLabelFormat = "yyyy-MM-dd HH:mm";
486    // Number of intervals on a Y-Axis
487    protected Integer _intervalsNumber = 10;
488
489    private EtherService _etherService;
490}
Note: See TracBrowser for help on using the repository browser.