LibreOffice Module chart2 (master) 1
StatisticsHelper.cxx
Go to the documentation of this file.
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 <DataSeries.hxx>
22#include <DataSeriesHelper.hxx>
23#include <ErrorBar.hxx>
24#include <unonames.hxx>
25
26#include <rtl/ustrbuf.hxx>
28#include <com/sun/star/chart2/XDataSeries.hpp>
29#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
30#include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
31#include <com/sun/star/chart2/data/XDataProvider.hpp>
32#include <com/sun/star/chart2/data/XDataSink.hpp>
33#include <com/sun/star/chart/ErrorBarStyle.hpp>
35
36#include <cmath>
37#include <limits>
38
39using ::com::sun::star::uno::Sequence;
40using ::com::sun::star::uno::Reference;
41using namespace ::com::sun::star;
42
43namespace
44{
45
46double lcl_getVariance( const Sequence< double > & rData, sal_Int32 & rOutValidCount )
47{
48 const sal_Int32 nCount = rData.getLength();
49 rOutValidCount = nCount;
50
51 double fSum = 0.0;
52 double fQuadSum = 0.0;
53
54 for( sal_Int32 i = 0; i < nCount; ++i )
55 {
56 const double fData = rData[i];
57 if( std::isnan( fData ))
58 --rOutValidCount;
59 else
60 {
61 fSum += fData;
62 fQuadSum += fData * fData;
63 }
64 }
65
66 if( rOutValidCount == 0 )
67 return std::numeric_limits<double>::quiet_NaN();
68
69 const double fN = static_cast< double >( rOutValidCount );
70 return (fQuadSum - fSum*fSum/fN) / fN;
71}
72
73uno::Reference< chart2::data::XLabeledDataSequence > lcl_getErrorBarLabeledSequence(
74 const Reference< chart2::data::XDataSource > & xDataSource,
75 bool bPositiveValue, bool bYError,
76 OUString & rOutRoleNameUsed )
77{
78 OUStringBuffer aRole( "error-bars-");
79 if( bYError )
80 aRole.append( 'y');
81 else
82 aRole.append( 'x');
83
84 OUString aPlainRole = aRole.makeStringAndClear();
85 aRole.append( aPlainRole + "-" );
86
87 if( bPositiveValue )
88 aRole.append( "positive" );
89 else
90 aRole.append( "negative" );
91
92 OUString aLongRole = aRole.makeStringAndClear();
93 uno::Reference< chart2::data::XLabeledDataSequence > xLSeq =
95 // try role without "-negative" or "-positive" postfix
96 if( xLSeq.is())
97 rOutRoleNameUsed = aLongRole;
98 else
99 {
100 xLSeq = ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aPlainRole );
101 if( xLSeq.is())
102 rOutRoleNameUsed = aPlainRole;
103 else
104 rOutRoleNameUsed = aLongRole;
105 }
106
107 return xLSeq;
108}
109
110void lcl_setRole(
111 const Reference< chart2::data::XDataSequence > & xNewSequence,
112 const OUString & rRole )
113{
114 Reference< beans::XPropertySet > xSeqProp( xNewSequence, uno::UNO_QUERY );
115 if( xSeqProp.is())
116 xSeqProp->setPropertyValue( "Role", uno::Any( rRole ));
117}
118
119void lcl_addSequenceToDataSource(
120 const Reference< chart2::data::XDataSource > & xDataSource,
121 const Reference< chart2::data::XDataSequence > & xNewSequence,
122 const OUString & rRole )
123{
124 Reference< chart2::data::XDataSink > xSink( xDataSource, uno::UNO_QUERY );
125 Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
126 if( ! xSink.is() )
127 return;
128
129 Reference< chart2::data::XLabeledDataSequence > xLSeq( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
130
131 lcl_setRole( xNewSequence, rRole );
132 xLSeq->setValues( xNewSequence );
133 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences(
134 xDataSource->getDataSequences());
135 aSequences.realloc( aSequences.getLength() + 1 );
136 auto pSequences = aSequences.getArray();
137 pSequences[ aSequences.getLength() - 1 ] = xLSeq;
138 xSink->setData( aSequences );
139}
140
141void lcl_setXMLRangePropertyAtDataSequence(
142 const Reference< chart2::data::XDataSequence > & xDataSequence,
143 const OUString & rXMLRange )
144{
145 try
146 {
147 static constexpr OUStringLiteral aXMLRangePropName( u"CachedXMLRange");
148 Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
149 Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
150 if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ))
151 xProp->setPropertyValue( aXMLRangePropName, uno::Any( rXMLRange ));
152 }
153 catch( const uno::Exception & )
154 {
155 DBG_UNHANDLED_EXCEPTION("chart2");
156 }
157}
158
159} // anonymous namespace
160
161namespace chart
162{
163
165 const Sequence< double > & rData )
166{
167 sal_Int32 nValCount;
168 return lcl_getVariance( rData, nValCount );
169}
170
171double StatisticsHelper::getStandardDeviation( const Sequence< double > & rData )
172{
173 double fResult = getVariance( rData );
174 if( ! std::isnan( fResult ))
175 fResult = sqrt( fResult );
176
177 return fResult;
178}
179
180double StatisticsHelper::getStandardError( const Sequence< double > & rData )
181{
182 sal_Int32 nValCount;
183 double fVar = lcl_getVariance( rData, nValCount );
184
185 if( nValCount == 0 || std::isnan( fVar ))
186 return std::numeric_limits<double>::quiet_NaN();
187 // standard-deviation / sqrt(n)
188 return sqrt( fVar ) / sqrt( double(nValCount) );
189}
190
191uno::Reference< chart2::data::XLabeledDataSequence > StatisticsHelper::getErrorLabeledDataSequenceFromDataSource(
192 const Reference< chart2::data::XDataSource > & xDataSource,
193 bool bPositiveValue,
194 bool bYError /* = true */ )
195{
196 uno::Reference< chart2::data::XLabeledDataSequence > xResult;
197 if( !xDataSource.is())
198 return xResult;
199
200 OUString aRole;
201 uno::Reference< chart2::data::XLabeledDataSequence > xLSeq =
202 lcl_getErrorBarLabeledSequence( xDataSource, bPositiveValue, bYError, aRole );
203 if( xLSeq.is())
204 xResult = xLSeq;
205
206 return xResult;
207}
208
209Reference< chart2::data::XDataSequence > StatisticsHelper::getErrorDataSequenceFromDataSource(
210 const Reference< chart2::data::XDataSource > & xDataSource,
211 bool bPositiveValue,
212 bool bYError /* = true */ )
213{
214 uno::Reference< chart2::data::XLabeledDataSequence > xLSeq =
216 xDataSource, bPositiveValue,
217 bYError );
218 if( !xLSeq.is())
219 return Reference< chart2::data::XDataSequence >();
220
221 return xLSeq->getValues();
222}
223
225 const Reference< chart2::data::XDataSource > & xDataSource,
226 sal_Int32 nIndex,
227 bool bPositiveValue,
228 bool bYError /* = true */ )
229{
230 double fResult = std::numeric_limits<double>::quiet_NaN();
231
232 Reference< chart2::data::XDataSequence > xValues(
233 StatisticsHelper::getErrorDataSequenceFromDataSource( xDataSource, bPositiveValue, bYError ));
234
235 Reference< chart2::data::XNumericalDataSequence > xNumValues( xValues, uno::UNO_QUERY );
236 if( xNumValues.is())
237 {
238 Sequence< double > aData( xNumValues->getNumericalData());
239 if( nIndex < aData.getLength())
240 fResult = aData[nIndex];
241 }
242 else if( xValues.is())
243 {
244 Sequence< uno::Any > aData( xValues->getData());
245 if( nIndex < aData.getLength())
246 aData[nIndex] >>= fResult;
247 }
248
249 return fResult;
250}
251
253 const Reference< chart2::data::XDataSource > & xDataSource,
254 const Reference< chart2::data::XDataProvider > & xDataProvider,
255 const OUString & rNewRange,
256 bool bPositiveValue,
257 bool bYError /* = true */,
258 OUString const * pXMLRange /* = 0 */ )
259{
260 Reference< chart2::data::XDataSink > xDataSink( xDataSource, uno::UNO_QUERY );
261 if( ! ( xDataSink.is() && xDataProvider.is()))
262 return;
263
264 OUString aRole;
266 lcl_getErrorBarLabeledSequence( xDataSource, bPositiveValue, bYError, aRole ));
267 Reference< chart2::data::XDataSequence > xNewSequence(
268 xDataProvider->createDataSequenceByRangeRepresentation( rNewRange ));
269 if( xNewSequence.is())
270 {
271 if( pXMLRange )
272 lcl_setXMLRangePropertyAtDataSequence( xNewSequence, *pXMLRange );
273 if( xLSeq.is())
274 {
275 lcl_setRole( xNewSequence, aRole );
276 xLSeq->setValues( xNewSequence );
277 }
278 else
279 lcl_addSequenceToDataSource( xDataSource, xNewSequence, aRole );
280 }
281}
282
283Reference< beans::XPropertySet > StatisticsHelper::addErrorBars(
284 const rtl::Reference< DataSeries > & xDataSeries,
285 sal_Int32 nStyle,
286 bool bYError /* = true */ )
287{
288 Reference< beans::XPropertySet > xErrorBar;
289 if( !xDataSeries.is())
290 return xErrorBar;
291
292 const OUString aPropName(
293 bYError ? OUString(CHART_UNONAME_ERRORBAR_Y) : OUString(CHART_UNONAME_ERRORBAR_X));
294 if( !( xDataSeries->getPropertyValue( aPropName ) >>= xErrorBar ) ||
295 !xErrorBar.is())
296 {
297 xErrorBar.set( new ErrorBar );
298 }
299
300 OSL_ASSERT( xErrorBar.is());
301 if( xErrorBar.is())
302 {
303 xErrorBar->setPropertyValue( "ErrorBarStyle", uno::Any( nStyle ));
304 }
305
306 xDataSeries->setPropertyValue( aPropName, uno::Any( xErrorBar ));
307
308 return xErrorBar;
309}
310
311Reference< beans::XPropertySet > StatisticsHelper::getErrorBars(
312 const rtl::Reference< DataSeries > & xDataSeries,
313 bool bYError /* = true */ )
314{
315 Reference< beans::XPropertySet > xErrorBar;
316 const OUString aPropName(
317 bYError ? OUString(CHART_UNONAME_ERRORBAR_Y) : OUString(CHART_UNONAME_ERRORBAR_X));
318
319 if ( xDataSeries.is())
320 xDataSeries->getPropertyValue( aPropName ) >>= xErrorBar;
321
322 return xErrorBar;
323}
324
326 const rtl::Reference< DataSeries > & xDataSeries,
327 bool bYError /* = true */ )
328{
329 Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError ));
330 sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE;
331
332 return ( xErrorBar.is() &&
333 ( xErrorBar->getPropertyValue( "ErrorBarStyle") >>= nStyle ) &&
334 nStyle != css::chart::ErrorBarStyle::NONE );
335}
336
338 const rtl::Reference< DataSeries > & xDataSeries,
339 bool bYError /* = true */ )
340{
341 Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError ));
342 if ( xErrorBar.is())
343 xErrorBar->setPropertyValue( "ErrorBarStyle", uno::Any(
344 css::chart::ErrorBarStyle::NONE ));
345}
346
348 const rtl::Reference< DataSeries > & xDataSeries,
349 bool bYError /* = true */ )
350{
351 Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError ));
352 sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE;
353
354 return ( xErrorBar.is() &&
355 ( xErrorBar->getPropertyValue( "ErrorBarStyle") >>= nStyle ) &&
356 nStyle == css::chart::ErrorBarStyle::FROM_DATA );
357}
358
359} // namespace chart
360
361/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
int nCount
#define DBG_UNHANDLED_EXCEPTION(...)
sal_Int32 nIndex
tools::SvRef< SvBaseLink > xSink
constexpr OUStringLiteral aData
OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::chart2::data::XLabeledDataSequence > getDataSequenceByRole(const css::uno::Reference< css::chart2::data::XDataSource > &xSource, const OUString &aRole, bool bMatchPrefix=false)
Retrieves the data sequence in the given data source that matches the given role.
OOO_DLLPUBLIC_CHARTTOOLS void removeErrorBars(const rtl::Reference< ::chart::DataSeries > &xDataSeries, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS double getStandardDeviation(const css::uno::Sequence< double > &rData)
OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::chart2::data::XDataSequence > getErrorDataSequenceFromDataSource(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource, bool bPositiveValue, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::beans::XPropertySet > getErrorBars(const rtl::Reference< ::chart::DataSeries > &xDataSeries, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS bool usesErrorBarRanges(const rtl::Reference< ::chart::DataSeries > &xDataSeries, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS double getStandardError(const css::uno::Sequence< double > &rData)
OOO_DLLPUBLIC_CHARTTOOLS bool hasErrorBars(const rtl::Reference< ::chart::DataSeries > &xDataSeries, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS double getErrorFromDataSource(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource, sal_Int32 nIndex, bool bPositiveValue, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::beans::XPropertySet > addErrorBars(const rtl::Reference< ::chart::DataSeries > &xDataSeries, sal_Int32 nStyle, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS void setErrorDataSequence(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource, const css::uno::Reference< css::chart2::data::XDataProvider > &xDataProvider, const OUString &rNewRange, bool bPositiveValue, bool bYError=true, OUString const *pXMLRange=nullptr)
OOO_DLLPUBLIC_CHARTTOOLS double getVariance(const css::uno::Sequence< double > &rData)
Calculates 1/n * sum (x_i - x_mean)^2.
OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::chart2::data::XLabeledDataSequence > getErrorLabeledDataSequenceFromDataSource(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource, bool bPositiveValue, bool bYError=true)
Reference< XComponentContext > getProcessComponentContext()
int i
OUString aPropName
constexpr OUStringLiteral CHART_UNONAME_ERRORBAR_Y
Definition: unonames.hxx:23
constexpr OUStringLiteral CHART_UNONAME_ERRORBAR_X
Definition: unonames.hxx:22