Skip to content

Commit

Permalink
Now in the extra calculation you can set the moment to obtain the val…
Browse files Browse the repository at this point in the history
…ue to be considered (before or after applying all the preprocess)
  • Loading branch information
juliarobles committed Oct 16, 2024
1 parent 6f2a4cb commit 9878992
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 35 deletions.
21 changes: 20 additions & 1 deletion src/components/editors/extraCalcForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react'
import { SelectableValue, StandardEditorContext } from "@grafana/data";
import { Calc, ExtraCalcFormat, IExtraCalc, ISelect } from 'utils/types';
import { Calc, ExtraCalcFormat, IExtraCalc, ISelect, WhenApplyEnum } from 'utils/types';
import { Alert, Button, Collapse, ConfirmButton, DeleteButton, Form, FormAPI, HorizontalGroup, InlineField, Input, InputControl, Select, useTheme2 } from '@grafana/ui';
import { ExtraCalcDefault } from 'utils/default';
import { Mode } from 'utils/constants';
Expand All @@ -23,10 +23,12 @@ export const ExtraCalcForm: React.FC<Props> = ({ extraCalc, updateFunction, dele

const calcOptions: ISelect[] = enumToSelect(Calc)
const formatOptions: ISelect[] = enumToSelect(ExtraCalcFormat)
const whenApplyOptions: ISelect[] = enumToSelect(WhenApplyEnum)

const [currentCalc, setCurrentCalc] = useState<IExtraCalc>(ExtraCalcDefault)
const [selectedCalc, setSelectedCalc] = useState<SelectableValue<string>>(calcOptions[0])
const [selectedFormat, setSelectedFormat] = useState<SelectableValue<string>>(formatOptions[0])
const [selectedWhen, setSelectedWhen] = useState<SelectableValue<string>>(whenApplyOptions[0])
const [currentDynamicFields, setCurrentDynamicFields] = useState<string[]>([])
const [currentDynFieldName, setCurrentDynFieldName] = useState<string>("")
const [disabled, setDisabled] = useState(false)
Expand All @@ -35,6 +37,7 @@ export const ExtraCalcForm: React.FC<Props> = ({ extraCalc, updateFunction, dele
setCurrentCalc(extraCalc)
setSelectedCalc({ value: extraCalc.calc, label: extraCalc.calc as string })
setSelectedFormat({ value: extraCalc.resFormat, label: extraCalc.resFormat as string })
setSelectedWhen({ value: extraCalc.whenApply, label: extraCalc.whenApply as string })
if (extraCalc.dynamicFields) setCurrentDynamicFields(extraCalc.dynamicFields)
}

Expand All @@ -56,6 +59,7 @@ export const ExtraCalcForm: React.FC<Props> = ({ extraCalc, updateFunction, dele
...currentCalc,
calc: selectedCalc.value,
resFormat: selectedFormat.value,
whenApply: selectedWhen.value,
dynamicFields: currentDynamicFields
})
if (mode === Mode.EDIT) {
Expand Down Expand Up @@ -167,6 +171,21 @@ export const ExtraCalcForm: React.FC<Props> = ({ extraCalc, updateFunction, dele
<InlineField label="Name" labelWidth={17} required grow disabled={disabled}>
<Input {...register("name")} value={currentCalc.name} disabled={disabled} onChange={handleOnChangeCalc} required />
</InlineField>
<InlineField label="When to apply" labelWidth={17} grow required disabled={disabled}>
<InputControl
render={({ field }) =>
<Select
value={selectedWhen}
options={whenApplyOptions}
onChange={(v) => setSelectedWhen(v)}
disabled={disabled}
defaultValue={whenApplyOptions[0]}
/>
}
control={control}
name="whenApply"
/>
</InlineField>
<InlineField label="Maximum iterations" labelWidth={17} grow disabled={disabled}>
<Input {...register("maxIterations")} value={currentCalc.maxIterations} disabled={disabled} onChange={handleOnChangeCalc} required />
</InlineField>
Expand Down
86 changes: 59 additions & 27 deletions src/utils/datasources/extraCalc.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Calc, DateRes, ExtraCalcFormat, IDataCollection, IDataPred, IModel, IResult, ITag } from "utils/types"
import { getListValuesFromNew, newDataToObject, predictResults } from "./predictions"
import { Calc, DateRes, ExtraCalcFormat, IDataCollection, IDataPred, IModel, IResult, ITag, PostChangeIDataPred, WhenApplyEnum } from "utils/types"
import { getListValuesFromNew, newDataToObject, predictResults, prepareAndPredictResults, prepareToPredict } from "./predictions"
import vm from 'vm'
import { getMean } from "utils/utils"
import { deepCopy, getMean } from "utils/utils"
import { dateTime, DateTime } from "@grafana/data"

const replaceVariables = (text: string, data: IDataPred, dyn?: number[], lastResult?: number) => {
Expand Down Expand Up @@ -63,60 +63,92 @@ const applyFormatToRes = (res: number, format: ExtraCalcFormat, selectedDate?: D
return res.toString()
}

const createRequests = (num: number, calcValue: number, data: IDataPred, tag: string, calc: Calc, idNumber: number) => {
const createRequests = (iniRes: IResult, num: number, calcValue: number, data: IDataPred, tag: string, calc: Calc, idNumber: number, isProcessed = false): PostChangeIDataPred => {
let res: IResult[] = []
let allData: IDataPred[] = []
for (let i = 0; i < num; i++) {
let newResult = deepCopy(iniRes)
let mean = getMean(data[tag])
let newValue = applyCalcValue(mean, calcValue, calc)
data = {
...data,
[tag]: getListValuesFromNew(newValue, mean, data[tag])
}
res.push({
id: ("extraCalc_" + (idNumber + i)),
data: { ...data },
correspondsWith: { tag: tag, intervalValue: newValue }
})
const copyData = {...data}
allData.push(copyData)

newResult.id = newResult.id + "_" + (idNumber + i)
newResult.correspondsWith.intervalValue = newValue
if(isProcessed) {
newResult.processedData = {...copyData}
} else {
newResult.data = {...copyData}
}

res.push(newResult)
}
return res
return {newData: allData, newResults: res}
}

const check = (r: IResult, model: IModel, isAfter: boolean, dyn?: number[]) => {
if(r.result && model.extraCalc && typeof r.result === 'number') {
let condition = ""
if(isAfter && r.processedData) {
condition = replaceVariables(model.extraCalc.until, r.processedData, dyn, r.result)
} else {
condition = replaceVariables(model.extraCalc.until, r.data, dyn, r.result)
}
return executeString(condition)
}
return false
}

export const extraCalcCollection = async (model: IModel, col: IDataCollection, dyn?: number[]): Promise<IDataCollection> => {
if (model.extraCalc && model.tags.some((tag: ITag) => tag.id === model.extraCalc?.tag)) {
let res: IResult[] = []
let calcValue = 0
let results: IResult[] = []
const tag = model.extraCalc.tag
const isAfter = model.extraCalc.whenApply === WhenApplyEnum.afterPreprocess

// Preparamos los datos iniciales y obtenemos el valor para los calculos
let data: IDataPred = prepareInitialData(col, model.numberOfValues)
const calcValue = executeString(replaceVariables(model.extraCalc.calcValue, data, dyn))

// Creamos el resultado inicial
const iniResult: IResult = {
id: "extraCalc",
data: { ...data },
correspondsWith: { tag: tag, intervalValue: getMean(data[tag]) }
}

// Generamos el resto de resultados sumando calc de forma recursiva al tag correspondiente y predecimos
let results = [iniResult, ...createRequests((model.extraCalc.numRequests-1), calcValue, data, tag, model.extraCalc.calc, 1)]
results = await predictResults(model, results)

// Comprobamos si se cumple la condicion en alguno
const check = (r: IResult) => {
if(r.result && model.extraCalc && typeof r.result === 'number') {
const condition = replaceVariables(model.extraCalc.until, r.data, dyn, r.result)
return executeString(condition)
}
return false
if(isAfter){
const prep = await prepareToPredict(model, [iniResult])
calcValue = executeString(replaceVariables(model.extraCalc.calcValue, prep.newData[0], dyn))
const requests = createRequests(iniResult, (model.extraCalc.numRequests-1), calcValue, prep.newData[0], tag, model.extraCalc.calc, 1, true)
results = await predictResults(model, [...prep.newData, ...requests.newData], [...prep.newResults, ...requests.newResults])
} else {
calcValue = executeString(replaceVariables(model.extraCalc.calcValue, data, dyn))
results = [iniResult, ...createRequests(iniResult, (model.extraCalc.numRequests-1), calcValue, data, tag, model.extraCalc.calc, 1).newResults]
results = await prepareAndPredictResults(model, results)
}
let idxFin = results.findIndex(check)

// Comprobamos si se cumple la condicion en alguno
let idxFin = results.findIndex((r) => check(r, model, isAfter, dyn))

while (idxFin < 0) { // Probamos hasta que se cumpla alguna condicion
data = results[results.length-1].data
const lastRes = results[results.length-1]
res = [...res, ...results]
results = [...createRequests(model.extraCalc.numRequests, calcValue, data, tag, model.extraCalc.calc, res.length)]
results = await predictResults(model, results)
idxFin = results.findIndex(check)
if(isAfter && lastRes.processedData){
data = lastRes.processedData
results = [...createRequests(iniResult, model.extraCalc.numRequests, calcValue, data, tag, model.extraCalc.calc, res.length).newResults]
const requests = createRequests(iniResult, model.extraCalc.numRequests, calcValue, data, tag, model.extraCalc.calc, res.length, true)
results = await predictResults(model, [...requests.newData], [...requests.newResults])
} else {
data = lastRes.data
results = [...createRequests(iniResult, model.extraCalc.numRequests, calcValue, data, tag, model.extraCalc.calc, res.length).newResults]
results = await prepareAndPredictResults(model, results)
}
idxFin = results.findIndex((r) => check(r, model, isAfter, dyn))
}

res = (idxFin + 1 < results.length) ? [...res, ...results.slice(0, (idxFin+1))] : [...res, ...results]
Expand Down
18 changes: 14 additions & 4 deletions src/utils/datasources/predictions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PreprocessCodeDefault } from "../default";
import { IData, IDataCollection, IDataPred, IFormat, IInterval, IModel, IResult, IScaler, IntervalTypeEnum } from "../types"
import { IData, IDataCollection, IDataPred, IFormat, IInterval, IModel, IResult, IScaler, IntervalTypeEnum, PostChangeIDataPred } from "../types"
//import * as dfd from "danfojs"
import { idDefault, idNew, varEachInput, varEachInputEnd, varInput, variableOutput } from "../constants"
import vm from 'vm'
Expand All @@ -15,7 +15,7 @@ export const predictAllCollections = async (model: IModel, allData: IDataCollect
return allData
}

export const predictResults = async (model: IModel, results: IResult[]) => {
export const prepareToPredict = async (model: IModel, results: IResult[]): Promise<PostChangeIDataPred> => {
let dataToPredict: IDataPred[] = []
for (const [i, r] of results.entries()) {
let finalData = deepCopy(r.data)
Expand All @@ -33,15 +33,25 @@ export const predictResults = async (model: IModel, results: IResult[]) => {
dataToPredict.push(finalData)
results[i] = { ...r, processedData: finalData }
}
const predictions: any = await sendRequest(model, dataToPredict)
return {newData: dataToPredict, newResults: results}
}

export const predictResults = async (model: IModel, data: IDataPred[], results: IResult[]) => {
const predictions: any = await sendRequest(model, data)
return results.map<IResult>((r: IResult, indx: number) => { return { ...r, result: predictions[indx] } })
}

export const prepareAndPredictResults = async (model: IModel, results: IResult[]) => {
const res = await prepareToPredict(model, results)
console.log("prepareResults", res)
return await predictResults(model, res.newData, res.newResults)
}

const predictData = async (model: IModel, dataCollection: IDataCollection) => {
//console.log("numValues", model.numberOfValues)
//console.log("dataCollection", dataCollection)
let results: IResult[] = prepareData(dataCollection, model.numberOfValues)
return await predictResults(model, results)
return await prepareAndPredictResults(model, results)
}

const getValuesFromInterval = (interval: IInterval): number[] => {
Expand Down
5 changes: 3 additions & 2 deletions src/utils/default.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { messages_en } from "./localization/en";
import { FormatTags, IContext, IDataCollection, IFormat, IModel, IInterval, ITag, Language, Method, IntervalTypeEnum, IExtraCalc, Calc, ExtraCalcFormat } from "./types";
import { FormatTags, IContext, IDataCollection, IFormat, IModel, IInterval, ITag, Language, Method, IntervalTypeEnum, IExtraCalc, Calc, ExtraCalcFormat, WhenApplyEnum } from "./types";

export const PreprocessCodeDefault = "console.log('Preprocess')"

Expand All @@ -19,7 +19,8 @@ export const ExtraCalcDefault: IExtraCalc = {
resProcess: "$res",
maxIterations: 1000,
resFormat: ExtraCalcFormat.raw,
numRequests: 10
numRequests: 10,
whenApply: WhenApplyEnum.afterPreprocess
}

export const ModelDefault: IModel = {
Expand Down
13 changes: 12 additions & 1 deletion src/utils/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export enum ExtraCalcFormat {
addDays = "Add as days to selected date"
}

export enum WhenApplyEnum {
afterPreprocess = "After preprocessing",
beforePreprocess = "Before preprocessing"
}

export enum FormatTags {
None = 'None',
dq = 'Double quotes',
Expand Down Expand Up @@ -152,7 +157,13 @@ export interface IExtraCalc {
resProcess: string,
maxIterations: number,
resFormat: ExtraCalcFormat,
numRequests: number
numRequests: number,
whenApply: WhenApplyEnum
}

export interface PostChangeIDataPred {
newData: IDataPred[],
newResults: IResult[]
}

export class DateRes {
Expand Down

0 comments on commit 9878992

Please sign in to comment.