# Is there a Histogram Function?

**URL:** <https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024>\
**Category:** Ignition\
**Created:** [February 19, 2014, 3:35pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024 "2014-02-19T15:35:14Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![tbackus](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tbackus/32/5091_2.png) [@tbackus](https://forum.inductiveautomation.com/u/tbackus)\
**Post date:** [February 19, 2014, 3:35pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/1 "2014-02-19T15:35:14Z")

</div>

I have a timeline chart to show faults in a PLC, Pictutre attached.

What the cusomer wants is a Histogram chart, basically a bar chart with faults at bottom (x Axis), number of total minutes (y Axis). they want to be able to select the last “8” hours or “16” hours or whatever hours. or the timeline.

Is this function built in somewhere or do I need to do some manual calculations to get total minutes for each fault?

---

<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:** [February 20, 2014, 10:07am UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/2 "2014-02-20T10:07:24Z")

</div>

How is the data gathered now? Is that a status chart you’re using?

---

<div class="post-metadata">

**Author:** ![tbackus](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tbackus/32/5091_2.png) [@tbackus](https://forum.inductiveautomation.com/u/tbackus)\
**Post date:** [February 20, 2014, 4:02pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/3 "2014-02-20T16:02:29Z")

</div>

Yes, it is a status chart, using historical tags.

I was able to summerize the columns to give me totals in minutes of downtime, but they want occurances… So as you can see on the picture, some red areas exist for a long time, but is still one occurance.

---

<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:** [February 21, 2014, 11:14am UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/4 "2014-02-21T11:14:55Z")

</div>

Yeah, you’ll have to iterate through the dataset, looking for the transiston.

Someone else will have to chime in at this point. My refusal to use historical tags just limits how much I can help you. 😉

---

<div class="post-metadata">

**Author:** ![hazelchr](https://avatars.discourse-cdn.com/v4/letter/h/e9c0ed/32.png) [@hazelchr](https://forum.inductiveautomation.com/u/hazelchr)\
**Post date:** [March 11, 2014, 7:38pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/5 "2014-03-11T19:38:09Z")

</div>

A while ago I wrote code to create a histogram, feel free to use/modify it if you want…

[code]#Script to create a histogram

#This script looks at an array of data and counts how many cells are between specific numbers (called “bins”) to use for plotting a histogram on a bar chart.

#----Change these values according to your needs-----  
dat=event.source.parent.Xbar #load a dataset. Have the column of interest be labeled “Data”

mx=event.source.parent.xbarmax #the maximum value of the data  
mn=event.source.parent.xbarmin #the minimum value of the data  
bins=10 #should this be dynamic based on the row count? is 10 bins enough granularity? Change to adapt to your dataset!

#----histogram code-----  
import math  
rng=float(mx-mn) #the range of the dataset  
binSize=float(rng/bins) #the size of the bins

mn1=mn-(2\*binSize)#include some extra bins on the low end  
bin\_ar=[] #initalize the bin array

for x in range(bins+4): #Iterate through the bin array. include some bins on the high end.  
bin\_val=round(mn1+(x\*binSize),1)  
bin\_ar.append([bin\_val])  
hd=[“Bins”]  
bins\_array= system.dataset.toDataSet(hd,bin\_ar) #the complete array of the bins

resar=[]  
for i in range(len(bin\_ar)-1): #iterate through each bin.  
cnt=0   
for x in range(dat.rowCount): #iterate on each datapoint, for a specific bin, then count if it is in range.   
val=dat.getValueAt(x,“Data”)  
if val\>= bins\_array.getValueAt(i,“Bins”) and val\< bins\_array.getValueAt(i+1,“Bins”): #if the value is within between the current bin and the next bin, count it.  
cnt+=1

```
if x==(dat.rowCount-1): 
	resar.append([str(bins_array.getValueAt(i,"Bins")),cnt]) #append to an array with the count results for the specific bin

```

hd1=[“Bin”,“Count”]  
histdata=system.dataset.toDataSet(hd1,resar) #the output dataset   
[/code]

---

<div class="post-metadata">

**Author:** ![tailfire](https://avatars.discourse-cdn.com/v4/letter/t/b5a626/32.png) [@tailfire](https://forum.inductiveautomation.com/u/tailfire)\
**Post date:** [March 13, 2014, 12:16am UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/6 "2014-03-13T00:16:58Z")

</div>

Nice script, can you post a pic of the resulting histogram?

---

<div class="post-metadata">

**Author:** ![tbackus](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tbackus/32/5091_2.png) [@tbackus](https://forum.inductiveautomation.com/u/tbackus)\
**Post date:** [March 17, 2014, 3:01pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/7 "2014-03-17T15:01:34Z")

</div>

Sorry guys, I have been pulled off on other projects and just getting back to this… I was not able to make the Histogram script work for me…

---

<div class="post-metadata">

**Author:** ![the\_msp](https://avatars.discourse-cdn.com/v4/letter/t/b38774/32.png) [@the\_msp](https://forum.inductiveautomation.com/u/the_msp)\
**Post date:** [December 12, 2016, 12:05pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/8 "2016-12-12T12:05:40Z")

</div>

I got this working for anyone interested, using a spinner to change the bin size on the fly

[code]#Script to create a histogram

#This script looks at an array of data and counts how many cells are between specific numbers (called “bins”) to use for plotting a histogram on a bar chart.

#----Change these values according to your needs-----  
#data = system.db.runQuery(“select t\_weld from laserweld where station = 3 and substation = 0 and datetime \> DateAdd(HOUR,-12,getdate())”) #load a dataset. Have the column of interest be labeled “Data”  
dropDownValue = event.source.parent.getComponent(‘Dropdown’).selectedStringValue  
start\_date = event.source.parent.getComponent(‘Date Range’).startDate  
end\_date = event.source.parent.getComponent(‘Date Range’).endDate  
input = system.db.runPrepQuery(“select %s as data from laserweld where station = 3 and substation = 0 and datetime between ? and ?” %dropDownValue, [start\_date, end\_date])

dat = system.dataset.toDataSet(input)  
mx= 0.4 #the maximum value of the data  
mn= 0.1 #the minimum value of the data  
bins=event.source.intValue #should this be dynamic based on the row count? is 10 bins enough granularity? Change to adapt to your dataset!

#----histogram code-----  
import math  
rng=float(mx-mn) #the range of the dataset  
binSize=float(rng/bins) #the size of the bins

mn1=mn-(2\*binSize)#include some extra bins on the low end  
bin\_ar=[] #initalize the bin array

for x in range(bins+4): #Iterate through the bin array. include some bins on the high end.  
bin\_val=round(mn1+(x\*binSize),1)  
bin\_ar.append([bin\_val])  
hd=[“Bins”]  
bins\_array= system.dataset.toDataSet(hd,bin\_ar) #the complete array of the bins

resar=[]  
for i in range(len(bin\_ar)-1): #iterate through each bin.  
cnt=0  
for x in range(dat.rowCount): #iterate on each datapoint, for a specific bin, then count if it is in range.  
val=dat.getValueAt(x,“Data”)  
if val\>= bins\_array.getValueAt(i,“Bins”) and val\< bins\_array.getValueAt(i+1,“Bins”): #if the value is within between the current bin and the next bin, count it.  
cnt+=1

if x==(dat.rowCount-1):  
resar.append([str(bins\_array.getValueAt(i,“Bins”)),cnt]) #append to an array with the count results for the specific bin

hd1=[“Bin”,“Count”]  
histdata=system.dataset.toDataSet(hd1,resar) #the output dataset  
event.source.parent.getComponent(‘Bar Chart’).data = histdata  
[/code]

---

<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:** [December 12, 2016, 2:34pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/9 "2016-12-12T14:34:19Z")

</div>

[quote=“JordanCClark”]My refusal to use historical tags just limits how much I can help you. 😉[/quote]Heh. I have nothing to add to the OP’s problem, but I do share your low opinion of narrow key-value history recording. I also have a low opinion of database backends that cannot do window aggregates, which make time delta computations for event analysis relatively easy.

---

<div class="post-metadata">

**Author:** ![jshannon](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jshannon/32/81937_2.png) [@jshannon](https://forum.inductiveautomation.com/u/jshannon)\
**Post date:** [October 15, 2018, 3:58pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/10 "2018-10-15T15:58:08Z")

</div>

That Histogram works great, thank you. How about drawing a bell curve on top for deviation?

---

<div class="post-metadata">

**Author:** ![GreggCavazos](https://avatars.discourse-cdn.com/v4/letter/g/90db22/32.png) [@GreggCavazos](https://forum.inductiveautomation.com/u/GreggCavazos)\
**Post date:** [August 2, 2019, 12:40am UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/11 "2019-08-02T00:40:11Z")

</div>

> [@pturmel](#):
>
> I have nothing to add to the OP’s problem, but I do share your low opinion of narrow key-value history recording. I also have a low opinion of database backends that cannot do window aggregates, which make time delta computations for event analysis relatively easy.

@pturmel / @JordanCClark, I am no expert on this, I am interested on the reasons behind those low opinions? can any of you elaborate or point me to a good read for my own enlightenment on why its not a good idea to use historian data for this application? also expand on the DB back-end for aggregate functions?

With Controls background I find DB queries a simple solution for some of my reporting requirements, but if I understand correctly for some applications may not be the best solution. What would be the option for those cases?

---

<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:** [August 2, 2019, 12:48pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/12 "2019-08-02T12:48:04Z")

</div>

Hi Gregg,  
The vast majority of my applications are event driven. Make a part, store values associated with that part. Often in the same row. This is where transaction groups excel.

The same can be done for time series data. multiple tags on one row in the db. This provides context that I’m not yet convinced exists in a single key-value structure, even if you query multiple historian points.

Window aggregates can be explained in a bit [more detail here](https://www.postgresql.org/docs/9.3/tutorial-window.html) (using Postgres as an example).

---

<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:** [August 2, 2019, 1:22pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/13 "2019-08-02T13:22:12Z")

</div>

Hi Gregg,

What Jordan said.

Plus, I’ve found that many, if not most, of the analysis I do with historical data involves correlations between different values in time. With key-value storage (tag historian), it is extraordinarily challenging to assemble datasets of multiple variables sampled at identical points in time. With transaction groups, it is a natural property of the value columns in each table.

Since it is common to not know ahead of time which value correlations will be interesting, I tend to select recording methods that enable easy ad-hoc analysis at a later date. Storage is cheap. It is easy to throw away data you later decide you don’t need. It is painful to realize you could solve a critical problem if only you had more historical data, or in a usable form.

---

<div class="post-metadata">

**Author:** ![rstevenson](https://avatars.discourse-cdn.com/v4/letter/r/d6d6ee/32.png) [@rstevenson](https://forum.inductiveautomation.com/u/rstevenson)\
**Post date:** [August 5, 2019, 6:17pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/14 "2019-08-05T18:17:15Z")

</div>

I asked a similar question earlier on a post about auto switching between windows in a project. My question for this specific instance, is where would I do this scripting to generate a histogram? I am attempting to generate histograms for test data that I am pulling from an SQL database.

Excited to see how quickly JordanCClark answers this one!

Thanks!

---

<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:** [August 5, 2019, 6:32pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/15 "2019-08-05T18:32:54Z")

</div>

> [@rstevenson](#):
>
> I am attempting to generate histograms for test data that I am pulling from an SQL database.

If you know the bucket intervals in advance, I would make the DB do the work. Something like this (Named Query):

```auto
SELECT bucket, count(*)
FROM (
  SELECT :firstbucket + :bucketinterval * floor((valuecolumn - :firstbucket) / :bucketinterval) AS bucket
  FROM sometable
  WHERE somecondition
) bucketized
GROUP BY bucket
ORDER BY bucket

```

---

<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:** [August 5, 2019, 7:26pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/16 "2019-08-05T19:26:16Z")

</div>

You caught me at a good time last time around. Don't always expect that! 😉

You can also try the statsutils port.

> [@Statistics Extensions for Ignition](http://forum.inductiveautomation.com/t/statistics-extensions-for-ignition/17100):
>
> After discussions elsewhere with @Brian on the forum, I’ve ported the statsutils library from [http://boltons.readthedocs.io](http://boltons.readthedocs.io) some changes from the originaL Removed the format\_histogram functions, as they were using unsupported string formatting. Maybe when Ignitions’s Jython gets upgraded, I can look at it again. Renamed remaining histogram function to histogram. Brevity is good. Added ‘raw’ flag to histogram function to give a one-dimensional list with repeat histogram values, instead…

---

<div class="post-metadata">

**Author:** ![rstevenson](https://avatars.discourse-cdn.com/v4/letter/r/d6d6ee/32.png) [@rstevenson](https://forum.inductiveautomation.com/u/rstevenson)\
**Post date:** [August 6, 2019, 7:57pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/17 "2019-08-06T19:57:54Z")

</div>

Is there a tutorial anywhere on how to use the Statsutils port? As I mentioned in another post, Im still learning how everything in Ignition works, and I am also in the process of migrating all of my projects and Ignition Gateway over to 8.0.2. College taught me to learn through stack overflow, and there doesn’t seem to be as much documentation for Ignition related items.

I appreciate the help.  
-Ryan

---

<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:** [August 7, 2019, 11:46am UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/18 "2019-08-07T11:46:34Z")

</div>

Well, there’s the pdf in the post I referenced above… 😕 Refreshed to make sure the upload sticks…

---

<div class="post-metadata">

**Author:** ![Alexander41](https://avatars.discourse-cdn.com/v4/letter/a/71e660/32.png) [@Alexander41](https://forum.inductiveautomation.com/u/Alexander41)\
**Post date:** [September 18, 2019, 4:21pm UTC](https://forum.inductiveautomation.com/t/is-there-a-histogram-function/8024/19 "2019-09-18T16:21:16Z")

</div>

In case you are still looking to use a histogram,

I've found the best place to put the code for a histogram is under the "propertyChange" event handler on the rootContainer; then you can use the code below to tie the script to your source dataset, which you add as a custom property on the rootContainer:

> if event.propertyName == 'dataset':
