Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : :
20 : : #include "StatisticsHelper.hxx"
21 : : #include "DataSeriesHelper.hxx"
22 : : #include "ErrorBar.hxx"
23 : : #include "macros.hxx"
24 : :
25 : : #include <rtl/math.hxx>
26 : : #include <rtl/ustrbuf.hxx>
27 : : #include <comphelper/processfactory.hxx>
28 : :
29 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 : : #include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
31 : : #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
32 : : #include <com/sun/star/chart2/data/XDataSink.hpp>
33 : : #include <com/sun/star/chart/ErrorBarStyle.hpp>
34 : :
35 : : using ::com::sun::star::uno::Sequence;
36 : : using ::com::sun::star::uno::Reference;
37 : : using ::rtl::OUString;
38 : : using ::rtl::OUStringBuffer;
39 : : using namespace ::com::sun::star;
40 : :
41 : : namespace
42 : : {
43 : :
44 : 0 : double lcl_getVariance( const Sequence< double > & rData, sal_Int32 & rOutValidCount,
45 : : bool bUnbiasedEstimator )
46 : : {
47 : 0 : const sal_Int32 nCount = rData.getLength();
48 : 0 : rOutValidCount = nCount;
49 : :
50 : 0 : double fSum = 0.0;
51 : 0 : double fQuadSum = 0.0;
52 : :
53 [ # # ]: 0 : for( sal_Int32 i = 0; i < nCount; ++i )
54 : : {
55 : 0 : const double fData = rData[i];
56 [ # # ]: 0 : if( ::rtl::math::isNan( fData ))
57 : 0 : --rOutValidCount;
58 : : else
59 : : {
60 : 0 : fSum += fData;
61 : 0 : fQuadSum += fData * fData;
62 : : }
63 : : }
64 : :
65 : : double fResult;
66 [ # # ]: 0 : if( rOutValidCount == 0 )
67 : 0 : ::rtl::math::setNan( & fResult );
68 : : else
69 : : {
70 : 0 : const double fN = static_cast< double >( rOutValidCount );
71 [ # # ]: 0 : if( bUnbiasedEstimator )
72 : 0 : fResult = (fQuadSum - fSum*fSum/fN) / (fN - 1);
73 : : else
74 : 0 : fResult = (fQuadSum - fSum*fSum/fN) / fN;
75 : : }
76 : :
77 : 0 : return fResult;
78 : : }
79 : :
80 : 0 : Reference< chart2::data::XLabeledDataSequence > lcl_getErrorBarLabeledSequence(
81 : : const Reference< chart2::data::XDataSource > & xDataSource,
82 : : bool bPositiveValue, bool bYError,
83 : : OUString & rOutRoleNameUsed )
84 : : {
85 [ # # ][ # # ]: 0 : OUStringBuffer aRole( C2U("error-bars-"));
86 [ # # ]: 0 : if( bYError )
87 [ # # ]: 0 : aRole.append( sal_Unicode( 'y' ));
88 : : else
89 [ # # ]: 0 : aRole.append( sal_Unicode( 'x' ));
90 : :
91 [ # # ]: 0 : OUString aPlainRole = aRole.makeStringAndClear();
92 [ # # ]: 0 : aRole.append( aPlainRole );
93 [ # # ]: 0 : aRole.append( sal_Unicode( '-' ));
94 : :
95 [ # # ]: 0 : if( bPositiveValue )
96 [ # # ][ # # ]: 0 : aRole = aRole.appendAscii( "positive" );
97 : : else
98 [ # # ][ # # ]: 0 : aRole = aRole.appendAscii( "negative" );
99 : :
100 [ # # ]: 0 : OUString aLongRole = aRole.makeStringAndClear();
101 : : Reference< chart2::data::XLabeledDataSequence > xLSeq(
102 [ # # ]: 0 : ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aLongRole ));
103 : : // try role without "-negative" or "-positive" postfix
104 [ # # ]: 0 : if( xLSeq.is())
105 : 0 : rOutRoleNameUsed = aLongRole;
106 : : else
107 : : {
108 [ # # ][ # # ]: 0 : xLSeq.set( ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aPlainRole ));
109 [ # # ]: 0 : if( xLSeq.is())
110 : 0 : rOutRoleNameUsed = aPlainRole;
111 : : else
112 : 0 : rOutRoleNameUsed = aLongRole;
113 : : }
114 : :
115 : 0 : return xLSeq;
116 : : }
117 : :
118 : 0 : void lcl_setRole(
119 : : const Reference< chart2::data::XDataSequence > & xNewSequence,
120 : : const OUString & rRole )
121 : : {
122 [ # # ]: 0 : Reference< beans::XPropertySet > xSeqProp( xNewSequence, uno::UNO_QUERY );
123 [ # # ]: 0 : if( xSeqProp.is())
124 [ # # ][ # # ]: 0 : xSeqProp->setPropertyValue( C2U("Role"), uno::makeAny( rRole ));
[ # # ][ # # ]
125 : 0 : }
126 : :
127 : 0 : void lcl_addSequenceToDataSource(
128 : : const Reference< chart2::data::XDataSource > & xDataSource,
129 : : const Reference< chart2::data::XDataSequence > & xNewSequence,
130 : : const OUString & rRole )
131 : : {
132 [ # # ]: 0 : Reference< chart2::data::XDataSink > xSink( xDataSource, uno::UNO_QUERY );
133 [ # # ][ # # ]: 0 : Reference< lang::XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
134 [ # # ][ # # ]: 0 : if( ! ( xFact.is() && xSink.is() ))
[ # # ]
135 : 0 : return;
136 : :
137 : : Reference< chart2::data::XLabeledDataSequence > xLSeq(
138 [ # # ][ # # ]: 0 : xFact->createInstance( C2U("com.sun.star.chart2.data.LabeledDataSequence")), uno::UNO_QUERY );
[ # # ][ # # ]
139 [ # # ]: 0 : if( xLSeq.is())
140 : : {
141 [ # # ]: 0 : lcl_setRole( xNewSequence, rRole );
142 [ # # ][ # # ]: 0 : xLSeq->setValues( xNewSequence );
143 : : Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences(
144 [ # # ][ # # ]: 0 : xDataSource->getDataSequences());
145 [ # # ]: 0 : aSequences.realloc( aSequences.getLength() + 1 );
146 [ # # ][ # # ]: 0 : aSequences[ aSequences.getLength() - 1 ] = xLSeq;
147 [ # # ][ # # ]: 0 : xSink->setData( aSequences );
[ # # ]
148 [ # # ][ # # ]: 0 : }
149 : : }
150 : :
151 : 0 : void lcl_setXMLRangePropertyAtDataSequence(
152 : : const Reference< chart2::data::XDataSequence > & xDataSequence,
153 : : const OUString & rXMLRange )
154 : : {
155 : : try
156 : : {
157 [ # # ]: 0 : const OUString aXMLRangePropName( C2U( "CachedXMLRange" ));
158 [ # # ]: 0 : Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
159 [ # # ][ # # ]: 0 : Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
160 [ # # ][ # # ]: 0 : if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ))
[ # # ][ # # ]
[ # # ]
161 [ # # ][ # # ]: 0 : xProp->setPropertyValue( aXMLRangePropName, uno::makeAny( rXMLRange ));
[ # # ][ # # ]
162 : : }
163 : 0 : catch( const uno::Exception & ex )
164 : : {
165 : : ASSERT_EXCEPTION( ex );
166 : : }
167 : 0 : }
168 : :
169 : : } // anonymous namespace
170 : :
171 : : namespace chart
172 : : {
173 : :
174 : 0 : double StatisticsHelper::getVariance(
175 : : const Sequence< double > & rData,
176 : : bool bUnbiasedEstimator /* = false */ )
177 : : {
178 : : sal_Int32 nValCount;
179 [ # # ]: 0 : return lcl_getVariance( rData, nValCount, bUnbiasedEstimator );
180 : : }
181 : :
182 : 0 : double StatisticsHelper::getStandardDeviation( const Sequence< double > & rData )
183 : : {
184 : 0 : double fResult = getVariance( rData );
185 [ # # ]: 0 : if( ! ::rtl::math::isNan( fResult ))
186 : 0 : fResult = sqrt( fResult );
187 : :
188 : 0 : return fResult;
189 : : }
190 : :
191 : 0 : double StatisticsHelper::getStandardError( const Sequence< double > & rData )
192 : : {
193 : : sal_Int32 nValCount;
194 [ # # ]: 0 : double fVar = lcl_getVariance( rData, nValCount, false );
195 : : double fResult;
196 : :
197 [ # # # # ]: 0 : if( nValCount == 0 ||
[ # # ]
198 : 0 : ::rtl::math::isNan( fVar ))
199 : : {
200 : 0 : ::rtl::math::setNan( & fResult );
201 : : }
202 : : else
203 : : {
204 : : // standard-deviation / sqrt(n)
205 : 0 : fResult = sqrt( fVar ) / sqrt( double(nValCount) );
206 : : }
207 : :
208 : 0 : return fResult;
209 : : }
210 : :
211 : 0 : Reference< chart2::data::XLabeledDataSequence > StatisticsHelper::getErrorLabeledDataSequenceFromDataSource(
212 : : const Reference< chart2::data::XDataSource > & xDataSource,
213 : : bool bPositiveValue,
214 : : bool bYError /* = true */ )
215 : : {
216 : 0 : Reference< chart2::data::XLabeledDataSequence > xResult;
217 [ # # ]: 0 : if( !xDataSource.is())
218 : : return xResult;
219 : :
220 : 0 : OUString aRole;
221 : : Reference< chart2::data::XLabeledDataSequence > xLSeq(
222 [ # # ]: 0 : lcl_getErrorBarLabeledSequence( xDataSource, bPositiveValue, bYError, aRole ));
223 [ # # ]: 0 : if( xLSeq.is())
224 [ # # ]: 0 : xResult.set( xLSeq );
225 : :
226 : 0 : return xResult;
227 : : }
228 : :
229 : 0 : Reference< chart2::data::XDataSequence > StatisticsHelper::getErrorDataSequenceFromDataSource(
230 : : const Reference< chart2::data::XDataSource > & xDataSource,
231 : : bool bPositiveValue,
232 : : bool bYError /* = true */ )
233 : : {
234 : : Reference< chart2::data::XLabeledDataSequence > xLSeq(
235 : : StatisticsHelper::getErrorLabeledDataSequenceFromDataSource(
236 : : xDataSource, bPositiveValue,
237 [ # # ]: 0 : bYError ));
238 [ # # ]: 0 : if( !xLSeq.is())
239 : 0 : return Reference< chart2::data::XDataSequence >();
240 : :
241 [ # # ][ # # ]: 0 : return xLSeq->getValues();
242 : : }
243 : :
244 : 0 : double StatisticsHelper::getErrorFromDataSource(
245 : : const Reference< chart2::data::XDataSource > & xDataSource,
246 : : sal_Int32 nIndex,
247 : : bool bPositiveValue,
248 : : bool bYError /* = true */ )
249 : : {
250 : 0 : double fResult = 0.0;
251 : 0 : ::rtl::math::setNan( & fResult );
252 : :
253 : : Reference< chart2::data::XDataSequence > xValues(
254 [ # # ]: 0 : StatisticsHelper::getErrorDataSequenceFromDataSource( xDataSource, bPositiveValue, bYError ));
255 : :
256 [ # # ]: 0 : Reference< chart2::data::XNumericalDataSequence > xNumValues( xValues, uno::UNO_QUERY );
257 [ # # ]: 0 : if( xNumValues.is())
258 : : {
259 [ # # ][ # # ]: 0 : Sequence< double > aData( xNumValues->getNumericalData());
260 [ # # ]: 0 : if( nIndex < aData.getLength())
261 [ # # ][ # # ]: 0 : fResult = aData[nIndex];
262 : : }
263 [ # # ]: 0 : else if( xValues.is())
264 : : {
265 [ # # ][ # # ]: 0 : Sequence< uno::Any > aData( xValues->getData());
266 [ # # ]: 0 : if( nIndex < aData.getLength())
267 [ # # ][ # # ]: 0 : aData[nIndex] >>= fResult;
268 : : }
269 : :
270 : 0 : return fResult;
271 : : }
272 : :
273 : 0 : void StatisticsHelper::setErrorDataSequence(
274 : : const Reference< chart2::data::XDataSource > & xDataSource,
275 : : const Reference< chart2::data::XDataProvider > & xDataProvider,
276 : : const OUString & rNewRange,
277 : : bool bPositiveValue,
278 : : bool bYError /* = true */,
279 : : OUString * pXMLRange /* = 0 */ )
280 : : {
281 [ # # ]: 0 : Reference< chart2::data::XDataSink > xDataSink( xDataSource, uno::UNO_QUERY );
282 [ # # ][ # # ]: 0 : if( ! ( xDataSink.is() && xDataProvider.is()))
[ # # ]
283 : 0 : return;
284 : :
285 : 0 : OUString aRole;
286 : : Reference< chart2::data::XLabeledDataSequence > xLSeq(
287 [ # # ]: 0 : lcl_getErrorBarLabeledSequence( xDataSource, bPositiveValue, bYError, aRole ));
288 : : Reference< chart2::data::XDataSequence > xNewSequence(
289 [ # # ][ # # ]: 0 : xDataProvider->createDataSequenceByRangeRepresentation( rNewRange ));
290 [ # # ]: 0 : if( xNewSequence.is())
291 : : {
292 [ # # ]: 0 : if( pXMLRange )
293 [ # # ]: 0 : lcl_setXMLRangePropertyAtDataSequence( xNewSequence, *pXMLRange );
294 [ # # ]: 0 : if( xLSeq.is())
295 : : {
296 [ # # ]: 0 : lcl_setRole( xNewSequence, aRole );
297 [ # # ][ # # ]: 0 : xLSeq->setValues( xNewSequence );
298 : : }
299 : : else
300 [ # # ]: 0 : lcl_addSequenceToDataSource( xDataSource, xNewSequence, aRole );
301 [ # # ]: 0 : }
302 : : }
303 : :
304 : 0 : Reference< beans::XPropertySet > StatisticsHelper::addErrorBars(
305 : : const Reference< chart2::XDataSeries > & xDataSeries,
306 : : const Reference< uno::XComponentContext > & xContext,
307 : : sal_Int32 nStyle,
308 : : bool bYError /* = true */ )
309 : : {
310 : 0 : Reference< beans::XPropertySet > xErrorBar;
311 [ # # ]: 0 : Reference< beans::XPropertySet > xSeriesProp( xDataSeries, uno::UNO_QUERY );
312 [ # # ]: 0 : if( !xSeriesProp.is())
313 : : return xErrorBar;
314 : :
315 [ # # ][ # # ]: 0 : const OUString aPropName( bYError ? C2U("ErrorBarY") : C2U("ErrorBarX"));
[ # # ]
316 [ # # ][ # # ]: 0 : if( !( xSeriesProp->getPropertyValue( aPropName ) >>= xErrorBar ) ||
[ # # ]
[ # # # # ]
[ # # ]
[ # # # # ]
317 : 0 : !xErrorBar.is())
318 : : {
319 [ # # ][ # # ]: 0 : xErrorBar.set( createErrorBar( xContext ));
320 : : }
321 : :
322 : : OSL_ASSERT( xErrorBar.is());
323 [ # # ]: 0 : if( xErrorBar.is())
324 : : {
325 [ # # ][ # # ]: 0 : xErrorBar->setPropertyValue( C2U("ErrorBarStyle"), uno::makeAny( nStyle ));
[ # # ][ # # ]
326 : : }
327 : :
328 [ # # ][ # # ]: 0 : xSeriesProp->setPropertyValue( aPropName, uno::makeAny( xErrorBar ));
[ # # ]
329 : :
330 : 0 : return xErrorBar;
331 : : }
332 : :
333 : 0 : Reference< beans::XPropertySet > StatisticsHelper::getErrorBars(
334 : : const Reference< chart2::XDataSeries > & xDataSeries,
335 : : bool bYError /* = true */ )
336 : : {
337 [ # # ]: 0 : Reference< beans::XPropertySet > xSeriesProp( xDataSeries, uno::UNO_QUERY );
338 : 0 : Reference< beans::XPropertySet > xErrorBar;
339 [ # # ][ # # ]: 0 : const OUString aPropName( bYError ? C2U("ErrorBarY") : C2U("ErrorBarX"));
[ # # ]
340 : :
341 [ # # ]: 0 : if ( xSeriesProp.is())
342 [ # # ][ # # ]: 0 : xSeriesProp->getPropertyValue( aPropName ) >>= xErrorBar;
[ # # ]
343 : :
344 : 0 : return xErrorBar;
345 : : }
346 : :
347 : 0 : bool StatisticsHelper::hasErrorBars(
348 : : const Reference< chart2::XDataSeries > & xDataSeries,
349 : : bool bYError /* = true */ )
350 : : {
351 [ # # ]: 0 : Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError ));
352 : 0 : sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE;
353 : :
354 : 0 : return ( xErrorBar.is() &&
355 [ # # ][ # # ]: 0 : ( xErrorBar->getPropertyValue( C2U("ErrorBarStyle")) >>= nStyle ) &&
[ # # ][ # # ]
[ # # ]
[ # # # # ]
356 [ # # ]: 0 : nStyle != ::com::sun::star::chart::ErrorBarStyle::NONE );
[ # # # # ]
357 : : }
358 : :
359 : 0 : void StatisticsHelper::removeErrorBars(
360 : : const Reference< chart2::XDataSeries > & xDataSeries,
361 : : bool bYError /* = true */ )
362 : : {
363 [ # # ]: 0 : Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError ));
364 [ # # ]: 0 : if ( xErrorBar.is())
365 [ # # ]: 0 : xErrorBar->setPropertyValue( C2U("ErrorBarStyle"), uno::makeAny(
366 [ # # ][ # # ]: 0 : ::com::sun::star::chart::ErrorBarStyle::NONE ));
[ # # ]
367 : 0 : }
368 : :
369 : 0 : bool StatisticsHelper::usesErrorBarRanges(
370 : : const Reference< chart2::XDataSeries > & xDataSeries,
371 : : bool bYError /* = true */ )
372 : : {
373 [ # # ]: 0 : Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError ));
374 : 0 : sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE;
375 : :
376 : 0 : return ( xErrorBar.is() &&
377 [ # # ][ # # ]: 0 : ( xErrorBar->getPropertyValue( C2U("ErrorBarStyle")) >>= nStyle ) &&
[ # # ][ # # ]
[ # # ]
[ # # # # ]
378 [ # # ]: 0 : nStyle == ::com::sun::star::chart::ErrorBarStyle::FROM_DATA );
[ # # # # ]
379 : : }
380 : :
381 : : } // namespace chart
382 : :
383 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|