X

NV5 Geospatial Blog

Each month, NV5 Geospatial posts new blog content across a variety of categories. Browse our latest posts below to learn about important geospatial information or use the search bar to find a specific topic or author. Stay informed of the latest blog posts, events, and technologies by joining our email list!



Not All Supernovae Are Created Equal: Rethinking the Universe’s Measuring Tools

Not All Supernovae Are Created Equal: Rethinking the Universe’s Measuring Tools

6/3/2025

Rethinking the Reliability of Type 1a Supernovae   How do astronomers measure the universe? It all starts with distance. From gauging the size of a galaxy to calculating how fast the universe is expanding, measuring cosmic distances is essential to understanding everything in the sky. For nearby stars, astronomers use... Read More >

Using LLMs To Research Remote Sensing Software: Helpful, but Incomplete

Using LLMs To Research Remote Sensing Software: Helpful, but Incomplete

5/26/2025

Whether you’re new to remote sensing or a seasoned expert, there is no doubt that large language models (LLMs) like OpenAI’s ChatGPT or Google’s Gemini can be incredibly useful in many aspects of research. From exploring the electromagnetic spectrum to creating object detection models using the latest deep learning... Read More >

From Image to Insight: How GEOINT Automation Is Changing the Speed of Decision-Making

From Image to Insight: How GEOINT Automation Is Changing the Speed of Decision-Making

4/28/2025

When every second counts, the ability to process geospatial data rapidly and accurately isn’t just helpful, it’s critical. Geospatial Intelligence (GEOINT) has always played a pivotal role in defense, security, and disaster response. But in high-tempo operations, traditional workflows are no longer fast enough. Analysts are... Read More >

Thermal Infrared Echoes: Illuminating the Last Gasp of a Dying Star

Thermal Infrared Echoes: Illuminating the Last Gasp of a Dying Star

4/24/2025

This blog was written by Eli Dwek, Emeritus, NASA Goddard Space Flight Center, Greenbelt, MD and Research Fellow, Center for Astrophysics, Harvard & Smithsonian, Cambridge, MA. It is the fifth blog in a series showcasing our IDL® Fellows program which supports passionate retired IDL users who may need support to continue their work... Read More >

A New Era of Hyperspectral Imaging with ENVI® and Wyvern’s Open Data Program

A New Era of Hyperspectral Imaging with ENVI® and Wyvern’s Open Data Program

2/25/2025

This blog was written in collaboration with Adam O’Connor from Wyvern.   As hyperspectral imaging (HSI) continues to grow in importance, access to high-quality satellite data is key to unlocking new insights in environmental monitoring, agriculture, forestry, mining, security, energy infrastructure management, and more.... Read More >

1345678910Last
8420 Rate this article:
No rating

Reliable Scalar vs Array Determination

Anonym

In the past I’ve blogged about identifying undefined variablesvs !NULL and the perils of overriding IDL_Object methods, I’m here today in a related vein to talk about how to identify if a variable is a scalar or an array.

One may wonder why you would care, but there are certain situations where a scalar value and a 1-element array behave the same, and there are other situations where they don’t.  A very simple case is with the comparison operators and WHERE clauses:

IDL> a = IndGen(10)
IDL> Where(a GT 5)
           6           7           8           9
IDL> Where(a GT [5])
          -1

When I use a scalar threshold in the GT comparison, I get the expected results.  If that threshold is turned into a 1-element array, then I get -1 signaling no good values.  If we look at what the comparison expression inside the WHERE clause returns, we’ll see why:

IDL> a GT 5
   0   0   0   0   0   0   1   1   1   1
IDL> a GT [5]
   0

The scalar comparison returns an array of Boolean values the same dimensions as the “a” variable, while the array comparison returns a scalar.  This is because the GT comparison operator operates on subsets of the operands based on the smaller dimension:

IDL> a GT [0]
   0
IDL> a GT [-1]
   1
IDL> a GT [-1, 0, 1]
   1   1   1
IDL> a GT [-1, 0, 2]
   1   1   0

The GT operator is vectorized, and performs pairwise comparisons on the values at each corresponding index, up to the smaller maximum index.  This behavior is easy to identify when we use numeric literals, but if we were using a variable instead then you would have to inspect that variable to get the desired behavior.  One common source of 1-element arrays in my work is the WHERE clause itself – the -1 failure return value is a scalar, but a successful return is always an array, be it one element or many.  A simple solution to this is to always index your variables at index 0 to make them scalar, but if you truly want an array then you have to be careful where you use that index to “scalarify” the variable.

IDL> a = 5
IDL> b = [a]
IDL> help, a, b, a[0], b[0]
A               INT       =        5
B               INT       = Array[1]
<Expression>    INT       =        5
<Expression>    INT       =        5

List and Hash Woes

Another common mistake for scalar vs 1-element array differences is when working with List and Hash objects.  When you use the square bracket index operator with a scalar value, it returns the element that corresponds to that index, but if you use an array, it returns a new List or Hash containing copies of that appropriate element(s):

IDL> l = List(1,2,3,4)
IDL> help, l[2]
<Expression>    INT       =        3
IDL> help, l[[2]]
<Expression>    LIST  <ID=10  NELEMENTS=1>
IDL> print, l[[2]]
       3

This makes a big difference, and is easy to do if you use a WHERE clause or the List or Hash Where() method, as they always return arrays, even in the 1-element case.  This behavior is documented, towards the bottom of the List and Hash help pages, about how to set or get a single element versus many.

Identifying a Scalar

So now that we have covered why it is important to know when a given variable is a scalar or an array, the question arises of how to reliably do this.  The classic answer is to test the return value of N_ELEMENTS() or to call ISA(/SCALAR), but there are times when this will yield incorrect results.  With the introduction of IDL_Object in 8.0, classes can inherit and override the _overloadSize()method, which is just what List and Hash objects do.  When you call N_ELEMENTS() or even SIZE(/DIMENSIONS) on a List or Hash, you get back the number of elements in the object, not the number of objects in your variable.

IDL> l = List(1,2,3,4)
IDL> N_Elements(l)
           4
IDL> Size(l, /DIMENSIONS)
           4
IDL> Size(l, /N_DIMENSIONS)
           1
IDL> ISA(l, /SCALAR)
   0

This is even more confusing with an empty List or Hash:

IDL> l = List()
IDL> N_Elements(l)
           0
IDL> Size(l, /DIMENSIONS)
           0
IDL> Size(l, /N_DIMENSIONS)
           0
IDL> ISA(l, /SCALAR)
   1

As I showed in the blog about IDL_Object caveats, you can scope a function call to the base class to get the expected result, but it is awkward looking:

IDL> l.IDL_Object::_overloadSize()
           1

I’ve had to deal with this over and over again, and the best solution I’ve come up with relies on the fact that the Obj_Valid() function will return a Boolean value with the same dimensions as the input argument.  So if I pass in a scalar object a scalar Boolean is returned,  a 1-element array of objects returns a 1-element array of Booleans, and an N-dimensional array of objects returns an N-dimensional array of Booleans.  I can then take the return of Obj_Valid() and pass it into ISA(/SCALAR).  Thanks to a ternary operator, this can be coded up as a one line function:

function isScalar, value
  compile_opt idl2
 
  return, ISA((Size(value, /TYPE) eq 11) $
              ? Obj_Valid(value) : value, $
              /SCALAR)
end

I have tested this with scalar, 1-element, and multi-element arrays of numbers, strings, pointers (null and valid), List and Hash objects, and normal objects (null and valid).  The only time you might get an unexpected result from this function is with a “scalar struct” variable, which is a construct that IDL doesn’t support.  Even if you create a single anonymous struct with only one tag, it is considered a 1-element array:

IDL> s = { foo : 1 }
IDL> N_Elements(s)
           1
IDL> Size(s, /DIMENSIONS)
           1
IDL> Size(s, /N_DIMENSIONS)
           1
IDL> ISA(s, /SCALAR)
   0

So if you need to differentiate between a single struct and an array of many structs, then testing the N_ELEMENTS() return is the way to go, and could be added to the isScalar() function.

Note: I could also have used Obj_ISA(), but timing tests revealed that Obj_Valid() is faster.

Please login or register to post comments.