/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "StatisticsHelper.hxx" #include "DataSeriesHelper.hxx" #include "ErrorBar.hxx" #include "macros.hxx" #include #include #include #include #include #include #include #include using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Reference; using ::rtl::OUString; using ::rtl::OUStringBuffer; using namespace ::com::sun::star; namespace { double lcl_getVariance( const Sequence< double > & rData, sal_Int32 & rOutValidCount, bool bUnbiasedEstimator ) { const sal_Int32 nCount = rData.getLength(); rOutValidCount = nCount; double fSum = 0.0; double fQuadSum = 0.0; for( sal_Int32 i = 0; i < nCount; ++i ) { const double fData = rData[i]; if( ::rtl::math::isNan( fData )) --rOutValidCount; else { fSum += fData; fQuadSum += fData * fData; } } double fResult; if( rOutValidCount == 0 ) ::rtl::math::setNan( & fResult ); else { const double fN = static_cast< double >( rOutValidCount ); if( bUnbiasedEstimator ) fResult = (fQuadSum - fSum*fSum/fN) / (fN - 1); else fResult = (fQuadSum - fSum*fSum/fN) / fN; } return fResult; } Reference< chart2::data::XLabeledDataSequence > lcl_getErrorBarLabeledSequence( const Reference< chart2::data::XDataSource > & xDataSource, bool bPositiveValue, bool bYError, OUString & rOutRoleNameUsed ) { OUStringBuffer aRole( C2U("error-bars-")); if( bYError ) aRole.append( sal_Unicode( 'y' )); else aRole.append( sal_Unicode( 'x' )); OUString aPlainRole = aRole.makeStringAndClear(); aRole.append( aPlainRole ); aRole.append( sal_Unicode( '-' )); if( bPositiveValue ) aRole = aRole.appendAscii( "positive" ); else aRole = aRole.appendAscii( "negative" ); OUString aLongRole = aRole.makeStringAndClear(); Reference< chart2::data::XLabeledDataSequence > xLSeq( ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aLongRole )); // try role without "-negative" or "-positive" postfix if( xLSeq.is()) rOutRoleNameUsed = aLongRole; else { xLSeq.set( ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aPlainRole )); if( xLSeq.is()) rOutRoleNameUsed = aPlainRole; else rOutRoleNameUsed = aLongRole; } return xLSeq; } void lcl_setRole( const Reference< chart2::data::XDataSequence > & xNewSequence, const OUString & rRole ) { Reference< beans::XPropertySet > xSeqProp( xNewSequence, uno::UNO_QUERY ); if( xSeqProp.is()) xSeqProp->setPropertyValue( C2U("Role"), uno::makeAny( rRole )); } void lcl_addSequenceToDataSource( const Reference< chart2::data::XDataSource > & xDataSource, const Reference< chart2::data::XDataSequence > & xNewSequence, const OUString & rRole ) { Reference< chart2::data::XDataSink > xSink( xDataSource, uno::UNO_QUERY ); Reference< lang::XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW ); if( ! ( xFact.is() && xSink.is() )) return; Reference< chart2::data::XLabeledDataSequence > xLSeq( xFact->createInstance( C2U("com.sun.star.chart2.data.LabeledDataSequence")), uno::UNO_QUERY ); if( xLSeq.is()) { lcl_setRole( xNewSequence, rRole ); xLSeq->setValues( xNewSequence ); Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences()); aSequences.realloc( aSequences.getLength() + 1 ); aSequences[ aSequences.getLength() - 1 ] = xLSeq; xSink->setData( aSequences ); } } void lcl_setXMLRangePropertyAtDataSequence( const Reference< chart2::data::XDataSequence > & xDataSequence, const OUString & rXMLRange ) { try { const OUString aXMLRangePropName( C2U( "CachedXMLRange" )); Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW ); Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo()); if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName )) xProp->setPropertyValue( aXMLRangePropName, uno::makeAny( rXMLRange )); } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } } // anonymous namespace namespace chart { double StatisticsHelper::getVariance( const Sequence< double > & rData, bool bUnbiasedEstimator /* = false */ ) { sal_Int32 nValCount; return lcl_getVariance( rData, nValCount, bUnbiasedEstimator ); } double StatisticsHelper::getStandardDeviation( const Sequence< double > & rData ) { double fResult = getVariance( rData ); if( ! ::rtl::math::isNan( fResult )) fResult = sqrt( fResult ); return fResult; } double StatisticsHelper::getStandardError( const Sequence< double > & rData ) { sal_Int32 nValCount; double fVar = lcl_getVariance( rData, nValCount, false ); double fResult; if( nValCount == 0 || ::rtl::math::isNan( fVar )) { ::rtl::math::setNan( & fResult ); } else { // standard-deviation / sqrt(n) fResult = sqrt( fVar ) / sqrt( double(nValCount) ); } return fResult; } Reference< chart2::data::XLabeledDataSequence > StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( const Reference< chart2::data::XDataSource > & xDataSource, bool bPositiveValue, bool bYError /* = true */ ) { Reference< chart2::data::XLabeledDataSequence > xResult; if( !xDataSource.is()) return xResult; OUString aRole; Reference< chart2::data::XLabeledDataSequence > xLSeq( lcl_getErrorBarLabeledSequence( xDataSource, bPositiveValue, bYError, aRole )); if( xLSeq.is()) xResult.set( xLSeq ); return xResult; } Reference< chart2::data::XDataSequence > StatisticsHelper::getErrorDataSequenceFromDataSource( const Reference< chart2::data::XDataSource > & xDataSource, bool bPositiveValue, bool bYError /* = true */ ) { Reference< chart2::data::XLabeledDataSequence > xLSeq( StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( xDataSource, bPositiveValue, bYError )); if( !xLSeq.is()) return Reference< chart2::data::XDataSequence >(); return xLSeq->getValues(); } double StatisticsHelper::getErrorFromDataSource( const Reference< chart2::data::XDataSource > & xDataSource, sal_Int32 nIndex, bool bPositiveValue, bool bYError /* = true */ ) { double fResult = 0.0; ::rtl::math::setNan( & fResult ); Reference< chart2::data::XDataSequence > xValues( StatisticsHelper::getErrorDataSequenceFromDataSource( xDataSource, bPositiveValue, bYError )); Reference< chart2::data::XNumericalDataSequence > xNumValues( xValues, uno::UNO_QUERY ); if( xNumValues.is()) { Sequence< double > aData( xNumValues->getNumericalData()); if( nIndex < aData.getLength()) fResult = aData[nIndex]; } else if( xValues.is()) { Sequence< uno::Any > aData( xValues->getData()); if( nIndex < aData.getLength()) aData[nIndex] >>= fResult; } return fResult; } void StatisticsHelper::setErrorDataSequence( const Reference< chart2::data::XDataSource > & xDataSource, const Reference< chart2::data::XDataProvider > & xDataProvider, const OUString & rNewRange, bool bPositiveValue, bool bYError /* = true */, OUString * pXMLRange /* = 0 */ ) { Reference< chart2::data::XDataSink > xDataSink( xDataSource, uno::UNO_QUERY ); if( ! ( xDataSink.is() && xDataProvider.is())) return; OUString aRole; Reference< chart2::data::XLabeledDataSequence > xLSeq( lcl_getErrorBarLabeledSequence( xDataSource, bPositiveValue, bYError, aRole )); Reference< chart2::data::XDataSequence > xNewSequence( xDataProvider->createDataSequenceByRangeRepresentation( rNewRange )); if( xNewSequence.is()) { if( pXMLRange ) lcl_setXMLRangePropertyAtDataSequence( xNewSequence, *pXMLRange ); if( xLSeq.is()) { lcl_setRole( xNewSequence, aRole ); xLSeq->setValues( xNewSequence ); } else lcl_addSequenceToDataSource( xDataSource, xNewSequence, aRole ); } } Reference< beans::XPropertySet > StatisticsHelper::addErrorBars( const Reference< chart2::XDataSeries > & xDataSeries, const Reference< uno::XComponentContext > & xContext, sal_Int32 nStyle, bool bYError /* = true */ ) { Reference< beans::XPropertySet > xErrorBar; Reference< beans::XPropertySet > xSeriesProp( xDataSeries, uno::UNO_QUERY ); if( !xSeriesProp.is()) return xErrorBar; const OUString aPropName( bYError ? C2U("ErrorBarY") : C2U("ErrorBarX")); if( !( xSeriesProp->getPropertyValue( aPropName ) >>= xErrorBar ) || !xErrorBar.is()) { xErrorBar.set( createErrorBar( xContext )); } OSL_ASSERT( xErrorBar.is()); if( xErrorBar.is()) { xErrorBar->setPropertyValue( C2U("ErrorBarStyle"), uno::makeAny( nStyle )); } xSeriesProp->setPropertyValue( aPropName, uno::makeAny( xErrorBar )); return xErrorBar; } Reference< beans::XPropertySet > StatisticsHelper::getErrorBars( const Reference< chart2::XDataSeries > & xDataSeries, bool bYError /* = true */ ) { Reference< beans::XPropertySet > xSeriesProp( xDataSeries, uno::UNO_QUERY ); Reference< beans::XPropertySet > xErrorBar; const OUString aPropName( bYError ? C2U("ErrorBarY") : C2U("ErrorBarX")); if ( xSeriesProp.is()) xSeriesProp->getPropertyValue( aPropName ) >>= xErrorBar; return xErrorBar; } bool StatisticsHelper::hasErrorBars( const Reference< chart2::XDataSeries > & xDataSeries, bool bYError /* = true */ ) { Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError )); sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE; return ( xErrorBar.is() && ( xErrorBar->getPropertyValue( C2U("ErrorBarStyle")) >>= nStyle ) && nStyle != ::com::sun::star::chart::ErrorBarStyle::NONE ); } void StatisticsHelper::removeErrorBars( const Reference< chart2::XDataSeries > & xDataSeries, bool bYError /* = true */ ) { Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError )); if ( xErrorBar.is()) xErrorBar->setPropertyValue( C2U("ErrorBarStyle"), uno::makeAny( ::com::sun::star::chart::ErrorBarStyle::NONE )); } bool StatisticsHelper::usesErrorBarRanges( const Reference< chart2::XDataSeries > & xDataSeries, bool bYError /* = true */ ) { Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError )); sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE; return ( xErrorBar.is() && ( xErrorBar->getPropertyValue( C2U("ErrorBarStyle")) >>= nStyle ) && nStyle == ::com::sun::star::chart::ErrorBarStyle::FROM_DATA ); } } // namespace chart /* vim:set shiftwidth=4 softtabstop=4 expandtab: */