initial version work
This commit is contained in:
Родитель
1ebc78a83b
Коммит
8b5efa2caa
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 697 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 63 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 7.8 KiB |
|
@ -0,0 +1,699 @@
|
|||
{
|
||||
"dataRoles": [
|
||||
{
|
||||
"displayName": "Date",
|
||||
"description": "Equally spaced date values",
|
||||
"kind": "Grouping",
|
||||
"name": "Date"
|
||||
},
|
||||
{
|
||||
"displayName": "Value",
|
||||
"description": "Numeric variable",
|
||||
"kind": "Measure",
|
||||
"name": "Value"
|
||||
}
|
||||
],
|
||||
"dataViewMappings": [
|
||||
{
|
||||
"conditions": [
|
||||
{
|
||||
"Date": {
|
||||
"max": 1
|
||||
},
|
||||
"Value": {
|
||||
"max": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"scriptResult": {
|
||||
"dataInput": {
|
||||
"table": {
|
||||
"rows": {
|
||||
"select": [
|
||||
{
|
||||
"for": {
|
||||
"in": "Date"
|
||||
}
|
||||
},
|
||||
{
|
||||
"for": {
|
||||
"in": "Value"
|
||||
}
|
||||
}
|
||||
],
|
||||
"dataReductionAlgorithm": {
|
||||
"top": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"script": {
|
||||
"scriptProviderDefault": "R",
|
||||
"scriptOutputType": "png",
|
||||
"source": {
|
||||
"objectName": "rcv_script",
|
||||
"propertyName": "source"
|
||||
},
|
||||
"provider": {
|
||||
"objectName": "rcv_script",
|
||||
"propertyName": "provider"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"objects": {
|
||||
"rcv_script": {
|
||||
"properties": {
|
||||
"provider": {
|
||||
"type": {
|
||||
"text": true
|
||||
}
|
||||
},
|
||||
"source": {
|
||||
"type": {
|
||||
"scripting": {
|
||||
"source": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings_forecastPlot_params": {
|
||||
"displayName": "Forecasting settings",
|
||||
"description": "All common ARIMA models are provided; if one of the seasonal models is selected, it will be used instead of the non-seasonal model",
|
||||
"properties": {
|
||||
"forecastLength": {
|
||||
"displayName": "Forecast length",
|
||||
"description": "Number of data points to predict",
|
||||
"type": {
|
||||
"numeric": true
|
||||
}
|
||||
},
|
||||
"confInterval1": {
|
||||
"displayName": "Confidence level",
|
||||
"description": "Select first confidence interval",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "0.2",
|
||||
"value": "0.2"
|
||||
},
|
||||
{
|
||||
"displayName": "0.4",
|
||||
"value": "0.4"
|
||||
},
|
||||
{
|
||||
"displayName": "0.5",
|
||||
"value": "0.5"
|
||||
},
|
||||
{
|
||||
"displayName": "0.75",
|
||||
"value": "0.75"
|
||||
},
|
||||
{
|
||||
"displayName": "0.8",
|
||||
"value": "0.8"
|
||||
},
|
||||
{
|
||||
"displayName": "0.9",
|
||||
"value": "0.9"
|
||||
},
|
||||
{
|
||||
"displayName": "0.95",
|
||||
"value": "0.95"
|
||||
},
|
||||
{
|
||||
"displayName": "0.975",
|
||||
"value": "0.975"
|
||||
},
|
||||
{
|
||||
"displayName": "0.98",
|
||||
"value": "0.98"
|
||||
},
|
||||
{
|
||||
"displayName": "0.99",
|
||||
"value": "0.99"
|
||||
},
|
||||
{
|
||||
"displayName": "0.995",
|
||||
"value": "0.995"
|
||||
},
|
||||
{
|
||||
"displayName": "0.999",
|
||||
"value": "0.999"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"confInterval2": {
|
||||
"displayName": "Confidence level #2",
|
||||
"description": "Select additional confidence interval",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "0.2",
|
||||
"value": "0.2"
|
||||
},
|
||||
{
|
||||
"displayName": "0.4",
|
||||
"value": "0.4"
|
||||
},
|
||||
{
|
||||
"displayName": "0.5",
|
||||
"value": "0.5"
|
||||
},
|
||||
{
|
||||
"displayName": "0.75",
|
||||
"value": "0.75"
|
||||
},
|
||||
{
|
||||
"displayName": "0.8",
|
||||
"value": "0.8"
|
||||
},
|
||||
{
|
||||
"displayName": "0.9",
|
||||
"value": "0.9"
|
||||
},
|
||||
{
|
||||
"displayName": "0.95",
|
||||
"value": "0.95"
|
||||
},
|
||||
{
|
||||
"displayName": "0.975",
|
||||
"value": "0.975"
|
||||
},
|
||||
{
|
||||
"displayName": "0.98",
|
||||
"value": "0.98"
|
||||
},
|
||||
{
|
||||
"displayName": "0.99",
|
||||
"value": "0.99"
|
||||
},
|
||||
{
|
||||
"displayName": "0.995",
|
||||
"value": "0.995"
|
||||
},
|
||||
{
|
||||
"displayName": "0.999",
|
||||
"value": "0.999"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings_seasonality_params": {
|
||||
"displayName": "Seasonality",
|
||||
"properties": {
|
||||
"show": {
|
||||
"type": {
|
||||
"bool": true
|
||||
}
|
||||
},
|
||||
"targetSeason": {
|
||||
"displayName": "Target seasonal factor",
|
||||
"description": "Specify, if time series is influenced by known seasonal factors. The the number of observations per season is limited by 24. Non compatible seasonality will be ignored",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "automatic",
|
||||
"value": "automatic"
|
||||
},
|
||||
{
|
||||
"displayName": "manual",
|
||||
"value": "manual"
|
||||
},
|
||||
{
|
||||
"displayName": "hour",
|
||||
"value": "hour"
|
||||
},
|
||||
{
|
||||
"displayName": "day",
|
||||
"value": "day"
|
||||
},
|
||||
{
|
||||
"displayName": "week",
|
||||
"value": "week"
|
||||
},
|
||||
{
|
||||
"displayName": "month",
|
||||
"value": "month"
|
||||
},
|
||||
{
|
||||
"displayName": "quater",
|
||||
"value": "quater"
|
||||
},
|
||||
{
|
||||
"displayName": "year",
|
||||
"value": "year"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"knownFrequency": {
|
||||
"displayName": "Seasonality frequency",
|
||||
"description": "Specify, if time series is influenced by known seasonal factors of known length. The units are in number of observations",
|
||||
"type": {
|
||||
"numeric": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings_model_params": {
|
||||
"displayName": "Model Customization",
|
||||
"properties": {
|
||||
"maxp": {
|
||||
"displayName": "Maximal p",
|
||||
"description": "The maximal order of the autoregressive component",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"displayName": "3",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxq": {
|
||||
"displayName": "Maximal q",
|
||||
"description": "The maximal order of the moving average component",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"displayName": "3",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxP": {
|
||||
"displayName": "Maximal P",
|
||||
"description": "The maximal order of the seasonal autoregressive component",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"displayName": "3",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxQ": {
|
||||
"displayName": "Maximal Q",
|
||||
"description": "The maximal order of the seasonal moving average component",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"displayName": "3",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxd": {
|
||||
"displayName": "Maximal d",
|
||||
"description": "The maximal degree of differencing",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxD": {
|
||||
"displayName": "Maximal D",
|
||||
"description": "The maximal degree of seasonal differencing",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"allowDrift": {
|
||||
"displayName": "Allow drift",
|
||||
"description": "Should the ARIMA model include a linear drift term?",
|
||||
"type": {
|
||||
"bool": true
|
||||
}
|
||||
},
|
||||
"allowMean": {
|
||||
"displayName": "Allow mean",
|
||||
"description": "Should the ARIMA model include a mean term?",
|
||||
"type": {
|
||||
"bool": true
|
||||
}
|
||||
},
|
||||
"fullEnumeration": {
|
||||
"displayName": "Full enumeration (slow)",
|
||||
"description": "If FALSE, will do stepwise selection (faster). Otherwise, it searches over all models (can be very slow).",
|
||||
"type": {
|
||||
"bool": true
|
||||
}
|
||||
},
|
||||
"boxCoxTransform": {
|
||||
"displayName": "Box-Cox transformation",
|
||||
"description": "A family of transformations that includes logarithms and power transformations. Depends on the parameter `lambda`. Recommended if the data show variation that increases or decreases with the level of the series",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "off",
|
||||
"value": "off"
|
||||
},
|
||||
{
|
||||
"displayName": "automatic",
|
||||
"value": "automatic"
|
||||
},
|
||||
{
|
||||
"displayName": "manual",
|
||||
"value": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"lambda": {
|
||||
"displayName": "lambda",
|
||||
"description": "Box-Cox transformation parameter",
|
||||
"type": {
|
||||
"numeric": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings_userModel_params": {
|
||||
"displayName": "User defined model",
|
||||
"properties": {
|
||||
"show": {
|
||||
"type": {
|
||||
"bool": true
|
||||
}
|
||||
},
|
||||
"p": {
|
||||
"displayName": "p",
|
||||
"description": "The order of the autoregressive component",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"displayName": "3",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"q": {
|
||||
"displayName": "q",
|
||||
"description": "The order of the moving average component",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"displayName": "3",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"P": {
|
||||
"displayName": "P",
|
||||
"description": "The order of the seasonal autoregressive component",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"displayName": "3",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Q": {
|
||||
"displayName": "Q",
|
||||
"description": "The order of the seasonal moving average component",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"displayName": "3",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"d": {
|
||||
"displayName": "d",
|
||||
"description": "The degree of differencing",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"D": {
|
||||
"displayName": "D",
|
||||
"description": "The degree of seasonal differencing",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "0",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"displayName": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"displayName": "2",
|
||||
"value": "2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings_graph_params": {
|
||||
"displayName": "Graphical parameters",
|
||||
"properties": {
|
||||
"dataCol": {
|
||||
"displayName": "History data color",
|
||||
"type": {
|
||||
"fill": {
|
||||
"solid": {
|
||||
"color": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"forecastCol": {
|
||||
"displayName": "Forecast data color",
|
||||
"type": {
|
||||
"fill": {
|
||||
"solid": {
|
||||
"color": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"percentile": {
|
||||
"displayName": "Opacity",
|
||||
"type": {
|
||||
"numeric": true
|
||||
}
|
||||
},
|
||||
"weight": {
|
||||
"displayName": "Line width",
|
||||
"type": {
|
||||
"numeric": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings_additional_params": {
|
||||
"displayName": "Info and warnings",
|
||||
"properties": {
|
||||
"show": {
|
||||
"type": {
|
||||
"bool": true
|
||||
}
|
||||
},
|
||||
"textSize": {
|
||||
"displayName": "Font size",
|
||||
"description": "Font size used to show information",
|
||||
"type": {
|
||||
"numeric": true
|
||||
}
|
||||
},
|
||||
"textColor": {
|
||||
"displayName": "Text color",
|
||||
"description": "Color used to show information",
|
||||
"type": {
|
||||
"fill": {
|
||||
"solid": {
|
||||
"color": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"infoCriteria": {
|
||||
"displayName": "Output information criteria",
|
||||
"description": "Used only for info, does not influence the results. Select one option: Akaike's Information Criterion (AIC), Corrected Akaike's Information Criterion (AICc), or Schwarz's Bayesian Information Criterion (BIC) ",
|
||||
"type": {
|
||||
"enumeration": [
|
||||
{
|
||||
"displayName": "none",
|
||||
"value": "none"
|
||||
},
|
||||
{
|
||||
"displayName": "AIC",
|
||||
"value": "AIC"
|
||||
},
|
||||
{
|
||||
"displayName": "BIC",
|
||||
"value": "BIC"
|
||||
},
|
||||
{
|
||||
"displayName": "AICc",
|
||||
"value": "AICc"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"suppressDefaultTitle": true
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"cranPackages": [
|
||||
{
|
||||
"name": "zoo",
|
||||
"displayName": "zoo: S3 Infrastructure for Regular and Irregular Time Series",
|
||||
"url": "https://cran.r-project.org/web/packages/zoo/index.html"
|
||||
},
|
||||
{
|
||||
"name": "scales",
|
||||
"displayName": "scales: Scale Functions for Visualization",
|
||||
"url": "https://cran.r-project.org/web/packages/scales/index.html"
|
||||
},
|
||||
{
|
||||
"name": "reshape2",
|
||||
"displayName": "reshape2: Flexibly Reshape Data: A Reboot of the Reshape Package",
|
||||
"url": "https://cran.r-project.org/web/packages/reshape2/index.html"
|
||||
},
|
||||
{
|
||||
"name": "forecast",
|
||||
"displayName": "forecast: Forecasting Functions for Time Series and Linear Models",
|
||||
"url": "https://cran.r-project.org/web/packages/forecast/index.html"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"name": "visual"
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"visual": {
|
||||
"name": "PowerBI-visuals-forcasting-ARIMA_WORK",
|
||||
"displayName": "Forecasting with ARIMA_WORK",
|
||||
"guid": "PBI_CV_AD348DC9_41C4_4867_B19O_53F9RDC6IEAS_WORK",
|
||||
"visualClassName": "Visual",
|
||||
"version": "1.0.0",
|
||||
"description": "<span>Time series forecasting is the use of a model to predict future values based on previously observed values. Current visual implements well known Autoregressive Integrated Moving Average (ARIMA) method for the forecasting. Both seasonal and non-seasonal modeling is supported. You can control the algorithm parameters and the visual attributes to suit your needs.<br/><br/><span style='font-style:italic'>Service prerequisites:</span> R-powered custom visual is used in service seamlessly<br/><br /><span style='font-style:italic'>Desktop prerequisites:</span> To run R scripts in Power BI Desktop, you must separately install R on your local computer.<br />You can download and install R for free from the <a href='https://mran.revolutionanalytics.com/download/'>Revolution Open download page</a> or the <a href='https://cran.r-project.org/bin/windows/base/'>CRAN Repository</a><br /><br /> <span style='font-style:italic'> R package dependencies(auto-installed): </span> graphics, scales, forecast, zoo <br /><br /> <span style='font-style:italic'> Supports R versions: </span> R 3.3.1, R 3.3.0, MRO 3.3.1, MRO 3.3.0, MRO 3.2.2 <br /></span>",
|
||||
"supportUrl": "http://community.powerbi.com/",
|
||||
"gitHubUrl": "https://github.com/microsoft/PowerBI-visuals-forcasting-ARIMA"
|
||||
},
|
||||
"apiVersion": "1.2.0",
|
||||
"author": {
|
||||
"name": "Microsoft",
|
||||
"email": "pbicvsupport@microsoft.com"
|
||||
},
|
||||
"assets": {
|
||||
"icon": "assets/icon.png"
|
||||
},
|
||||
"externalJS": [],
|
||||
"style": "style/visual.less",
|
||||
"capabilities": "capabilities.json",
|
||||
"dependencies": "dependencies.json"
|
||||
}
|
|
@ -0,0 +1,604 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
# Third Party Programs. This software enables you to obtain software applications from other sources.
|
||||
# Those applications are offered and distributed by third parties under their own license terms.
|
||||
# Microsoft is not developing, distributing or licensing those applications to you, but instead,
|
||||
# as a convenience, enables you to use this software to obtain those applications directly from
|
||||
# the application providers.
|
||||
# By using the software, you acknowledge and agree that you are obtaining the applications directly
|
||||
# from the third party providers and under separate license terms, and that it is your responsibility to locate,
|
||||
# understand and comply with those license terms.
|
||||
# Microsoft grants you no license rights for third-party software or applications that is obtained using this software.
|
||||
|
||||
#
|
||||
# WARNINGS:
|
||||
#
|
||||
# CREATION DATE: 24/7/2016
|
||||
#
|
||||
# LAST UPDATE: 18/01/2017
|
||||
#
|
||||
# VERSION: 1.0.0
|
||||
#
|
||||
# R VERSION TESTED: 3.3.1
|
||||
#
|
||||
# AUTHOR: pbicvsupport@microsoft.com
|
||||
#
|
||||
# REFERENCES: https://en.wikipedia.org/wiki/Autoregressive_integrated_moving_average, https://www.otexts.org/fpp/8
|
||||
|
||||
|
||||
|
||||
Sys.setlocale("LC_ALL","English") # internationalization
|
||||
|
||||
#For DEBUG uses:
|
||||
#save(list = ls(all.names = TRUE), file='c:/Users/boefraty/Temp/tempData.Rda')
|
||||
load(file='c:/Users/boefraty/Temp/tempData.Rda')
|
||||
|
||||
|
||||
############ User Parameters #########
|
||||
|
||||
|
||||
##PBI_PARAM: Should warnings text be displayed?
|
||||
#Type:logical, Default:TRUE, Range:NA, PossibleValues:NA, Remarks: NA
|
||||
showWarnings = TRUE
|
||||
|
||||
##PBI_PARAM: Should additional info about the forcasting method be displayed?
|
||||
#Type:logical, Default:TRUE, Range:NA, PossibleValues:NA, Remarks: NA
|
||||
showInfo=TRUE
|
||||
if(exists("settings_additional_params_show"))
|
||||
showInfo = settings_additional_params_show
|
||||
|
||||
|
||||
infoCriteria = "none"
|
||||
if(exists("settings_additional_params_infoCriteria"))
|
||||
infoCriteria = settings_additional_params_infoCriteria
|
||||
|
||||
##PBI_PARAM: Forecast length
|
||||
#Type:integer, Default:NULL, Range:NA, PossibleValues:NA, Remarks: NULL means choose forecast length automatically
|
||||
forecastLength=10
|
||||
if(exists("settings_forecastPlot_params_forecastLength"))
|
||||
{
|
||||
forecastLength = as.numeric(settings_forecastPlot_params_forecastLength)
|
||||
if(is.na(forecastLength))
|
||||
forecastLength = 10
|
||||
forecastLength = round(max(min(forecastLength,1e+6),1))
|
||||
}
|
||||
|
||||
confInterval1 = 0.85
|
||||
if(exists("settings_forecastPlot_params_confInterval1"))
|
||||
{
|
||||
confInterval1 = as.numeric(settings_forecastPlot_params_confInterval1)
|
||||
}
|
||||
confInterval2 = 0.95
|
||||
if(exists("settings_forecastPlot_params_confInterval2"))
|
||||
{
|
||||
confInterval2 = as.numeric(settings_forecastPlot_params_confInterval2)
|
||||
}
|
||||
if(confInterval1 > confInterval2)
|
||||
{#switch
|
||||
temp = confInterval1
|
||||
confInterval1 = confInterval2
|
||||
confInterval2 = temp
|
||||
}
|
||||
|
||||
|
||||
withSeasonality = TRUE
|
||||
if(exists("settings_seasonality_params_show"))
|
||||
withSeasonality = settings_seasonality_params_show
|
||||
|
||||
|
||||
##PBI_PARAM target Season
|
||||
#Type: string, Default:"Automatic", Range:NA, PossibleValues:"Automatic","Hour","Day","Week", ...
|
||||
targetSeason = "automatic"
|
||||
if(exists("settings_seasonality_params_targetSeason"))
|
||||
targetSeason = settings_seasonality_params_targetSeason
|
||||
|
||||
knownFrequency = 12
|
||||
if(exists("settings_seasonality_params_knownFrequency"))
|
||||
knownFrequency = min(1000000,max(2,settings_seasonality_params_knownFrequency))
|
||||
|
||||
|
||||
maxp = 3
|
||||
if(exists("settings_model_params_maxp"))
|
||||
maxp = as.numeric(settings_model_params_maxp)
|
||||
|
||||
maxq = 3
|
||||
if(exists("settings_model_params_maxq"))
|
||||
maxq = as.numeric(settings_model_params_maxq)
|
||||
|
||||
maxd = 2
|
||||
if(exists("settings_model_params_maxd"))
|
||||
maxd = as.numeric(settings_model_params_maxd)
|
||||
|
||||
maxP = 3
|
||||
if(exists("settings_model_params_maxP"))
|
||||
maxP = as.numeric(settings_model_params_maxP)
|
||||
|
||||
maxQ = 3
|
||||
if(exists("settings_model_params_maxQ"))
|
||||
maxQ = as.numeric(settings_model_params_maxQ)
|
||||
|
||||
maxD = 2
|
||||
if(exists("settings_model_params_maxD"))
|
||||
maxD = as.numeric(settings_model_params_maxD)
|
||||
|
||||
allowDrift = FALSE
|
||||
if(exists("settings_model_params_allowDrift"))
|
||||
allowDrift = (settings_model_params_allowDrift)
|
||||
|
||||
allowMean = FALSE
|
||||
if(exists("settings_model_params_allowMean"))
|
||||
allowMean = settings_model_params_allowMean
|
||||
|
||||
fullEnumeration = FALSE
|
||||
if(exists("settings_model_params_fullEnumeration"))
|
||||
fullEnumeration = settings_model_params_fullEnumeration
|
||||
|
||||
|
||||
boxCoxTransform = "off"
|
||||
if(exists("settings_model_params_boxCoxTransform"))
|
||||
boxCoxTransform = settings_model_params_boxCoxTransform
|
||||
|
||||
lambda = 0
|
||||
if(exists("settings_model_params_lambda"))
|
||||
lambda = max(-1,min(settings_model_params_lambda,2))
|
||||
|
||||
userModel = FALSE
|
||||
if(exists("settings_userModel_params_show"))
|
||||
userModel = settings_userModel_params_show
|
||||
|
||||
|
||||
p = 3
|
||||
if(exists("settings_userModel_params_p"))
|
||||
p = as.numeric(settings_userModel_params_p)
|
||||
|
||||
q = 3
|
||||
if(exists("settings_userModel_params_q"))
|
||||
q = as.numeric(settings_userModel_params_q)
|
||||
|
||||
d = 2
|
||||
if(exists("settings_userModel_params_d"))
|
||||
d = as.numeric(settings_userModel_params_d)
|
||||
|
||||
P = 3
|
||||
if(exists("settings_userModel_params_P"))
|
||||
P = as.numeric(settings_userModel_params_P)
|
||||
|
||||
Q = 3
|
||||
if(exists("settings_userModel_params_Q"))
|
||||
Q = as.numeric(settings_userModel_params_Q)
|
||||
|
||||
D = 2
|
||||
if(exists("settings_userModel_params_D"))
|
||||
D = as.numeric(settings_userModel_params_D)
|
||||
|
||||
lowerConfInterval = confInterval1
|
||||
upperConfInterval = confInterval2
|
||||
|
||||
###############Library Declarations###############
|
||||
|
||||
libraryRequireInstall = function(packageName, ...)
|
||||
{
|
||||
if(!require(packageName, character.only = TRUE))
|
||||
warning(paste("*** The package: '", packageName, "' was not installed ***",sep=""))
|
||||
}
|
||||
|
||||
|
||||
libraryRequireInstall("scales")
|
||||
libraryRequireInstall("forecast")
|
||||
libraryRequireInstall("zoo")
|
||||
|
||||
###############Internal parameters definitions#################
|
||||
|
||||
#PBI_PARAM Minimal number of points
|
||||
#Type:integer, Default:10, Range:[0,], PossibleValues:NA, Remarks: NA
|
||||
minPoints = 10
|
||||
|
||||
##PBI_PARAM Color of time series line
|
||||
#Type:string, Default:"orange", Range:NA, PossibleValues:"orange","blue","green","black"
|
||||
pointsCol = "blue"
|
||||
if(exists("settings_graph_params_dataCol"))
|
||||
pointsCol = settings_graph_params_dataCol
|
||||
|
||||
##PBI_PARAM Color of forecast line
|
||||
#Type:string, Default:"red", Range:NA, PossibleValues:"red","blue","green","black"
|
||||
forecastCol = "orange"
|
||||
if(exists("settings_graph_params_forecastCol"))
|
||||
forecastCol = settings_graph_params_forecastCol
|
||||
|
||||
#PBI_PARAM Transparency of scatterplot points
|
||||
#Type:numeric, Default:0.4, Range:[0,1], PossibleValues:NA, Remarks: NA
|
||||
transparency = 1
|
||||
if(exists("settings_graph_params_percentile"))
|
||||
transparency = as.numeric(settings_graph_params_percentile)/100
|
||||
|
||||
#PBI_PARAM Shaded band for confidence interval
|
||||
#Type:logical, Default:TRUE, Range:NA, PossibleValues:NA, Remarks: NA
|
||||
fillConfidenceLevels=TRUE
|
||||
|
||||
#PBI_PARAM Size of points on the plot
|
||||
#Type:numeric, Default: 1 , Range:[0.1,5], PossibleValues:NA, Remarks: NA
|
||||
pointCex = 1
|
||||
if(exists("settings_graph_params_weight"))
|
||||
pointCex = as.numeric(settings_graph_params_weight)/10
|
||||
|
||||
#PBI_PARAM Size of subtitle on the plot
|
||||
#Type:numeric, Default: 0.75 , Range:[0.1,5], PossibleValues:NA, Remarks: NA
|
||||
cexSub = 0.75
|
||||
if(exists("settings_additional_params_textSize"))
|
||||
cexSub = as.numeric(settings_additional_params_textSize)/12
|
||||
|
||||
|
||||
infoTextColor = "gray"
|
||||
if(exists("settings_additional_params_textColor"))
|
||||
infoTextColor = settings_additional_params_textColor
|
||||
|
||||
|
||||
|
||||
###############Internal functions definitions#################
|
||||
|
||||
# tiny function to deal with verl long strings on plot
|
||||
cutStr2Show = function(strText, strCex = 0.8, abbrTo = 100, isH = TRUE, maxChar = 3, partAvailable = 1)
|
||||
{
|
||||
# partAvailable, wich portion of window is available, in [0,1]
|
||||
if(is.null(strText))
|
||||
return (NULL)
|
||||
|
||||
SCL = 0.075*strCex/0.8
|
||||
pardin = par()$din
|
||||
gStand = partAvailable*(isH*pardin[1]+(1-isH)*pardin[2]) /SCL
|
||||
|
||||
# if very very long abbreviate
|
||||
if(nchar(strText)>abbrTo && nchar(strText)> 1)
|
||||
strText = abbreviate(strText, abbrTo)
|
||||
|
||||
# if looooooong convert to lo...
|
||||
if(nchar(strText)>round(gStand) && nchar(strText)> 1)
|
||||
strText = paste(substring(strText,1,floor(gStand)),"...",sep="")
|
||||
|
||||
# if shorter than maxChar remove
|
||||
if(gStand<=maxChar)
|
||||
strText = NULL
|
||||
|
||||
return(strText)
|
||||
}
|
||||
|
||||
|
||||
# Find number of ticks on X axis
|
||||
FindTicksNum = function(n,f)
|
||||
{
|
||||
tn = 10 # default minimum
|
||||
D = 2 # tick/inch
|
||||
numCircles = n/f
|
||||
xSize = par()$din[1]
|
||||
tn = max(round(xSize*D),tn)
|
||||
return(tn)
|
||||
}
|
||||
|
||||
#format labels on X-axis automatically
|
||||
flexFormat = function(dates, orig_dates, freq = 1, myformat = NULL)
|
||||
{
|
||||
|
||||
days=(as.numeric(difftime(dates[length(dates)],dates[1]),units="days"))
|
||||
months = days/30
|
||||
years = days/365.25
|
||||
|
||||
|
||||
constHour = length(unique(orig_dates$hour))==1
|
||||
constMin = length(unique(orig_dates$min))==1
|
||||
constSec = length(unique(orig_dates$sec))==1
|
||||
constMon = length(unique(orig_dates$mon))==1
|
||||
|
||||
timeChange = any(!constHour,!constMin,!constSec)
|
||||
|
||||
if(is.null(myformat))
|
||||
{
|
||||
if(years > 10){
|
||||
if(constMon)
|
||||
{
|
||||
myformat = "%Y" #many years => only year :2001
|
||||
}else{
|
||||
myformat = "%m/%y" #many years + months :12/01
|
||||
}
|
||||
}else{
|
||||
if(years > 1 && N < 50){
|
||||
myformat = "%b %d, %Y" #several years, few samples:Jan 01, 2010
|
||||
}else{
|
||||
if(years > 1){
|
||||
myformat = "%m/%d/%y" #several years, many samples: 01/20/10
|
||||
}else{
|
||||
if(years <= 1 && !timeChange)
|
||||
myformat = "%b %d" #1 year,no time: Jan 01
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(is.null(myformat) && timeChange)
|
||||
if(years>1){
|
||||
myformat = "%m/%d/%y %H:%M" # 01/20/10 12:00
|
||||
}else{
|
||||
if(days>1){
|
||||
myformat = "%b %d, %H:%M" # Jan 01 12:00
|
||||
}else{
|
||||
if(days<=1){
|
||||
myformat = "%H:%M" # Jan 01 12:00
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!is.null(myformat)){
|
||||
if(myformat == "%Y,Q%q")
|
||||
dates = as.yearqtr(dates)
|
||||
dates1= format(dates, myformat)
|
||||
}else{
|
||||
dates1 = as.character(1:length(dates)) # just id
|
||||
}
|
||||
return(dates1)
|
||||
}
|
||||
|
||||
|
||||
# verify if "perSeason" is good for "frequency" parameter
|
||||
freqSeason1 = function(seasons,perSeason)
|
||||
{
|
||||
if((seasons > 5 && perSeason > 3) || (seasons > 2 && perSeason > 7))
|
||||
return (perSeason)
|
||||
|
||||
return(1)
|
||||
}
|
||||
|
||||
|
||||
# find frequency using the dates, targetS is a "recommended" seasonality
|
||||
findFreqFromDates1 = function(dates, targetS = "Automatic")
|
||||
{
|
||||
freq = 1
|
||||
N = length(dates)
|
||||
nnn = c("hour", "day", "week", "month", "quater", "year")
|
||||
seasons = rep(NaN,6)
|
||||
names(seasons) = nnn
|
||||
perSeason = seasons
|
||||
|
||||
seasons["day"]=round(as.numeric(difftime(dates[length(dates)],dates[1]),units="days"))
|
||||
seasons["hour"]=round(as.numeric(difftime(dates[length(dates)],dates[1]),units="hours"))
|
||||
seasons["week"]=round(as.numeric(difftime(dates[length(dates)],dates[1]),units="weeks"))
|
||||
seasons["month"] = seasons["day"]/30
|
||||
seasons["year"] = seasons["day"]/365.25
|
||||
seasons["quater"] = seasons["year"]*4
|
||||
|
||||
perSeason = N/seasons
|
||||
|
||||
if(targetS!="automatic") # target
|
||||
freq = perSeason[targetS]
|
||||
|
||||
if(freq < 2) # if TRUE, target season factor is not good
|
||||
freq = 1
|
||||
|
||||
for( s in rev(nnn)) # check year --> Quater --> etc
|
||||
if(freq == 1 )
|
||||
freq = freqSeason1(seasons[s],perSeason[s])
|
||||
|
||||
return(round(freq))
|
||||
}
|
||||
|
||||
#get valid frequency parameter, based on input from user
|
||||
getFrequency1 = function(parsed_dates, values, tS, f)
|
||||
{
|
||||
myFreq = f
|
||||
grp = c("automatic","none","manual")
|
||||
|
||||
if(!(tS %in% c("autodetect from value","none","manual"))) #detect from date
|
||||
{
|
||||
myFreq = findFreqFromDates1(parsed_dates, targetS = tS)
|
||||
}else{
|
||||
if(tS == "none")
|
||||
{ myFreq = 1}
|
||||
else
|
||||
{# NOT YET IMPLEMENTED
|
||||
# if(tS == "autodetect from value")
|
||||
# myFreq = freqFromValue1(values)
|
||||
}
|
||||
}
|
||||
numPeriods = floor(length(values)/myFreq)
|
||||
if(numPeriods< 2)
|
||||
myFreq = findFreqFromDates1(parsed_dates, targetS = "automatic")
|
||||
return(myFreq)
|
||||
}
|
||||
|
||||
#format info string
|
||||
GetFitMethodString = function(fit,withSeasonality, infoCriteria = "none")
|
||||
{
|
||||
|
||||
arma = fit$arma
|
||||
|
||||
resString = as.character(arimaorder(fit))
|
||||
|
||||
skey = c("p","d","q","P","D","Q", "m")
|
||||
skey = skey[1:length(resString)]
|
||||
skey = paste(skey, collapse = ",")
|
||||
|
||||
resString = paste("ARIMA: (",skey,") = (",paste(resString,collapse = ","),")",sep ="")
|
||||
# add more info
|
||||
if(infoCriteria != "none")
|
||||
{
|
||||
if(infoCriteria == "AIC")
|
||||
resString = paste(resString, "; AIC = ", as.character(round(fit$aic,2)), sep ="")
|
||||
else
|
||||
if(infoCriteria == "AICc")
|
||||
resString = paste(resString, "; AICc = ", as.character(round(fit$aicc,2)), sep ="")
|
||||
else
|
||||
if(infoCriteria == "BIC")
|
||||
resString = paste(resString, "; BIC = ", as.character(round(fit$bic,2)), sep ="")
|
||||
}
|
||||
|
||||
return(resString)
|
||||
|
||||
}
|
||||
|
||||
# find lambda for Box-Cox transform
|
||||
FindBoxCoxLambda = function(timeSeries, boxCoxTransform, lambda = NULL, mymethod = "loglik")
|
||||
{
|
||||
if(boxCoxTransform == "off")
|
||||
return(NULL)
|
||||
if(boxCoxTransform == "manual")
|
||||
return(lambda)
|
||||
if(boxCoxTransform == "automatic")
|
||||
lambda=BoxCox.lambda(timeSeries, method = mymethod, lower = -1, upper = 2)
|
||||
return (lambda)
|
||||
}
|
||||
|
||||
|
||||
|
||||
###############Upfront input correctness validations (where possible)#################
|
||||
pbiWarning = NULL
|
||||
|
||||
if(!exists("Date") || !exists("Value"))
|
||||
{
|
||||
dataset=data.frame()
|
||||
pbiWarning = cutStr2Show("Both 'Date' and 'Value' fields are required.", strCex = 0.85)
|
||||
timeSeries=ts()
|
||||
showWarnings=TRUE
|
||||
}else{
|
||||
dataset= cbind(Date,Value)
|
||||
dataset<-dataset[complete.cases(dataset),] #remove corrupted rows
|
||||
|
||||
labTime = "Time"
|
||||
labValue=names(dataset)[ncol(dataset)]
|
||||
|
||||
N=nrow(dataset)
|
||||
|
||||
|
||||
if(N==0 && exists("Date") && nrow(Date)>0 && exists("Value")){
|
||||
pbiWarning1 = cutStr2Show("Wrong date type. Only 'Date', 'Time', 'Date/Time' are allowed without hierarchy", strCex = 0.85)
|
||||
pbiWarning = paste(pbiWarning1, pbiWarning, sep ="\n")
|
||||
timeSeries=ts()
|
||||
showWarnings=TRUE
|
||||
}else {
|
||||
|
||||
|
||||
dataset = dataset[order(dataset[,1]),]
|
||||
parsed_dates=strptime(dataset[,1],"%Y-%m-%dT%H:%M:%S",tz="UTC")
|
||||
labTime = names(Date)[1]
|
||||
|
||||
if((any(is.na(parsed_dates))))
|
||||
{
|
||||
pbiWarning1 = cutStr2Show("Wrong or corrupted 'Date'.", strCex = 0.85)
|
||||
pbiWarning2 = cutStr2Show("Only 'Date', 'Time', 'Date/Time' types are allowed without hierarchy", strCex = 0.85)
|
||||
pbiWarning = paste(pbiWarning1, pbiWarning2, pbiWarning, sep ="\n")
|
||||
timeSeries=ts()
|
||||
showWarnings=TRUE
|
||||
}
|
||||
else
|
||||
{
|
||||
interval = difftime(parsed_dates[length(parsed_dates)],parsed_dates[1])/(length(parsed_dates)-1) # force equal spacing
|
||||
|
||||
if(withSeasonality==FALSE)
|
||||
targetSeason = "none"
|
||||
|
||||
myFreq = getFrequency1(parsed_dates, values = dataset[,2], tS = targetSeason, f = knownFrequency)
|
||||
|
||||
|
||||
if(myFreq < 2)
|
||||
withSeasonality = FALSE
|
||||
|
||||
if(withSeasonality == FALSE)
|
||||
{
|
||||
maxP = maxQ = maxD = P = Q = D = 0
|
||||
}
|
||||
|
||||
|
||||
timeSeries=ts(data = dataset[,2], start=1, frequency = round(myFreq))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
##############Main Visualization script###########
|
||||
|
||||
pbiInfo = NULL
|
||||
|
||||
if(length(timeSeries)>=minPoints) {
|
||||
|
||||
lambda = FindBoxCoxLambda(timeSeries, boxCoxTransform, lambda)
|
||||
|
||||
fit = NULL
|
||||
#if user model fails do auto.arima
|
||||
if(userModel)
|
||||
{
|
||||
result <- tryCatch({
|
||||
fit = suppressWarnings(Arima(timeSeries, order = c(p,d,q), seasonal = c(P,D,Q),
|
||||
include.mean=allowMean, include.drift=allowDrift,
|
||||
method = "ML", lambda=lambda))
|
||||
}, warning = function(war) {
|
||||
|
||||
# warning handler picks up where error was generated
|
||||
print(paste("MY_WARNING: ",war))
|
||||
return("Arima_warning")
|
||||
|
||||
}, error = function(err) {
|
||||
|
||||
# error handler picks up where error was generated
|
||||
print(paste("MY_ERROR: ",err))
|
||||
return("Arima_error")
|
||||
|
||||
}, finally = {
|
||||
|
||||
}) # END tryCatch
|
||||
|
||||
}
|
||||
|
||||
if(is.null(fit))
|
||||
fit = auto.arima(timeSeries, max.p = maxp, max.q = maxq, max.d = maxd,
|
||||
max.P = maxP, max.Q = maxQ, max.D = maxD,
|
||||
seasonal= withSeasonality,allowdrift=allowDrift, allowmean=allowMean, lambda=lambda,
|
||||
max.order=4, parallel = FALSE, stepwise = !fullEnumeration)
|
||||
|
||||
|
||||
|
||||
fit$method = GetFitMethodString(fit,withSeasonality, infoCriteria)
|
||||
if(lowerConfInterval==0)
|
||||
lowerConfInterval = NULL;
|
||||
prediction = forecast(fit, level=c(lowerConfInterval,upperConfInterval), h=forecastLength)
|
||||
|
||||
lastValue = tail(prediction$x,1)
|
||||
|
||||
prediction$mean=ts(c(lastValue,prediction$mean),
|
||||
frequency = frequency(prediction$mean),
|
||||
end=end(prediction$mean))
|
||||
#
|
||||
prediction$upper=rbind(c(lastValue,lastValue),prediction$upper)
|
||||
#
|
||||
prediction$lower=rbind(c(lastValue,lastValue),prediction$lower)
|
||||
|
||||
if(showInfo)
|
||||
{
|
||||
pbiInfo=paste(pbiInfo,"", fit$method, sep="")
|
||||
pbiInfo = cutStr2Show(pbiInfo,strCex = cexSub, isH = TRUE, maxChar = 20)
|
||||
}
|
||||
|
||||
labTime = cutStr2Show(labTime, strCex =1.1, isH = TRUE)
|
||||
labValue = cutStr2Show(labValue, strCex =1.1, isH = FALSE)
|
||||
|
||||
plot.forecast(prediction, lwd=pointCex, col=alpha(pointsCol,transparency), fcol=alpha(forecastCol,transparency), flwd = pointCex, shaded=fillConfidenceLevels,
|
||||
main = "", sub = pbiInfo, col.sub = infoTextColor, cex.sub = cexSub, xlab = labTime, ylab = labValue, xaxt = "n")
|
||||
|
||||
|
||||
NpF = (length(parsed_dates))+forecastLength
|
||||
freq = frequency(timeSeries)
|
||||
|
||||
#format x_with_f
|
||||
numTicks = FindTicksNum(NpF,freq) # find based on plot size
|
||||
|
||||
x_with_f = as.POSIXlt(seq(from=parsed_dates[1], to = (parsed_dates[1]+interval*(length(parsed_dates)+forecastLength)), length.out = numTicks))
|
||||
x_with_forcast_formatted = flexFormat(dates = x_with_f, orig_dates = parsed_dates, freq = freq)
|
||||
|
||||
correction = (NpF-1)/(numTicks-1) # needed due to subsampling of ticks
|
||||
axis(1, at = 1+correction*((0:(numTicks-1))/freq), labels = x_with_forcast_formatted)
|
||||
|
||||
|
||||
} else{ #empty plot
|
||||
plot.new()
|
||||
showWarnings = TRUE
|
||||
pbiWarning<-paste(pbiWarning, "Not enough data points", sep="\n")
|
||||
}
|
||||
|
||||
#add warning as subtitle
|
||||
if(showWarnings)
|
||||
title(main=NULL, sub=pbiWarning, outer=FALSE, col.sub = infoTextColor, cex.sub=cexSub)
|
|
@ -0,0 +1,156 @@
|
|||
module powerbi.extensibility.visual {
|
||||
/**
|
||||
* Gets property value for a particular object.
|
||||
*
|
||||
* @function
|
||||
* @param {DataViewObjects} objects - Map of defined objects.
|
||||
* @param {string} objectName - Name of desired object.
|
||||
* @param {string} propertyName - Name of desired property.
|
||||
* @param {T} defaultValue - Default value of desired property.
|
||||
*/
|
||||
export function getValue<T>(objects: DataViewObjects, objectName: string, propertyName: string, defaultValue: T ): T {
|
||||
if(objects) {
|
||||
let object = objects[objectName];
|
||||
if(object) {
|
||||
let property: T = <T>object[propertyName];
|
||||
if(property !== undefined) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets property value for a particular object.
|
||||
*
|
||||
* @function
|
||||
* @param {DataViewObjects} objects - Map of defined objects.
|
||||
* @param {string} objectName - Name of desired object.
|
||||
* @param {string} propertyName - Name of desired property.
|
||||
* @param {T} defaultValue - Default value of desired property.
|
||||
*/
|
||||
export function getValueMinMax<T>(objects: DataViewObjects, objectName: string, propertyName: string, defaultValue: T, minVal: T, maxVal: T ): T {
|
||||
if(objects) {
|
||||
let object = objects[objectName];
|
||||
if(object) {
|
||||
let property: T = <T>object[propertyName];
|
||||
if(property < minVal)
|
||||
{
|
||||
return minVal;
|
||||
}
|
||||
if(property > maxVal)
|
||||
{
|
||||
return maxVal;
|
||||
}
|
||||
if(property !== undefined) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets property value for a particular object.
|
||||
*
|
||||
* @function
|
||||
* @param {DataViewObjects} objects - Map of defined objects.
|
||||
* @param {string} objectName - Name of desired object.
|
||||
* @param {string} propertyName - Name of desired property.
|
||||
* @param {T} defaultValue - Default value of desired property.
|
||||
*/
|
||||
export function getValueNumberMinMax(objects: DataViewObjects, objectName: string, propertyName: string, defaultValue: number, minValue: number, maxValue: number ) {
|
||||
if(objects) {
|
||||
let object = objects[objectName];
|
||||
if(object) {
|
||||
let property = object[propertyName];
|
||||
if(property !== undefined) {
|
||||
if(property > maxValue)
|
||||
{
|
||||
return maxValue;
|
||||
}
|
||||
if(property < minValue)
|
||||
{
|
||||
return minValue;
|
||||
}
|
||||
return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets conditional property value for a particular object of type string
|
||||
*
|
||||
* @function
|
||||
* @param {string} inVal - current value of parameter
|
||||
* @param {string} contrVal - control value
|
||||
* @param {string} contrVal2Compare - specific string to be compared with contrVal
|
||||
* @param {boolean} logic - true / false "logic"
|
||||
* @param {string} outValIfCondTrue - output value if comparison (contrVal == contrVal2Compare) comes out as "logic"
|
||||
*/
|
||||
export function ifStringReturnString(inVal: string, contrVal: string, contrVal2Compare: string, outValIfCondTrue: string, logic: boolean, applyNow:boolean)
|
||||
{
|
||||
if(applyNow && contrVal == contrVal2Compare && logic == true)
|
||||
return outValIfCondTrue;
|
||||
|
||||
if(applyNow && contrVal != contrVal2Compare && logic == false)
|
||||
return outValIfCondTrue;
|
||||
|
||||
return inVal;
|
||||
}
|
||||
|
||||
export function ifStringReturnStringClustersMethod(numClustersMethods:string , numOfClusters:string)
|
||||
{
|
||||
if(numOfClusters!="auto")
|
||||
return "None"
|
||||
|
||||
if(numOfClusters=="auto" && numClustersMethods=="None")
|
||||
return "fast"
|
||||
|
||||
return numClustersMethods;
|
||||
}
|
||||
|
||||
export function inMinMax(a: number, mi: number, ma: number)
|
||||
{
|
||||
if(a<mi)
|
||||
return mi;
|
||||
if(a>ma)
|
||||
return ma;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets property value for a particular object in a category.
|
||||
*
|
||||
* @function
|
||||
* @param {DataViewCategoryColumn} category - List of category objects.
|
||||
* @param {number} index - Index of category object.
|
||||
* @param {string} objectName - Name of desired object.
|
||||
* @param {string} propertyName - Name of desired property.
|
||||
* @param {T} defaultValue - Default value of desired property.
|
||||
*/
|
||||
export function getCategoricalObjectValue<T>(category: DataViewCategoryColumn, index: number, objectName: string, propertyName: string, defaultValue: T): T {
|
||||
let categoryObjects = category.objects;
|
||||
|
||||
if(categoryObjects) {
|
||||
let categoryObject: DataViewObject = categoryObjects[index];
|
||||
if(categoryObject) {
|
||||
let object = categoryObject[objectName];
|
||||
if(object) {
|
||||
let property: T = <T>object[propertyName];
|
||||
if(property !== undefined) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* Power BI Visual CLI
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation
|
||||
* All rights reserved.
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the ""Software""), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
module powerbi.extensibility.visual {
|
||||
|
||||
interface VisualSettingsForecastPlotParams {
|
||||
show: boolean;
|
||||
forecastLength: number;
|
||||
confInterval1: string;
|
||||
confInterval2: string;
|
||||
}
|
||||
|
||||
interface VisualSettingsSeasonalityParams {
|
||||
show: boolean;
|
||||
targetSeason: string;
|
||||
knownFrequency: number;
|
||||
}
|
||||
|
||||
interface VisualSettingsModelParams {
|
||||
maxp: string;
|
||||
maxq: string;
|
||||
maxP: string;
|
||||
maxQ: string;
|
||||
maxd: string;
|
||||
maxD: string;
|
||||
allowDrift: boolean;
|
||||
allowMean: boolean;
|
||||
fullEnumeration: boolean;
|
||||
boxCoxTransform: string;
|
||||
lambda: number;
|
||||
}
|
||||
interface VisualSettingsUserModelParams {
|
||||
show: boolean;
|
||||
p: string;
|
||||
q: string;
|
||||
P: string;
|
||||
Q: string;
|
||||
d: string;
|
||||
D: string;
|
||||
}
|
||||
interface VisualGraphParams {
|
||||
show: boolean;
|
||||
dataCol: string;
|
||||
forecastCol: string;
|
||||
percentile: number;
|
||||
weight: number;
|
||||
}
|
||||
interface VisualAdditionalParams {
|
||||
show: boolean;
|
||||
textSize: number;
|
||||
textColor: string;
|
||||
infoCriteria: string;
|
||||
}
|
||||
|
||||
|
||||
export class Visual implements IVisual {
|
||||
private imageDiv: HTMLDivElement;
|
||||
private imageElement: HTMLImageElement;
|
||||
|
||||
private settings_forecastPlot_params: VisualSettingsForecastPlotParams;
|
||||
private settings_seasonality_params: VisualSettingsSeasonalityParams;
|
||||
private settings_model_params: VisualSettingsModelParams;
|
||||
private settings_userModel_params: VisualSettingsUserModelParams;
|
||||
private settings_graph_params: VisualGraphParams;
|
||||
private settings_additional_params: VisualAdditionalParams;
|
||||
|
||||
public constructor(options: VisualConstructorOptions) {
|
||||
this.imageDiv = document.createElement('div');
|
||||
this.imageDiv.className = 'rcv_autoScaleImageContainer';
|
||||
options.element.appendChild(this.imageDiv);
|
||||
|
||||
this.imageElement = document.createElement('img');
|
||||
this.imageElement.className = 'rcv_autoScaleImage';
|
||||
|
||||
this.imageDiv.appendChild(this.imageElement);
|
||||
|
||||
this.settings_forecastPlot_params = <VisualSettingsForecastPlotParams>{
|
||||
forecastLength: 10,
|
||||
confInterval1: "0.85",
|
||||
confInterval2: "0.95"
|
||||
};
|
||||
|
||||
this.settings_seasonality_params = <VisualSettingsSeasonalityParams>{
|
||||
show: true,
|
||||
targetSeason: "automatic",
|
||||
knownFrequency: 12,
|
||||
};
|
||||
|
||||
|
||||
this.settings_model_params = <VisualSettingsModelParams>{
|
||||
maxp: "3",
|
||||
maxq: "3",
|
||||
maxP: "3",
|
||||
maxQ: "3",
|
||||
maxd: "2",
|
||||
maxD: "2",
|
||||
allowDrift: true,
|
||||
allowMean: false,
|
||||
fullEnumeration: false,
|
||||
boxCoxTransform: "off",
|
||||
lambda: 0.1,
|
||||
}
|
||||
this.settings_userModel_params = <VisualSettingsUserModelParams>{
|
||||
show: false,
|
||||
p: "3",
|
||||
q: "3",
|
||||
P: "3",
|
||||
Q: "3",
|
||||
d: "2",
|
||||
D: "2",
|
||||
}
|
||||
|
||||
|
||||
this.settings_graph_params = <VisualGraphParams>{
|
||||
|
||||
dataCol: "blue",
|
||||
forecastCol: "orange",
|
||||
percentile: 40,
|
||||
weight: 10
|
||||
|
||||
};
|
||||
|
||||
this.settings_additional_params = <VisualAdditionalParams>{
|
||||
show: true,
|
||||
textSize: 10,
|
||||
textColor: "gray",
|
||||
infoCriteria: "none"
|
||||
};
|
||||
}
|
||||
|
||||
public update(options: VisualUpdateOptions) {
|
||||
let dataViews: DataView[] = options.dataViews;
|
||||
if (!dataViews || dataViews.length === 0)
|
||||
return;
|
||||
|
||||
let dataView: DataView = dataViews[0];
|
||||
if (!dataView || !dataView.metadata)
|
||||
return;
|
||||
|
||||
this.settings_forecastPlot_params = <VisualSettingsForecastPlotParams>{
|
||||
forecastLength: getValue<number>(dataView.metadata.objects, 'settings_forecastPlot_params', 'forecastLength', 10),
|
||||
confInterval1: getValue<string>(dataView.metadata.objects, 'settings_forecastPlot_params', 'confInterval1', "0.85"),
|
||||
confInterval2: getValue<string>(dataView.metadata.objects, 'settings_forecastPlot_params', 'confInterval2', "0.95")
|
||||
};
|
||||
|
||||
this.settings_seasonality_params = <VisualSettingsSeasonalityParams>{
|
||||
show: getValue<boolean>(dataView.metadata.objects, 'settings_seasonality_params', 'show', true),
|
||||
targetSeason: getValue<string>(dataView.metadata.objects, 'settings_seasonality_params', 'targetSeason', "year"),
|
||||
knownFrequency: getValue<number>(dataView.metadata.objects, 'settings_seasonality_params', 'knownFrequency', 12),
|
||||
|
||||
}
|
||||
|
||||
this.settings_model_params = <VisualSettingsModelParams>{
|
||||
maxp: getValue<string>(dataView.metadata.objects, 'settings_model_params', 'maxp', "3"),
|
||||
maxq: getValue<string>(dataView.metadata.objects, 'settings_model_params', 'maxq', "3"),
|
||||
maxP: getValue<string>(dataView.metadata.objects, 'settings_model_params', 'maxP', "3"),
|
||||
maxQ: getValue<string>(dataView.metadata.objects, 'settings_model_params', 'maxQ', "3"),
|
||||
maxd: getValue<string>(dataView.metadata.objects, 'settings_model_params', 'maxd', "2"),
|
||||
maxD: getValue<string>(dataView.metadata.objects, 'settings_model_params', 'maxD', "2"),
|
||||
allowDrift: getValue<boolean>(dataView.metadata.objects, 'settings_model_params', 'allowDrift', true),
|
||||
allowMean: getValue<boolean>(dataView.metadata.objects, 'settings_model_params', 'allowMean', false),
|
||||
fullEnumeration: getValue<boolean>(dataView.metadata.objects, 'settings_model_params', 'fullEnumeration', false),
|
||||
boxCoxTransform: getValue<string>(dataView.metadata.objects, 'settings_model_params', 'boxCoxTransform', "off"),
|
||||
lambda: getValue<number>(dataView.metadata.objects, 'settings_model_params', 'lambda', 0.1),
|
||||
}
|
||||
|
||||
this.settings_userModel_params = <VisualSettingsUserModelParams>{
|
||||
show: getValue<boolean>(dataView.metadata.objects, 'settings_userModel_params', 'show', false),
|
||||
p: getValue<string>(dataView.metadata.objects, 'settings_userModel_params', 'p', "3"),
|
||||
q: getValue<string>(dataView.metadata.objects, 'settings_userModel_params', 'q', "3"),
|
||||
P: getValue<string>(dataView.metadata.objects, 'settings_userModel_params', 'P', "3"),
|
||||
Q: getValue<string>(dataView.metadata.objects, 'settings_userModel_params', 'Q', "3"),
|
||||
d: getValue<string>(dataView.metadata.objects, 'settings_userModel_params', 'd', "2"),
|
||||
D: getValue<string>(dataView.metadata.objects, 'settings_userModel_params', 'D', "2"),
|
||||
}
|
||||
|
||||
this.settings_graph_params = <VisualGraphParams>{
|
||||
dataCol: getValue<string>(dataView.metadata.objects, 'settings_graph_params', 'dataCol', "blue"),
|
||||
forecastCol: getValue<string>(dataView.metadata.objects, 'settings_graph_params', 'forecastCol', "orange"),
|
||||
percentile: getValue<number>(dataView.metadata.objects, 'settings_graph_params', 'percentile', 40),
|
||||
weight: getValue<number>(dataView.metadata.objects, 'settings_graph_params', 'weight', 10),
|
||||
}
|
||||
|
||||
this.settings_additional_params = <VisualAdditionalParams>{
|
||||
show: getValue<boolean>(dataView.metadata.objects, 'settings_additional_params', 'show', true),
|
||||
textSize: getValue<number>(dataView.metadata.objects, 'settings_additional_params', 'textSize', 10),
|
||||
textColor: getValue<string>(dataView.metadata.objects, 'settings_additional_params', 'textColor', "gray"),
|
||||
infoCriteria: getValue<string>(dataView.metadata.objects, 'settings_additional_params', 'infoCriteria', "none")
|
||||
|
||||
}
|
||||
|
||||
let imageUrl: string = null;
|
||||
if (dataView.scriptResult && dataView.scriptResult.payloadBase64) {
|
||||
imageUrl = "data:image/png;base64," + dataView.scriptResult.payloadBase64;
|
||||
}
|
||||
|
||||
if (imageUrl) {
|
||||
this.imageElement.src = imageUrl;
|
||||
} else {
|
||||
this.imageElement.src = null;
|
||||
}
|
||||
|
||||
this.onResizing(options.viewport);
|
||||
}
|
||||
|
||||
public onResizing(finalViewport: IViewport): void {
|
||||
this.imageDiv.style.height = finalViewport.height + 'px';
|
||||
this.imageDiv.style.width = finalViewport.width + 'px';
|
||||
}
|
||||
|
||||
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration {
|
||||
let objectName = options.objectName;
|
||||
let objectEnumeration = [];
|
||||
|
||||
switch (objectName) {
|
||||
case 'settings_forecastPlot_params':
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
forecastLength: Math.round(inMinMax(this.settings_forecastPlot_params.forecastLength, 1, 1000000)),
|
||||
confInterval1: this.settings_forecastPlot_params.confInterval1,
|
||||
confInterval2: this.settings_forecastPlot_params.confInterval2
|
||||
},
|
||||
selector: null
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case 'settings_seasonality_params':
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
show: this.settings_seasonality_params.show,
|
||||
targetSeason: this.settings_seasonality_params.targetSeason,
|
||||
},
|
||||
selector: null
|
||||
});
|
||||
if (this.settings_seasonality_params.targetSeason == "manual") {
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
knownFrequency: inMinMax(this.settings_seasonality_params.knownFrequency, 2, 1000000)
|
||||
},
|
||||
selector: null
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'settings_model_params':
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
maxp: this.settings_model_params.maxp,
|
||||
maxd: this.settings_model_params.maxd,
|
||||
maxq: this.settings_model_params.maxq
|
||||
},
|
||||
|
||||
});
|
||||
if (this.settings_seasonality_params.show) {
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
maxP: this.settings_model_params.maxP,
|
||||
maxD: this.settings_model_params.maxD,
|
||||
maxQ: this.settings_model_params.maxQ
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
allowDrift: this.settings_model_params.allowDrift,
|
||||
allowMean: this.settings_model_params.allowMean,
|
||||
boxCoxTransform: this.settings_model_params.boxCoxTransform,
|
||||
},
|
||||
|
||||
});
|
||||
if (this.settings_model_params.boxCoxTransform == "manual") {
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
lambda: inMinMax(this.settings_model_params.lambda, -1, 2)
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
fullEnumeration: this.settings_model_params.fullEnumeration
|
||||
},
|
||||
selector: null
|
||||
});
|
||||
break;
|
||||
|
||||
case 'settings_userModel_params':
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
show: this.settings_userModel_params.show,
|
||||
p: this.settings_userModel_params.p,
|
||||
d: this.settings_userModel_params.d,
|
||||
q: this.settings_userModel_params.q
|
||||
|
||||
},
|
||||
selector: null
|
||||
});
|
||||
if (this.settings_seasonality_params.show) {
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
P: this.settings_userModel_params.P,
|
||||
D: this.settings_userModel_params.D,
|
||||
Q: this.settings_userModel_params.Q
|
||||
},
|
||||
selector: null
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'settings_graph_params':
|
||||
objectEnumeration.push({
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
dataCol: this.settings_graph_params.dataCol,
|
||||
forecastCol: this.settings_graph_params.forecastCol,
|
||||
percentile: this.settings_graph_params.percentile,
|
||||
weight: this.settings_graph_params.weight
|
||||
|
||||
},
|
||||
selector: null
|
||||
});
|
||||
break;
|
||||
|
||||
case 'settings_additional_params':
|
||||
objectEnumeration.push({
|
||||
|
||||
objectName: objectName,
|
||||
properties: {
|
||||
show: this.settings_additional_params.show,
|
||||
textSize: this.settings_additional_params.textSize,
|
||||
textColor: this.settings_additional_params.textColor,
|
||||
infoCriteria: this.settings_additional_params.infoCriteria
|
||||
},
|
||||
selector: null
|
||||
});
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
return objectEnumeration;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
.rcv_autoScaleImageContainer {
|
||||
position: relative;
|
||||
|
||||
.rcv_autoScaleImage {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
/* @noflip */
|
||||
left: 50%;
|
||||
transform: translateY(-50%) translateX(-50%);
|
||||
-webkit-transform: translateY(-50%) translateX(-50%);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES5",
|
||||
"sourceMap": true,
|
||||
"out": "./.tmp/build/visual.js"
|
||||
},
|
||||
"files": [
|
||||
".api/v1.2.0/PowerBI-visuals.d.ts",
|
||||
"src/objectEnumerationUtility.ts",
|
||||
"src/visual.ts"
|
||||
]
|
||||
}
|
Загрузка…
Ссылка в новой задаче