Sunday, February 4, 2018

I Thank All Those Responsible for Creating LiveCode's Data Grid Object

I have known about LiveCode's data grid object for a long time. I explored it briefly soon after I started learning LiveCode and recognized immediately how useful it would be. But, I found that learning to use it would require some time and so I waited for a project that needed it. Well, that time has finally come. Now that I've learned the fundamentals of a data grid, I am so grateful that someone, or some team, took the time to create it.

Why I Needed a Data Grid

A data grid is simply a way to present data in a table-style format, similar to a table in Word or an Excel spreadsheet. (You can also display data in a label-style format.) Let me explain why I needed it. In my Q sort tool I provide a report to users that lists how related their Q sort results are to each and every other person who did the sort. This relationship is expressed by a correlation coefficient ranging from +1 to -1 where +1 is a perfect, positive correlation and -1 is a perfect negative correlation. Perfect correlations never happen in the social sciences - at least I've never seen one. Instead one gets a number somewhere in-between. A strong positive number indicates that the two people's sorts share a statistical relationship in the same direction. That is, their Q sorts indicate a shared point of view. They are of like minds. A strong negative number also indicates a statistical relationship, but in the opposite direction. To use the example of ice cream flavors, two people who seem to like or dislike the same flavors would have a strong positive correlation number, whereas two people who have very different tastes would have a strong negative number: "I love chocolate, but I hate pistachio." "Really? I hate chocolate but love pistachio."

Up to now, I've been displaying these data to the user within a simple, hard to read - and ugly - text field:

Ugliness aside, I've also found that some people misinterpret the data mainly because they don't necessarily see the all important comma in the right column in-between the person's name and the correlation. The zig zagging right edge of the data also makes it tough to read. I also have many non-US people who grew up using the comma instead of the period as the decimal point. This causes further confusion.

In contrast, a data grid allows the same data to be displayed in a clearer, neatly arranged, table-style format:

So, How Does a Data Grid Work?

A data grid is actually a group of interrelated LiveCode objects all tied together with special scripts unique to a data grid. For example, each cell in a data grid is actually a text field. To get all of the individual fields to work together requires a family of specialized scripts that have been programmed into the data grid object. I again thank the person or people who took the time many years ago to create the data grid object and for including a complete set of specialized commands and functions to control it using scripts.

I have only scratched the surface of the capabilities of a data grid so far in my Q sort tool. I learned about the fundamentals of a data grid by going through much of the following LiveCode tutorial:

I highly recommend this tutorial to anyone who is about to use data grids for the first time with the caveat that you will need some time and patience. It's not difficult, but there are a lot of nonintuitive details to master. I also recommend creating some "toy projects" at first so you can play around with the data grid and the associated scripts before trying to plug a data grid into one of your real projects. The frustration for me was that I have finally come to "think in LiveCode" but the data grid scripts weren't following my grasp of the LiveCode language. It was kind of like traveling to another part of the country where everyone speaks a different dialect with a very strong accent. You know they're speaking English, but you're just not sure what the person said.

Examples of a Few Key Scripts

First, it's easy to populate a data grid manually using the property inspector. However, I needed to learn how to populate it with scripts. The first script I learned wasn't very hard - you just need to use a comma to delineate between cells on a row, then add a line return at the end of the row. This example comes straight from the tutorial:

1:  on mouseUp   
2:     ## Create tab delimited data.   
3:     ## Note that first line has name of columns.   
4:     ## Providing names tells Data Grid how to map   
5:     ## data to appropriate columns.    
6:     put "Live" & tab & "Code" & cr & \   
7:           "ALABAMA" & tab & "AL" & cr & \   
8:           "ALASKA" & tab & "AK" into theText   
9:     ## Let Data Grid know that first line has column names   
10:     put true into firstLineContainsColumnNames   
11:     set the dgText [ firstLineContainsColumnNames ] of group "DataGrid 1" to theText   
12:   end mouseUp   

Line 11, the line that actually puts the data into the data grid, is really the only line of script that I didn't already know. If this were just a regular ol' text field, the script would have been this:

put theText into field "myData"

Let's consider how to sort data, first in a in a regular text field where each line has some comma delimited text, such as the name of a country followed by its capital (e.g. USA, Washington DC). This script sorts the entire field by the name of the country:

sort field "list" ascending by item 1 of each

To sort instead by the capital, we just change it to item 2:

sort lines of field "list" ascending by item 2 of each

Obviously, we can swap "ascending" with "descending" to reverse the sorting direction.

Here is the sort command for a data grid:

set the dgProps["sort by column"] of group "DataGrid" to "City"

Again, not a script one can conjure up with just an ordinary knowledge of LiveCode.

Another great thing about data grids is that they have sorting built into them. The user just needs to click on the header in either column to toggle the direction of the sort.

But, There's So Much More

I needed more functionality, such as clicking on a person's name and showing the correlation coefficients just for that person. I'll cut to the chase and show the entire script:

1:  global varComparisonSummaryDG, varAllComparisonsDG, varOneGroupOnlyDG  
2:  on mouseDown pMouseBtnNo  
3:    set the itemDelimiter to tab  
4:    dgMouseDown pMouseBtnNo  
5:    //Gets the number of the row clicked on  
6:    put the dgHilitedLines of me into L  
7:    //Gets the value of a column in a particular row  
8:    put GetDataOfLine(L, "Name") into varName  
9:    put varName into line 2 of field "comparison label"  
10:    //show field "one group only"  
11:    // put empty into field "one group onlyDG"  
12:    put empty into varOneGroupOnlyDG  
13:    set the dgData of group "One Group OnlyDG" to empty  
14:    put the number of lines of varAllComparisonsDG into M  
15:    repeat with i=1 to M  
16:     if line i of varAllComparisonsDG = varName then   
17:       repeat with j=i to M //after name is found, look for the next empty line  
18:        if item 1 of line j of varAllComparisonsDG is "SUM" then exit repeat  
19:       end repeat  
20:       put line i+1 to j-1 of varAllComparisonsDG into varOneGroupOnlyDG  
21:       set the dgText [ false ] of group "One Group OnlyDG" to varOneGroupOnlyDG  
22:       exit repeat  
23:     end if  
24:    end repeat  
25:    set the itemDelimiter to comma  
26:  end mouseDown  

Even as I look at this code now, a few days after I wrote it, I find it challenging to remember what all is going on. But here are the basics:

  • Line 6 puts the number of the line just clicked into the variable L.
  • Line 8 puts the data in the column "Name" into the variable varName.
  • Line 9 just puts the person's name in a label field near the top of the screen to make it clearer who is the person being compared.
  • The global variable varAllComparisonsDG contains all of the comparison data. Lines 15-24 systematically looks through all of this data to find the person's name. Once found, it notes where in the variable the data for this person is found in line numbers. (A variable holds data in a way that is similar to a field.)
  • Line 20 puts this data into a variable named varOneGroupOnlyDG
  • Line 21 puts the data in variable varOneGroupOnlyDG into the second data grid shown on the screen on the right.

And yes, there is so much more. A good place to browse is this web page showing all of the data grid properties. 

So I end this post with yet another shout out to those responsible for creating the data grid and making it available as a built-in tool for LiveCode. I don't know what I would have done without it.

Lloyd's LiveCode Blog Is No Longer MIA

Yes, it may have appeared that I've been "missing in action" when it comes to me writing about learning LiveCode. But, I want to assure all my readers - both of them - that my Learning LiveCode blog is alive and well. I haven't posted much lately mainly because I've been involved in deep dives of two very different LiveCode projects.

The first is a project that has some modest funding support in the area of agricultural education. For reasons mainly of confidentiality I've not written anything about that project despite spending an enormous amount of time on it over the past year or so. But, I think I'll be able to start writing about it soon. It's actually a very cool project and I've come up with an interesting prototype that the team likes and appears to be getting good reviews during the first field trials.

The second project has simply been doing some heavy duty tweaking of my Q sort tool. The tool itself remains fundamentally the same as when I wrote about it back in August. However, some of these tweaks have been fairly significant, such as switching to LiveCode's data grid object, also known as a table field. My next post will be about learning how to use a data grid. And, some new options are planned that I look forward to sharing here.

So, thanks for being patient and thanks for all those cards and letters asking where I've been. (Sorry, that last bit was a lie, but it felt good writing it.)