# How to get area under curve

**URL:** <https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [September 8, 2024, 7:41pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699 "2024-09-08T19:41:51Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Eugene49](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@Eugene49](https://forum.inductiveautomation.com/u/Eugene49)\
**Post date:** [September 8, 2024, 7:41pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/1 "2024-09-08T19:41:51Z")

</div>

I have a tag power\_kW where I am historizing.

I want to get Energy between time interval.

So I did tag query power\_kW for a given time interval.

If I plot it on a chart, The energy should be the area beneath the power\_kW curve.

Is there a function to get the Area below the curve?

---

<div class="post-metadata">

**Author:** ![Mitchell\_Dennis](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Mitchell\_Dennis](https://forum.inductiveautomation.com/u/Mitchell_Dennis)\
**Post date:** [September 9, 2024, 12:28am UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/2 "2024-09-09T00:28:19Z")

</div>

Divide the sum of power by the number of samples per hour.  
So if you have an aggregation interval of 5, energy = sum(power) / (60 / 5)

A quick way to get the sum of a column from a dataset is by doing the following:

```python
def sum_col(dataset, col_name):
	col_data = ds.getColumnAsList(ds.getColumnIndex(col_name))
	return sum(col_data)

ds = system.dataset.toDataSet(['test'],[[1],[1],[1]])
sum_col(ds, 'test')

```

Replace 'ds' with whatever dataset you have and 'test' with the column name you want.

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [September 9, 2024, 11:42am UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/3 "2024-09-09T11:42:43Z")

</div>

If you are doing energy metering then I recommend recording the kWh rather than kW and doing it on a periodic schedule to a dedicated database. It makes energy calculations over any time period very easy. Historian is not good for this sort of job.

---

<div class="post-metadata">

**Author:** ![DNice](https://avatars.discourse-cdn.com/v4/letter/d/858c86/32.png) [@DNice](https://forum.inductiveautomation.com/u/DNice)\
**Post date:** [September 9, 2024, 11:47am UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/4 "2024-09-09T11:47:57Z")

</div>

Integrate 😉

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [September 9, 2024, 12:07pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/5 "2024-09-09T12:07:03Z")

</div>

This post reviews the operation, scroll down to the bottom for the proper download.

> [@Chart Help](https://forum.inductiveautomation.com/t/chart-help/9303/2):
>
> Time for a paradigm shift. Dah-da-da-daahh! (Imagine Jeff Dunham’s “Melvin, the Superhero Guy”) wink First, a window to play with. [Integral\_2014-11-07\_1314.proj](https://us1.discourse-cdn.com/inductiveautomation/original/2X/a/ac01bdd388a88ed210b3220d8491a9f97cf49c59.proj) (41.8 KB) Ok, the best you’ll be able to do is an approximation. The only thing we have are a set of discrete data points. Strictly speaking, we have no idea what is happening between the points. Graphing these points will give us a straight line between each one. The more samples you have the finer the details, and the closer the a…

---

<div class="post-metadata">

**Author:** ![Eugene49](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@Eugene49](https://forum.inductiveautomation.com/u/Eugene49)\
**Post date:** [September 9, 2024, 2:19pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/6 "2024-09-09T14:19:51Z")

</div>

> [@Transistor](#):
>
> dedicated

You are right. write to database and reset value in regular interval..?

I was thinking of alternative to this, where user can enter time range of any granularity.

---

<div class="post-metadata">

**Author:** ![Eugene49](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@Eugene49](https://forum.inductiveautomation.com/u/Eugene49)\
**Post date:** [September 9, 2024, 2:24pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/7 "2024-09-09T14:24:37Z")

</div>

> [@DNice](#):
>
> Integrate

You said it. Was wondering if there was a built-in function for it. Or a kind person has an elegant code, I can start with..

Python numpy should have something like that.

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [September 9, 2024, 2:54pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/8 "2024-09-09T14:54:22Z")

</div>

> [@Eugene49](#):
>
> You said it. Was wondering if there was a built-in function for it. Or a kind person has an elegant code, I can start with..

Dude, really? 😉 Around post 5 in this thread...

> [@JordanCClark](#):
>
> This post reviews the operation,

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [September 9, 2024, 2:55pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/9 "2024-09-09T14:55:31Z")

</div>

> [@Eugene49](#):
>
> ... write to database and reset value in regular interval ...

No, never reset. Use it like your utility company does and just record the kWh reading and t\_stamp. Then you can calculate the energy used in any time period by subtracting the first reading from the last.

To generate data for a chart you would need the difference between successive kWh readings.

One other big benefit of this method is that, should the logging fail for a period of time, you can still calculate the average energy use through the data gap. With kW logging you can't.

---

<div class="post-metadata">

**Author:** ![Eugene49](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@Eugene49](https://forum.inductiveautomation.com/u/Eugene49)\
**Post date:** [September 10, 2024, 3:40am UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/10 "2024-09-10T03:40:52Z")

</div>

My head hurts, lets take a step back.

Suppose I have a tag, energy\_kWH, which is accumulates indefinitely.

Goal is to record the daily energy usage.

Every midnight, I run my code, read energy, and set timestamp and write it on database.

so I have the below on database:

midnight1, energyNow - energy0  
midnight2, energyNow - energy1  
missed(code did not run)  
midnight4, energy is ??

Compare with reset:  
midnight1, energyNow (then reset)  
midnight2, energyNow (then reset)  
missed(code did not run)  
midnight4, energyNow (wrong measurements)

Option 3:  
Historized power\_kW,  
get the curve from yesterdayMidnight to today's midnight, energy is the area of curve.

How did option 1 became the best option?

Option 4: Historized energy\_kWH  
get Energy at yesterday midnight  
get Energy at today's midnight  
energy today = the difference

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [September 10, 2024, 12:25pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/11 "2024-09-10T12:25:24Z")

</div>

> [@Eugene49](#):
>
> How did option 1 became the best option?

Because you can never lose any information. With any reset operation, there is always a tiny interval where an increment can be lost.

Also, you don't have to record just at midnight. You can record on the hour, every hour. Or every minute on the minute. Or every five minutes. Whatever granularity you choose, and never losing any information. For any longer period, the energy is simply the first recorded value after the period minus the first recorded value of the period. Trivial in any database.

When recording more often, you minimize the disruption of downtime, as the energy is simply accounted to the next recording, not lost.

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [September 10, 2024, 12:38pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/12 "2024-09-10T12:38:24Z")

</div>

For multiple meters I'd recommend a table structure like this:

- t\_stamp
- meterId
- kwh\_reading
- kvar\_reading

Everything else can be calculated by SQL or script.

@pturmel, I'm interested in what you'd recommend for t\_stamp values. Would you round down to the nearest second or minute to make the queries easier to catch the boundary records?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [September 10, 2024, 12:46pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/13 "2024-09-10T12:46:31Z")

</div>

> [@Transistor](#):
>
> Would you round down

Shouldn't be necessary when using properly rounded-down timestamp parameters in the WHERE clause.

It **is** important that the actual recording be fresh data from the source OPC item, not from a subscribed tag. That is, transaction groups should be configured to OPC Read mode, and scripted inserts should use `system.opc.readValues()`.

---

<div class="post-metadata">

**Author:** ![Eugene49](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@Eugene49](https://forum.inductiveautomation.com/u/Eugene49)\
**Post date:** [September 10, 2024, 3:17pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/14 "2024-09-10T15:17:40Z")

</div>

> [@pturmel](#):
>
> You can record on the hour, every hour. Or every minute on the minute. Or every five minutes. Whatever granularity you choose, and never losing any information.

But this is what historian does, isn't it?  
Then we only need to enable historian for this tag.  
(not to stir, but looking for best implementation)

And do query history on this tag on using single time instance.  
"What is the Energy yesterday Midnight"  
"What is the Energy Today Midnight"  
Subtract them.

Main goal really,  
I wanted to save in database, discretely because I wanted to show on bar graph Energy Usage Per Day.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [September 10, 2024, 3:32pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/15 "2024-09-10T15:32:03Z")

</div>

> [@Eugene49](#):
>
> But this is what historian does, isn't it?

No, the historian won't save on even intervals like a scheduled transaction group or a scripted operation in a scheduled event.

---

<div class="post-metadata">

**Author:** ![Eugene49](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@Eugene49](https://forum.inductiveautomation.com/u/Eugene49)\
**Post date:** [September 10, 2024, 3:50pm UTC](https://forum.inductiveautomation.com/t/how-to-get-area-under-curve/95699/16 "2024-09-10T15:50:21Z")

</div>

> [@pturmel](#):
>
> No, the historian won't save on even intervals like a scheduled transaction group or a scripted operation in a scheduled event.

Thank you.

I am happy with the below now:  
I will historized Energy Tag. Make two queries on it and store the difference in database for reporting.  
Its not perfect but should solve most of the problem (missing data, miss "writing to database" code)  
This will return 1 value (Maximum within 60sec).

```python
dsEnergy_kWh = system.tag.queryTagHistory(
	paths, 
	startDate=todayMidnight,
	aggregationMode="Maximum",  
	returnSize = 1, 
	rangeSeconds=60)

#return one line:
#[Tue Sep 10 00:00:00 CDT 2024, 316.96161602693377]

```
