Building a 2D histogram

Hi, I'm trying to build a 2D histogram from scratch rather than using the jointhistogram function as an exercise.

I'm trying to create an image of a 2D wave.  I fill the bins in of the 2D wave with Tdiff and Ltyp. 

I think I have the basics down, but I get the error message "Index out of range for wave "wave2D. " I shifted the numbers so they're all positive.  i'm still coming up with an empty cell.

 

function TwoDHist(Ltyp,Tdiff, RangeToF, RangePSD,BinNumber)
    wave Tdiff, Ltyp
    variable BinNumber, RangePSD, RangeToF
    variable i, N=numpnts(Tdiff), ToFIndex, PSDIndex
   
    Make/N=(800,800)/O wave2D = 0
    for (i=0; i<N; i+=1)
        ToFIndex = floor(Tdiff[i]/(RangeToF/BinNumber)) // divided by bin widths. Shift by 1750 to account for all numbers
        PSDIndex = floor(Ltyp[i]/(RangePSD/BinNumber)) // Also shifted by 1750 
        if ((220 < ToFIndex) && (ToFIndex < 800) && (799 < PSDIndex) && (PSDIndex < 800))  //ToF and PSD index must be within this range.
            wave2D [ToFIndex][PSDindex]=+1   // Select ToF and PSD coordinate, put 1 in corresponding cell.
        endif
    endfor

NewImage wave2D
ModifyImage wave2D ctab= {*,*,Terrain,0}

end

 

Hi. I get that you want to try to do this as an exercise, but the JointHistogram function is really nice. Also there is a snippet on here which has some nice code to do 2D histograms that you could learn from. Anyway:

  • If Tdiff and Ltyp are not the same length, specifically if Tdiff is shorter than Ltyp, your code will give out of range at values of i beyond the length of Ltyp.
  • Second problem I see is that ToFIndex or PSDIndex will not be whole integers. This gives a problem with the assignment of wave2D.
  • The 3rd line in your loop doesn't make sense to me and I don't understand what you're trying to do here.  

We also ship a WaveMetrics procedure that predates the JointHistogram operation. Put this near the top of your Procedure window and then compile:

#include <Bivariate Histogram 2>

You can view the code by selecting the procedure window from Windows->Procedure Windows.

In reply to by johnweeks

That code won't let me input single float 32 bit waves.  I could convert them to double float 64 bit but I'm afraid that some data is lost. This is the reason for using the event-mode data so there's minimal loss.

In reply to by sjr51

I've seen the snippets, I think I'd prefer to be able to do this conceptually across other languages.

  • The waves are the same length.  Not all cells are filled, but I'm just assuming the empty cells will register as 0's.
  • What problem are you referring to for the assignment of wave2D? Can the cells not be assigned by non integers?
  • I updated the code with better comments so I hope the loops make more sense.  

In reply to by j s s

j s s wrote:

That code won't let me input single float 32 bit waves.  I could convert them to double float 64 bit but I'm afraid that some data is lost. This is the reason for using the event-mode data so there's minimal loss.

Are you referring to the code in the WM procedure Bivariate Histogram 2? That code makes no restriction on the number type of the waves you feed it.

I am also a bit puzzled by your fear of losing data if you convert 32-bit floats to 64-bit floats. It would seem that converting to greater precision would only preserve your lower procision.

Blank cells are filled with NaN (not-a-number). The IEEE standard requires that all tests involving NaN should return false. So you can have paradoxical results like this:

Function Paradox()
    Variable dum=NaN
    if (dum < 0)
        print "dum is less than zero"
    else
        print "dum is not less than zero"
    endif
    if (dum >= 0)
        print "dum is greater than zero"
    else
        print "dum not greater than or equal to zero, it must be less than zero"
    endif
end

which, when run does this:

•paradox()
  dum is not less than zero
  dum not greater than or equal to zero, it must be less than zero

 

In reply to by johnweeks

I was referring to the macro GUI for bivariate histogram 2. I guess less about losing data, I'm just not sure what the data conversion is and I would prefer to keep the event-mode data as is.

In reply to by j s s

j s s wrote:

  • I updated the code with better comments so I hope the loops make more sense.  

OK I think I understand. However, now the code doesn't work because you will shoot through i and end with your two variables set at the last (N-1) row value and then only assign one cell in your matrix. If you put the line back in the loop, the line should read:

wave2D[PSDindex][ToFIndex] += 1

If you want the rest of the values to = 0 you can do

Make/N=(850,850)/O wave2D=0

When you make the wave.

Just to reiterate my two cents on this, the other three code options for this task are solid.

In reply to by sjr51

Edited my code to move that statement into the for loop, but i'm still getting a blank 2D wave. 

I've tried using jointhistogram snippets and the bivariate histogram code but I still return with either an empty wave or a wave that doesn't make sense, so I'm trying to control as much of the code as I can.  I think my ranges might be affecting the build of the 2D wave.

Thanks for all the help.

In reply to by j s s

j s s wrote:

I've tried using jointhistogram snippets and the bivariate histogram code but I still return with either an empty wave or a wave that doesn't make sense

Well, now I'm curious about it. Could you attach an Igor experiment file with two waves from which you want to get a bivariate histogram?

No worries - you could post a pxp with the two waves and your function. I'm just suggesting code improvements without helping you get to a solution. You might get more help from the forum if you post an example.

I see a problem with your if statement which means you'll get a blank 2D wave. That condition cannot be satisfied

if ((220 < ToFIndex) && (ToFIndex < 800) && (799 < PSDIndex) && (PSDIndex < 800))

There are no integers greater than 799 and less than 800. So your assignment will never run. You can test that by enabling the debugger and creating a breakpoint (red circle in the margin of procedure window) at your assignment line. If the debugger doesn't kick in, you know that the condition of the if statement has not been met.

This is a common problem in Igor... Your wave Ltyp11 is a 2D wave with dimensions of 312501 x 1. Without any loss of data you can redimension it to have zero columns: 

Redimension/N=-1 Ltyp11

and now you can select it in the GUI for Bivariate Histogram 2.