Perspective Box and Whisker Plot

I was actually wondering if anyone had or had advice on how to create a box and whisker plot view using ignition perspective.

I have tried using the candlestick render mode but I am still struggling on the data because my box and whisker plot will be temperature values on the y-axis and many temperature variables on the x-axis not time.

Thank you for any input

1 Like

Using the candlestick render isn’t going to be exactly the same as a box and whisker plot, but depending on your needs it might get you close enough.

Instead of a time axis, use a category X-axis to organize your temperature variables. Each temperature variable will be it’s own category, and will one have one data entry, containing an open, high, low, and close value. Then under series, map candlestick.open, candlestick.high, candlestick.low, and data to the corresponding values.

Sidenote:
I think it might be possible to render something that actually resembles an actual box and whisker plot by playing around with column render widths. If anyone wants get deep in the weeds on this, I’d try making series for:

  1. Min Marker
  2. Min to Q1
  3. Q1 to Median
  4. Median Marker
  5. Median to Q3
  6. Q3 to Max
  7. Max Marker

By playing around with the colors and width/heights of the different series I think something serviceable can be made. You’ll probably have to do something wacky in order to give your min, median, and max markers a visible thickness (maybe draw the real value ± some percentage of the chart range?).

Thank you for your help,
Is there anyway you can give an example of what your describing in the first part (not the side note)? I am trying to get that together but my graph is always blank but not in error.

I couldn’t get the ‘Low’ value of the candlestick to render correctly; maybe someone from IA should take a look at it…


candlestick.json (14.4 KB)

I appreciate that a lot. I think that will work or at least get me pointed in the right direction. You’ll have to forgive me, I am very new to perspective. I get an error when I paste the JSON code into my root container. Am I doing something wrong when trying to get that graph imported?
image

I was able to get it working as of now, I see what you mean when you say the low is not working as expected. Do you think we are missing a parameter? basically the line should stop at the low value but it just goes straight to zero or the x-axis.

:+1:t2: Glad to hear.

That’s exactly what I’m seeing, no amount of fiddling with the data source seem to make any difference. For reference I’m on 8.0.15. Maybe @ynejati can take a look at this.

Here’s a first draft of a proper box and whisker chart. Can you test this out for me and make sure it renders like you would expect?

It definitely needs some theming options as well as some axis options: what kind of coloring options would you expect to have?

BoxAndWhisker.zip (16.0 KB)

1 Like

I took a look at it and I like the aesthetic of this box and whisker plot. It does accurately resembles a box and whisker more. I think the hard part will be the way I have to get data into this graph. I have one dataset tag with 17 columns of many values in that dataset as shown below.

Is your dataset tag the recorded temperature readings? If so, I’d set up some kind of gateway task to regularly calculate the quartile data for each TC. You could store these calculation results in a separate dataset tag (or maybe a document tag?).

Then on the Box and Whisker chart, bind the props.data property to your calculated values tag and apply any script transforms needed to create the objects that the chart expects.

So far I have tagged the min, max and median markers. As you can see its not quite right and I tried to work with the values to get the box to match up to the markers but nothing I was doing seems to work well. Do I need to figure out the max of the median and the median of the max for example to make the graph look better?

You need to use the parameters on the embedded view in the Example window, and not touch anything inside of the view named Template. There’s some scripting happening to get everything to render properly. See the picture I posted above for a reference.


I have to apologize, when you said data I figured you meant the datasource elements. But yes, when I tagged the data in the proper place the graph looks really great. I can’t thank you enough for the help. the last small question I have is for the values of q1 and q3, that would technically but the high and low of the median value right? What expression do you usually use for grabbing that data?
EDIT: I am taking the standard deviation and adding to the median for my Q3 value and subtracting it from the median for my Q1 value.

Great, I’m glad you were able to get it working!

Q1 and Q3 refer to quartile 1 and quartile 3, which are the median of the lower half of the data set and the median of the upper half of the data set respectively.

First calculate the median of your dataset. Then, group all the values less than the median and group all the values greater than the median. Taking the median of the lower set will give you Q1 and taking the median of the upper set will give you Q3.

Graphing median ± SD is probably not very useful; it’s possible for the median + SD to be greater than the maximum sampled value.

Edit: misused mean instead of median.

This is not a correct description of quartiles. Q2 is the median of the entire dataset. Q1 is the median of the lower half (not below the mean, below the median). Q3 is the median of the upper half.

(Even that description is a bit fuzzy, as it doesn’t address what to do when the number of samples doesn’t divide up neatly.)

1 Like

Oops, you’re absolutely right. Mean is incorrect, median is what you need.

The point still stands about median +- SD though.

1 Like

I get what I have to do: Split the dataset by taking the median, then taking the median again of the upper half and lower half from the original median that was taken. I am struggling on how to do that through an expression binding. Any input on that would be appreciated

Don't split the dataset. Just make a list of all the values, and sort it. Take the subscript of the last value (length - 1) and multiply it by ¼, ½, and ¾. Where those are integers, that is the subscript of the value for that quartile. If there's a fraction, round down and up for your subscripts, and interpolate between those values.

( Use a script transform. )

1 Like

So I have the dataset sorted in ascending order. When you say take a subscript of the last value (length -1). I am not quite sure want you mean there.

I think he means the index value. Once you have a list of all your values, find the length and minus 1 then get your indexes for the quartiles like below

myList = (1,2,4,5,7,8,9,12,13,13,14)
nodeCnt = len(myList) - 1
q1_ndx = nodeCnt * .25
q2_ndx = nodeCnt * .5
q3_ndx = nodeCnt * .75

print q1_ndx, q2_ndx, q3_ndx   #Result is 2.75, 5.5, and 8.25

Once you have these values, if it is a fraction, round up and round down to get the index values needed to average the actual values. For example, for q1 in my script, the index value is 2.75. There is no 2.75 index, so round up and down to get 2 and 3. Quartile 1 will be the average of indexes 2 and 3

q1 = (myList[2]+myList[3]/2)

EDIT
An easier way is to use system.math.percentile()

myList = (1,2,4,5,7,8,9,12,13,13,14)
q1 = system.math.percentile(myList,25)
q2 = system.math.percentile(myList,50)
q3 = system.math.percentile(myList,75)
2 Likes