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