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