* build a summary table
build a summary table
I am needing to build a plugin that is somewhat akin to the Tools>Work with data> addresses display
What i will do is, grab a source, it could be FaG, could be the 1920 Census, whatever.
find the source, go to the parent, get the addr field , I believe I have rtvRcdGob code that I can make work for that.
THEN THE MAGIC
if it is not in the table, add to table, add 1 to used.
if it is in the table, , add 1 to used.
fhcolumnoutput tblAddr tblused (one line if I can)
sloshing around it seems pairs or pairs would work, but for me the documentation of them is not cogent, nor do the examples seem to work for me, in a way I can associate to and modify.
am I even on the right track, what are the real coders recommendations here?
Thanks in advance.
What i will do is, grab a source, it could be FaG, could be the 1920 Census, whatever.
find the source, go to the parent, get the addr field , I believe I have rtvRcdGob code that I can make work for that.
THEN THE MAGIC
if it is not in the table, add to table, add 1 to used.
if it is in the table, , add 1 to used.
fhcolumnoutput tblAddr tblused (one line if I can)
sloshing around it seems pairs or pairs would work, but for me the documentation of them is not cogent, nor do the examples seem to work for me, in a way I can associate to and modify.
am I even on the right track, what are the real coders recommendations here?
Thanks in advance.
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
So you want to produce a Result Set of Addresses and Usage counts.
Start with a table that has the Address as the index and the Usage as the value at that index.
local strAddr = "" holds the Address
local tblAddr = { }
When strAddr has been loaded with an Address the following will update the Usage count :-
tblAddr[strAddr] = ( tblAddr[strAddr] + 1 ) or 1
When all the Addresses have been found you need to put the Address and Usage into two Result Set tables :-
local tblAddress = { }
local tblUsage = { }
for strAddress, intUsage in pairs (tblAddr) do
table.insert(tblAddress,strAddress)
table.insert(tblUsage,intUsage)
end
Start with a table that has the Address as the index and the Usage as the value at that index.
local strAddr = "" holds the Address
local tblAddr = { }
When strAddr has been loaded with an Address the following will update the Usage count :-
tblAddr[strAddr] = ( tblAddr[strAddr] + 1 ) or 1
When all the Addresses have been found you need to put the Address and Usage into two Result Set tables :-
local tblAddress = { }
local tblUsage = { }
for strAddress, intUsage in pairs (tblAddr) do
table.insert(tblAddress,strAddress)
table.insert(tblUsage,intUsage)
end
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
LOL, you knew I would be back, still magic to me, the err is shown as **ERR in the code, I dont know what the statement nor the error means...
Code: Select all
--[[
@title: LstLoc
@author: Ron Melby
@lastupdated: Apr 2018
@version: 1.0
@description: List Summary Locations for a source report
]]
-- rtvSrcRcds
function rtvSrcRcds(SrcTag, parmSOUR)
local ptr = fhNewItemPtr()
ptr:MoveToFirstRecord('INDI')
while ptr:IsNotNull() do
if fhGetTag(ptr) == SrcTag then -- SrcTag Source being searched for
local ptrLink = fhGetValueAsLink(ptr)
if ptrLink:IsSame(parmSOUR) then
wrtTbls(ptr, parmSOUR)
end
end
ptr:MoveNextSpecial() --set to next TAG
end
end -- fn rtvSrcRcds
-- wrtTbls
function wrtTbls(ptr, parmSOUR)
local strLoc = "" -- holds the Location
local ptrINDI = fhNewItemPtr() -- INDI ptr
local ptrWork = fhNewItemPtr() -- offset ptr
local ptrLoc = fhNewItemPtr() -- PLAC or ADDR ptr (needs Parm)
local tblLoc = { } -- All locations of source
local tblLocation = { } -- location summary of source
local tblUsage = { } -- count of summary location instances
-- Get INDI offset
ptrINDI:MoveToRecordItem(ptr)
-- EVENT
ptrWork:MoveToParentItem(ptr)
-- Loc or disposition
local TAG = '~.' ..(fhGetTag(ptrWork))
ptrLoc = (TAG.. '.ADDR')
ptrWork:MoveTo(ptrINDI, ptrLoc)
if ptrWork:IsNull() then
ptrLoc = (TAG.. '.NOTE2')
ptrWork:MoveTo(ptrINDI, ptrLoc)
end
strLoc = fhGetValueAsText(ptrWork)
table.insert(tblLoc, strLoc)
-- When strLoc has been loaded
-- the following will update the Usage count
tblLoc[strLoc] = (tblLoc[strLoc] + 1) or 1 <**ERR attempt to perform arithmetic on field '?' (a nil value)
-- When all the Locationes have been found you need to
-- put the Location and Usage into two Result Set tables :-
for strLocation, intUsage in pairs (tblLoc) do
table.insert(tblLocation,strLocation)
table.insert(tblUsage,intUsage)
end
end -- fn wrtTbls
-- Main Code
tblParm = {} -- Source to report
-- Prompt for Source
local tblParm = fhPromptUserForRecordSel('SOUR',1)
-- nothing chosen
if #tblParm == 0 then
fhMessageBox('Plugin Cancelled')
return
end
--if citation has no links
local iCitations = fhCallBuiltInFunction('LinksTo', tblParm[1])
if iCitations == 0 then
fhMessageBox('No Citations Found')
return
end
local parmSOUR = tblParm[1]
rtvSrcRcds('SOUR', parmSOUR)
-- Output Tables built to Results Window
fhOutputResultSetColumn("Location", "text", tblLocation, #tblLocation, 256, "align_left", 1)
fhOutputResultSetColumn("Occurs", "text", tblUsage, #tblUsage, 48, "align_left")
return
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
Sorry, my mistake it should have been
tblAddr[strAddr] = ( tblAddr[strAddr] or 0 ) + 1
what that says is take the value from existing tblAddr[strAddr] entry, but if missing use 0, then add 1.
It seems from your script that you are only searching INDIvidual records for matching Source Citations.
That would exclude matching Source Citations on say Marriage and Divorce facts in FAMily records.
tblAddr[strAddr] = ( tblAddr[strAddr] or 0 ) + 1
what that says is take the value from existing tblAddr[strAddr] entry, but if missing use 0, then add 1.
It seems from your script that you are only searching INDIvidual records for matching Source Citations.
That would exclude matching Source Citations on say Marriage and Divorce facts in FAMily records.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
the 0 or 1 part of it I got, its before that, what that means.
And yes, you bring up a good point, now I have to figure out how to hit the Fam Records
for (indi, fam) do or something I suppose
here is the current code, it runs without error, but very strange reults:
I am expecting (ie):
*burial unknown. 15
* burial unknown. Body donated to medical science. 1
St. Mildred's Churchyard, , Tenterden, Kent, EN, GBR 1098
St. Mchaels Churchyard, , Bethersden, Kent, EN, GBR 186 ....
and so on, some have the index in the location some in the usage
and they are not 'rolled up'.
and I see nothing wrong with my ptrWork:ADDR or NOTE2 logic.
And yes, you bring up a good point, now I have to figure out how to hit the Fam Records
for (indi, fam) do or something I suppose
here is the current code, it runs without error, but very strange reults:
I am expecting (ie):
*burial unknown. 15
* burial unknown. Body donated to medical science. 1
St. Mildred's Churchyard, , Tenterden, Kent, EN, GBR 1098
St. Mchaels Churchyard, , Bethersden, Kent, EN, GBR 186 ....
and so on, some have the index in the location some in the usage
and they are not 'rolled up'.
and I see nothing wrong with my ptrWork:ADDR or NOTE2 logic.
Code: Select all
--[[
@title: LstLoc
@author: Ron Melby
@lastupdated: Apr 2018
@version: 1.0
@description: List Summary Locations for a source report
]]
-- rtvSrcRcds
function rtvSrcRcds(SrcTag, parmSOUR)
local ptr = fhNewItemPtr()
ptr:MoveToFirstRecord('INDI')
while ptr:IsNotNull() do
if fhGetTag(ptr) == SrcTag then -- SrcTag Source being searched for
local ptrLink = fhGetValueAsLink(ptr)
if ptrLink:IsSame(parmSOUR) then
wrtTbls(ptr, parmSOUR)
end
end
ptr:MoveNextSpecial() --set to next TAG
end
end -- fn rtvSrcRcds
-- wrtTbls
function wrtTbls(ptr, parmSOUR)
local strLoc = "" -- holds the Location
local ptrINDI = fhNewItemPtr() -- INDI ptr
local ptrWork = fhNewItemPtr() -- offset ptr
local ptrLoc = fhNewItemPtr() -- PLAC or ADDR ptr (needs Parm)
local tblLoc = { } -- All locations of source
-- Get INDI offset
ptrINDI:MoveToRecordItem(ptr)
-- EVENT
ptrWork:MoveToParentItem(ptr)
-- Loc or disposition
local TAG = '~.' ..(fhGetTag(ptrWork))
ptrLoc = (TAG.. '.ADDR')
ptrWork:MoveTo(ptrINDI, ptrLoc)
if ptrWork:IsNull() then
ptrLoc = (TAG.. '.NOTE2')
ptrWork:MoveTo(ptrINDI, ptrLoc)
end
strLoc = fhGetValueAsText(ptrWork)
table.insert(tblLoc, strLoc)
-- When strLoc has been loaded
-- the following will update the Usage count
tblLoc[strLoc] = (tblLoc[strLoc] or 0) + 1
-- When all the Locationes have been found you need to
-- put the Location and Usage into two Result Set tables :-
for strLocation, intUsage in pairs (tblLoc) do
table.insert(tblLocation,strLocation)
table.insert(tblUsage,intUsage)
end
end -- fn wrtTbls
-- Main Code
tblLocation = { } -- location summary of source
tblUsage = { } -- count of summary location instances
tblParm = {} -- Source to report
-- Prompt for Source
local tblParm = fhPromptUserForRecordSel('SOUR',1)
-- nothing chosen
if #tblParm == 0 then
fhMessageBox('Plugin Cancelled')
return
end
--if citation has no links
local iCitations = fhCallBuiltInFunction('LinksTo', tblParm[1])
if iCitations == 0 then
fhMessageBox('No Citations Found')
return
end
local parmSOUR = tblParm[1]
rtvSrcRcds('SOUR', parmSOUR)
-- Output Tables built to Results Window
fhOutputResultSetColumn("Location", "text", tblLocation, #tblLocation, 256, "align_left", 1)
fhOutputResultSetColumn("Occurs", "text", tblUsage, #tblUsage, 48, "align_left")
return
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
On line 50 do NOT use table.insert(tblLoc, strLoc) as that is what upsets the tblLoc entries.
You would see that in Plugin editor/debug mode if you view that table contents each time it gets changed.
tblLoc[strLoc] creates a table entry indexed by strLoc whereas most tables you have used so far are indexed by a number.
e.g.
table.insert(tblLoc, strLoc) is the same as tblLoc[#tblLoc+1] = strLoc
So its first use performs tblsLoc[1] = strLoc
Its second use performs tblsLoc[2] = strLoc and so on...
Whereas tblLoc[strLoc] is using the address text string as the index, i.e. it is a dictionary.
To include FAMily records add an extra loop to function rtvSrcRcds
You would see that in Plugin editor/debug mode if you view that table contents each time it gets changed.
tblLoc[strLoc] creates a table entry indexed by strLoc whereas most tables you have used so far are indexed by a number.
e.g.
table.insert(tblLoc, strLoc) is the same as tblLoc[#tblLoc+1] = strLoc
So its first use performs tblsLoc[1] = strLoc
Its second use performs tblsLoc[2] = strLoc and so on...
Whereas tblLoc[strLoc] is using the address text string as the index, i.e. it is a dictionary.
To include FAMily records add an extra loop to function rtvSrcRcds
Code: Select all
for _, strType in ipairs ( { 'INDI'; 'FAM'; } ) do
ptr:MoveToFirstRecord(strType)
while ptr:IsNotNull() do
: : : :
ptr:MoveNextSpecial() --set to next TAG
end
end
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
The table fills out correctly as far as it goes, I watched it wrtTbls 40-50 times, and inspected variables
I then threw a throwaway **DEBUG in wrtOutput and see absolutely nothing wrong and it fails, (or ends) with 13 records output, silently. I can find nothing wrong with the records., what should I be debuggins? or what jumps out?
I then threw a throwaway **DEBUG in wrtOutput and see absolutely nothing wrong and it fails, (or ends) with 13 records output, silently. I can find nothing wrong with the records., what should I be debuggins? or what jumps out?
Code: Select all
--[[
@title: LstLoc
@author: Ron Melby
@lastupdated: Apr 2018
@version: 1.0
@description: List Summary Locations for a source report
]]
-- rtvSrcRcds
function rtvSrcRcds(SrcTag, parmSOUR)
local ptr = fhNewItemPtr()
-- declare pointer
for _, rType in ipairs ( { 'INDI'; 'FAM'; } ) do -- Scan the Record Types
ptr:MoveToFirstRecord(rType)
while ptr:IsNotNull() do
if fhGetTag(ptr) == SrcTag then -- SrcTag Source being searched for
local ptrLink = fhGetValueAsLink(ptr) -- cast to same type ptr
if ptrLink:IsSame(parmSOUR) then
local ptrLink = fhGetValueAsLink(ptr)
wrtTbls(ptr, parmSOUR)
end
end
ptr:MoveNextSpecial() --set to next TAG
end
end
end -- fn rtvSrcRcds
-- wrtTbls
function wrtTbls(ptr, parmSOUR)
local strLoc = "" -- holds the Location
local ptrINDI = fhNewItemPtr() -- INDI ptr
local ptrWork = fhNewItemPtr() -- offset ptr
local ptrLoc = fhNewItemPtr() -- PLAC or ADDR ptr (needs Parm)
-- Get INDI offset
ptrINDI:MoveToRecordItem(ptr)
-- EVENT
ptrWork:MoveToParentItem(ptr)
-- Loc or disposition
local TAG = '~.' ..(fhGetTag(ptrWork))
ptrLoc = (TAG.. '.ADDR')
ptrWork:MoveTo(ptrINDI, ptrLoc)
if ptrWork:IsNull() then
ptrLoc = (TAG.. '.NOTE2')
ptrWork:MoveTo(ptrINDI, ptrLoc)
strLoc = fhGetValueAsText(ptrWork)
len = string.len(strLoc)
if len > ix1 then
ix1 = len
end
-- When strLoc has been loaded
-- the following will update the Usage count
tblLoc[strLoc] = (tblLoc[strLoc] or 0) + 1
end
end -- fn wrtTbls
function bldOutput()
-- When all the Locations have been found you need to
-- put the Location and Usage into two Result Set tables
for strLocation, intUsage in pairs (tblLoc) do
**DEBUG
if (strLocation == "" or strLocation == nil) or (intUsage == nil or intUsage == 0) then
hold = hold never happens
end
table.insert(tblLocation,strLocation)
table.insert(tblUsage,intUsage)
end
end -- bldOutput
-- Main Code
tblLoc = { } -- All locations of source
tblLocation = { } -- location summary of source
tblUsage = { } -- count of summary location instances
tblParm = {} -- Source to report
ix1 = 0
-- Prompt for Source
local tblParm = fhPromptUserForRecordSel('SOUR',1)
-- nothing chosen
if #tblParm == 0 then
fhMessageBox('Plugin Cancelled')
return
end
--if citation has no links
local iCitations = fhCallBuiltInFunction('LinksTo', tblParm[1])
if iCitations == 0 then
fhMessageBox('No Citations Found')
return
end
local parmSOUR = tblParm[1]
rtvSrcRcds('SOUR', parmSOUR)
bldOutput()
ix1 = (ix1 * 4) + 16
-- Output Tables built to Results Window
fhOutputResultSetColumn("Location", "text", tblLocation, #tblLocation, ix1, "align_left", 1)
fhOutputResultSetColumn("Occurs", "text", tblUsage, #tblUsage, 16, "align_left")
return
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
It is your changes to function wrtTbls
If you check carefully, when there is an Address it does NOT update tblLoc[strLoc]
The end is in the wrong place.
BTW:
It would be more efficient to perform the length adjustment in function bldOutput where each strLocation only needs checking once.
e.g. ix1 = math.max( ix1, #strLocation )
math.max is one of the many useful maths functions and #strLocation is shorthand for string length.
Also, strictly speaking the "Occurs" column should be "integer" instead of "text".
If you check carefully, when there is an Address it does NOT update tblLoc[strLoc]
The end is in the wrong place.
BTW:
It would be more efficient to perform the length adjustment in function bldOutput where each strLocation only needs checking once.
e.g. ix1 = math.max( ix1, #strLocation )
math.max is one of the many useful maths functions and #strLocation is shorthand for string length.
Also, strictly speaking the "Occurs" column should be "integer" instead of "text".
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
and that is what I get for myopic assumptions in my debugs. an end was the end of me. I was looking at strLoc thinking that is where the funniness was, and did not debug the tlbLoc[strLoc] statement. Thank you, Mike. Interestingly, now that you pulled my head back, it fair jumps out at you and beats you over the head, doesn't it?
I have taken your points in integer, string.len and fixed those issues, I also changed the sort to the integer descending, its brill.
now, I am going to dive into iup for a simple pushbutton whether place or address is wanted. That simple thing will result in a thread that will bring down the entire internet, stand by.
by the way, is there a way (I know there is, but a more advanced idea than I am capable of) to associate a tbl with tblLoc, and keep it synched with tblLocation ? my idea would be a function to reverse the address, grab country, state, county from place on the same record slice and dice it (which I think I can do from earlier plugins we have done and discussed), have it end up on the order of:
USA.MN.Olmsted
GRB.EN.Kent
which I could put in a fhoutputcolumn in front of tblLocations:
Grandview Memorial Gardens....yadda yadda yadda
St. Mildred's Churchyard...blah blah blah
The thinking being a great sort field to easily generally locate these places in the event I should take a fancy to print it out and gallivant to an area and have a little lookie see.
I have taken your points in integer, string.len and fixed those issues, I also changed the sort to the integer descending, its brill.
now, I am going to dive into iup for a simple pushbutton whether place or address is wanted. That simple thing will result in a thread that will bring down the entire internet, stand by.
by the way, is there a way (I know there is, but a more advanced idea than I am capable of) to associate a tbl with tblLoc, and keep it synched with tblLocation ? my idea would be a function to reverse the address, grab country, state, county from place on the same record slice and dice it (which I think I can do from earlier plugins we have done and discussed), have it end up on the order of:
USA.MN.Olmsted
GRB.EN.Kent
which I could put in a fhoutputcolumn in front of tblLocations:
Grandview Memorial Gardens....yadda yadda yadda
St. Mildred's Churchyard...blah blah blah
The thinking being a great sort field to easily generally locate these places in the event I should take a fancy to print it out and gallivant to an area and have a little lookie see.
FH V.6.2.7 Win 10 64 bit
- PeterR
- Megastar
- Posts: 1135
- Joined: 10 Jul 2006 16:55
- Family Historian: V7
- Location: Northumberland, UK
Re: build a summary table
My simple Plugin, in the store, Address Summary Report does something similar, so it might provide a few ideas.
Peter Richmond (researching Richmond, Bulman, Martin, Driscoll, Baxter, Hall, Dales, Tyrer)
Re: build a summary table
it was the address summary report and place summary report that first gave me my bright idea, thank you for that.
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
You can do lots of extremely clever stuff with tables that are a very powerful data structure.
You want to associate two bits of data with an Address:
1) Its usage count
2) Its Place field
So consider a table structure local tblData = { Usage = 123; Place = "Kent, UK"; } or if you prefer:
local tblData = { }
tblData["Usage"] = 123
tblData["Place"] = "Kent. UK"
Both produce a dictionary table with two name indexed entries.
Thus instead of tblLoc[strAddr] = ( tblLoc[strAddr] or 0 ) + 1 you would use:
local tblData = tblLoc[strAddr] or { } to get existing data or create an empty table
local intUsage = ( tblData["Usage"] or 0 ) + 1 update the usage count similar to you do now
local strPlace = tblData["Place"] or strPLAC grab existing place or set new one from ~.PLAC field
tblLoc[strAddr] = { Usage = intUsage; Place = strPlace; } save the usage and place for address
Then later to build the Result Set tables:
for strLocation, tblData in pairs (tblLoc) do
table.insert(tblLocation,strLocation)
table.insert(tblUsage,tblData["Usage"])
table.insert(tblPlace,tblData["Place"])
end
BTW: Shorthand for tblData["Usage"] is tblData.Usage and for tblData["Place"] is tblData.Place
You want to associate two bits of data with an Address:
1) Its usage count
2) Its Place field
So consider a table structure local tblData = { Usage = 123; Place = "Kent, UK"; } or if you prefer:
local tblData = { }
tblData["Usage"] = 123
tblData["Place"] = "Kent. UK"
Both produce a dictionary table with two name indexed entries.
Thus instead of tblLoc[strAddr] = ( tblLoc[strAddr] or 0 ) + 1 you would use:
local tblData = tblLoc[strAddr] or { } to get existing data or create an empty table
local intUsage = ( tblData["Usage"] or 0 ) + 1 update the usage count similar to you do now
local strPlace = tblData["Place"] or strPLAC grab existing place or set new one from ~.PLAC field
tblLoc[strAddr] = { Usage = intUsage; Place = strPlace; } save the usage and place for address
Then later to build the Result Set tables:
for strLocation, tblData in pairs (tblLoc) do
table.insert(tblLocation,strLocation)
table.insert(tblUsage,tblData["Usage"])
table.insert(tblPlace,tblData["Place"])
end
BTW: Shorthand for tblData["Usage"] is tblData.Usage and for tblData["Place"] is tblData.Place
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
I've seen the post Mike, gonna take me a while to cipher on that one. I'll be back...
FH V.6.2.7 Win 10 64 bit
Re: build a summary table
I tried it and have failed miserably.
Area Location occurs
USA.MN.Olmsted Pleasant Prarie Cemetery, Prairie Vista Drive NW, Rochester, MN, , USA 47
USA.MN.Olmsted Oakwood Cemetery, 38 7th Avenue NE, Rochester, MN, 55906, USA 12
GBR.EN.Kent St. Mildred''s Churchyard, , Tenterden, Kent, EN, GBR' 11
USA.MN.Crow Wing Greenwood Cemetery, , Bemidji, MN, , USA 19
this is what I expect my output to be, each part I do well. I have Area, I have Location, I have occurs. what I dont have is output, part of my trouble being I cannot debug sucessfully [table .1] and the other part not being able to understand pairs and ipairs here is the code, the trouble is in wrtTbls function, or in BldOutput function. while it would also be real handy to have occurances of area as you see it is not unique, however if I put the column in and it said 59 2 times, it would not cause any visual or euphonic trauma. but, I cant even get output with what I have. I am not sure how to get my length from math.max as I bld tables for output, As I said, I have made a mess of it Here is the code:
Area Location occurs
USA.MN.Olmsted Pleasant Prarie Cemetery, Prairie Vista Drive NW, Rochester, MN, , USA 47
USA.MN.Olmsted Oakwood Cemetery, 38 7th Avenue NE, Rochester, MN, 55906, USA 12
GBR.EN.Kent St. Mildred''s Churchyard, , Tenterden, Kent, EN, GBR' 11
USA.MN.Crow Wing Greenwood Cemetery, , Bemidji, MN, , USA 19
this is what I expect my output to be, each part I do well. I have Area, I have Location, I have occurs. what I dont have is output, part of my trouble being I cannot debug sucessfully [table .1] and the other part not being able to understand pairs and ipairs here is the code, the trouble is in wrtTbls function, or in BldOutput function. while it would also be real handy to have occurances of area as you see it is not unique, however if I put the column in and it said 59 2 times, it would not cause any visual or euphonic trauma. but, I cant even get output with what I have. I am not sure how to get my length from math.max as I bld tables for output, As I said, I have made a mess of it Here is the code:
Code: Select all
--[[
@title: LstLoc
@author: Ron Melby
@lastupdated: Apr 2018
@version: 1.0
@description: List Summary Locations for a source report
You can do lots of extremely clever stuff with tables that are a very powerful data structure.
You want to associate two bits of data with an Address:
1) Its usage count
2) Its Place field
So consider a table structure local tblData = { Usage = 123; Place = "Kent, UK"; } or if you prefer:
local tblData = { }
tblData["Usage"] = 123
tblData["Place"] = "Kent. UK"
Both produce a dictionary table with two name indexed entries.
]]
function getArea(ptrRCD, rcdOffset)
local ptrRCD = ptrRCD
local rcdOffset = (rcdOffset .. ".PLAC")
local ptrLoc = fhNewItemPtr()
local ptrWork = fhNewItemPtr() -- offset ptr
local zip = "^ -%d+%-?%d+ -$"
local arrLOC = {}
local strArea = ""
local field = ""
local index = 1
strArea = fhGetItemText(ptrRCD, rcdOffset)
if strArea == "" then
return " . ."
end
for field in string.gmatch(strArea, "([^,]+)") do
arrLOC[index] = field
index = index + 1
end
index = index - 1
strArea = ""
while index > 2 do
-- field = arrLOC[index]
field = (arrLOC[index]:gsub("^%s*", ""))
if (index == 5) and ((field == " ") or (field == "")) then
field = " "
end
if (index == 4) and ((field == " ") or (field == "")) then
field = " "
end
if (index == 3) and ((field == " ") or (field == "")) then
field = " "
end
strArea = strArea .. field
if (index > 3)then
strArea = strArea .. "."
end
index = index - 1
end
return strArea
end
-- rtvSrcRcds
function rtvSrcRcds(SrcTag, parmSOUR)
local ptr = fhNewItemPtr()
-- declare pointer
for _, rType in ipairs ( { 'INDI'; 'FAM'; } ) do -- Scan the Record Types
ptr:MoveToFirstRecord(rType)
while ptr:IsNotNull() do
if fhGetTag(ptr) == SrcTag then -- SrcTag Source being searched for
local ptrLink = fhGetValueAsLink(ptr) -- cast to same type ptr
if ptrLink:IsSame(parmSOUR) then
local ptrLink = fhGetValueAsLink(ptr)
wrtTbls(ptr, parmSOUR)
end
end
ptr:MoveNextSpecial() --set to next rcdOffset
end
end
end -- fn rtvSrcRcds
-- wrtTbls
function wrtTbls(ptr, parmSOUR)
local strLoc = "" -- holds the Location
local ptrRCD = fhNewItemPtr() -- INDI ptr
local ptrWork = fhNewItemPtr() -- offset ptr
local ptrLoc = fhNewItemPtr() -- PLAC or ADDR ptr (needs Parm)
-- Get INDI offset
ptrRCD:MoveToRecordItem(ptr)
-- EVENT
ptrWork:MoveToParentItem(ptr)
-- Loc or disposition
local rcdOffset = '~.' ..(fhGetTag(ptrWork))
ptrLoc = (rcdOffset.. '.ADDR')
ptrWork:MoveTo(ptrRCD, ptrLoc)
if ptrWork:IsNull() then
ptrLoc = (rcdOffset.. '.NOTE2')
ptrWork:MoveTo(ptrRCD, ptrLoc)
end
strLoc = fhGetValueAsText(ptrWork)
local strArea = getArea(ptrRCD, rcdOffset)
-- tblLoc[strLoc] = (tblLoc[strLoc] or 0) + 1
tblData = tblLoc[strLoc] or { }
strArea = tblData["Area"] or strArea
intOccur = (tblData["Occur"] or 0 ) + 1
tblData[strLoc] = { Area = strArea; Occur = intOccur;} -- Location = strLoc;
end -- fn wrtTbls
function bldOutput()
-- When all the Locations have been found you need to
-- put the Location and Occurance into two Result Set tables
for strLocation, _ in pairs (tblData) do
table.insert(tblLocation,tblData["Location"])
cw1 = math.max(cw1, #Location)
table.insert(tblArea,tblData["Area"])
cw2 = math.max(cw2, #Area)
table.insert(tblOccur,tblData["Occur"])
cw3 = math.max(cw3, #Occur)
end
end -- bldOutput
-- Main Code
tblData = {}
tblLoc = {}
tblLocation = {} -- Location (could be PLAC or ADDR depending on inparm tblpLoc)
tblArea = {} -- Country.State.County from PLAC record
tblOccur = {} -- Location instances
tblParm = {} -- Source to report
tblpLoc = {".ADDR", ".PLAC"} --
cw1 = 0
cw2 = 0
cw3 = 0
-- Prompt for Source
local tblParm = fhPromptUserForRecordSel('SOUR',1)
-- nothing chosen
if #tblParm == 0 then
fhMessageBox('Plugin Cancelled')
return
end
--if citation has no links
local iCitations = fhCallBuiltInFunction('LinksTo', tblParm[1])
if iCitations == 0 then
fhMessageBox('No Citations Found')
return
end
local parmSOUR = tblParm[1]
rtvSrcRcds('SOUR', parmSOUR)
bldOutput()
cw1 = (cw1 * 4) + 0
cw2 = (cw2 * 4) + 8
cw3 = (cw3 * 4) + 0
-- Output Tables built to Results Window
fhOutputResultSetColumn("Area", "text", tblArea, #tblArea, cw1, "align_left", 2)
fhOutputResultSetColumn("Location", "text", tblLocation, #tblLocation, cw2, "align_left", 3)
fhOutputResultSetColumn("Occurs", "integer", tblOccur, #tblOccur, cw3, "align_right", 1, false)
return
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
You really have to focus on what the code is doing.
e.g.
On line 113 you are saving the details back into the tblData instead of the tblLoc
i.e.
tblLoc[strLoc] = { Area = strArea; Occur = intOccur; }
Then in function bldOutput you have not echoed my code at all.
The max functions must use the same data as inserted into each Result Set table.
For cw3 the occurs integer must be converted to a string to get its length.
i.e.
for strLocation, tblData in pairs (tblLoc) do
table.insert(tblLocation,strLocation)
cw1 = math.max(cw1, #strLocation)
table.insert(tblArea,tblData["Area"])
cw2 = math.max(cw2, #tblData["Area"])
table.insert(tblOccur,tblData["Occur"])
cw3 = math.max(cw3, #tostring(tblData["Occur"]))
end
Finally, the fhOutputResultSetColumn functions associate cw1 and cw2 with the wrong columns!
e.g.
On line 113 you are saving the details back into the tblData instead of the tblLoc
i.e.
tblLoc[strLoc] = { Area = strArea; Occur = intOccur; }
Then in function bldOutput you have not echoed my code at all.
The max functions must use the same data as inserted into each Result Set table.
For cw3 the occurs integer must be converted to a string to get its length.
i.e.
for strLocation, tblData in pairs (tblLoc) do
table.insert(tblLocation,strLocation)
cw1 = math.max(cw1, #strLocation)
table.insert(tblArea,tblData["Area"])
cw2 = math.max(cw2, #tblData["Area"])
table.insert(tblOccur,tblData["Occur"])
cw3 = math.max(cw3, #tostring(tblData["Occur"]))
end
Finally, the fhOutputResultSetColumn functions associate cw1 and cw2 with the wrong columns!
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
got it fixed,thanks.
I dont know what the code is doing so it is impossible to focus.
believe me, there have been over 200 (at the very least) iterations of that code before I came here, closest I ever got was double location output with occurance.
so, I am still confused why a single table cannot be built, as:
tblLoc[strLoc] = {Location = strLoc; Area = strArea; Occur = intOccur;}
and cut the columns out of one record.
I dont know what the code is doing so it is impossible to focus.
believe me, there have been over 200 (at the very least) iterations of that code before I came here, closest I ever got was double location output with occurance.
so, I am still confused why a single table cannot be built, as:
tblLoc[strLoc] = {Location = strLoc; Area = strArea; Occur = intOccur;}
and cut the columns out of one record.
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
Well, until you do learn to understand what the code is doing, you will continue to struggle to get the code to work.
Just practice with small fragments to see how they work.
I assume you know to click in the left hand margin to set breakpoints where you can examine the values in lower right pane.
One slight snag is that global tables are not visible by default so make them local but outside all functions and at the top.
You can build a single table, but it is pointless, because the index [strLoc] is always the same as field Location = strLoc;
You cannot use the fields Location = strLoc; Area = strArea; Occur = intOccur; directly in the fhOutputResultSetColumn functions because they are not tables. i.e. fhOutputResultSetColumn("Area", "text", tblLoc["Area"], ... is invalid
Just practice with small fragments to see how they work.
I assume you know to click in the left hand margin to set breakpoints where you can examine the values in lower right pane.
One slight snag is that global tables are not visible by default so make them local but outside all functions and at the top.
You can build a single table, but it is pointless, because the index [strLoc] is always the same as field Location = strLoc;
You cannot use the fields Location = strLoc; Area = strArea; Occur = intOccur; directly in the fhOutputResultSetColumn functions because they are not tables. i.e. fhOutputResultSetColumn("Area", "text", tblLoc["Area"], ... is invalid
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
Maybe a summary of how tables work would be useful?
The following explanations will use these terms table[index] = value where:
table refers to a table structure
index refers to a key that identifies a table entry
value refers to whatever that indexed entry holds
t = { } declares an empty table with no indexed entries
t[1] = "alpha" sets the entry index key with the integer 1 to the value "alpha"
Let us consider basic integer array tables where every index is an integer starting at 1 and running consecutively.
e.g.
t[1] = "alpha"
t[2] = "bravo"
t[3] = "charlie"
The length of such a table is given by #t which in this example is 3 the largest consecutive index.
You can use table functions to modify such integer arrays.
table.insert( t, "delta" ) is the same as t[#t+1] = "delta" and thus t[4] now has value "delta"
To loop through all such integer array table entries in numerical order use the integer pairs ipairs function:
for index, value in ipairs (t) do
~ here the index & value will be successively 1 & "alpha", 2 & "bravo", 3 & "charlie" and 4 & "delta" in that order.
end
Now consider what I call dictionary tables where each index is typically a text string.
e.g.
t["Aa"] = "alpha"
t["Bb"] = "bravo"
t["Cc"] = "charlie"
Such tables do NOT have a length (or rather it is always 0) and the table functions are ineffective.
To loop through all such dictionary table entries in no specific order use the pairs function:
for index, value in pairs (t) do
~ here the index & value will be "Aa" & "alpha", "Bb" & "bravo", etc, but in no particular order.
end
If you use this pairs loop on the integer array table above, each index & value will be as for ipairs but in no particular order.
There is a shorthand way of constructing the tables shown above:
t = { "alpha"; "bravo"; "charlie"; } for an integer array table
t = { Aa="alpha"; Bb="bravo"; Cc="charlie"; } for a dictionary table
Any index can be all sorts of data type, such as numbers like 1.6 or 25.3, even in the same table.
Any value can be almost anything such as a number, a text string, or even a table.
e.g.
t[1] = "alpha"
t["Bb"] = "bravo"
t[1.6] = 25.3
t["C9"] = { One=1; Two=2; }
Use the pairs loop on this table and each index & value pair will be retrieved in a random order.
The following explanations will use these terms table[index] = value where:
table refers to a table structure
index refers to a key that identifies a table entry
value refers to whatever that indexed entry holds
t = { } declares an empty table with no indexed entries
t[1] = "alpha" sets the entry index key with the integer 1 to the value "alpha"
Let us consider basic integer array tables where every index is an integer starting at 1 and running consecutively.
e.g.
t[1] = "alpha"
t[2] = "bravo"
t[3] = "charlie"
The length of such a table is given by #t which in this example is 3 the largest consecutive index.
You can use table functions to modify such integer arrays.
table.insert( t, "delta" ) is the same as t[#t+1] = "delta" and thus t[4] now has value "delta"
To loop through all such integer array table entries in numerical order use the integer pairs ipairs function:
for index, value in ipairs (t) do
~ here the index & value will be successively 1 & "alpha", 2 & "bravo", 3 & "charlie" and 4 & "delta" in that order.
end
Now consider what I call dictionary tables where each index is typically a text string.
e.g.
t["Aa"] = "alpha"
t["Bb"] = "bravo"
t["Cc"] = "charlie"
Such tables do NOT have a length (or rather it is always 0) and the table functions are ineffective.
To loop through all such dictionary table entries in no specific order use the pairs function:
for index, value in pairs (t) do
~ here the index & value will be "Aa" & "alpha", "Bb" & "bravo", etc, but in no particular order.
end
If you use this pairs loop on the integer array table above, each index & value will be as for ipairs but in no particular order.
There is a shorthand way of constructing the tables shown above:
t = { "alpha"; "bravo"; "charlie"; } for an integer array table
t = { Aa="alpha"; Bb="bravo"; Cc="charlie"; } for a dictionary table
Any index can be all sorts of data type, such as numbers like 1.6 or 25.3, even in the same table.
Any value can be almost anything such as a number, a text string, or even a table.
e.g.
t[1] = "alpha"
t["Bb"] = "bravo"
t[1.6] = 25.3
t["C9"] = { One=1; Two=2; }
Use the pairs loop on this table and each index & value pair will be retrieved in a random order.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
Does it then follow that ipairs reads them in order of their index?
say I have a key banana which for the sake of the argument the nnth record from the lowest value in the file, how do I read the table starting at that record to the end?
and the explanations have helped immensely, thanks, the concepts I have, but the language skill is lacking. So had they been put in one record, the key would have been location still?
since I had to
for k,v in t do
anyhow, to get output tables I thought I could--
index = 0
location = ' b'
while location ~= "" do
index = index + 1
tblLocation[index] = tblData.Location
etc....
end
or does the .... render table functions ineffective... make ipairs (it means integer pairs, and not indexed pairs) and the read by text key goners?
say I have a key banana which for the sake of the argument the nnth record from the lowest value in the file, how do I read the table starting at that record to the end?
and the explanations have helped immensely, thanks, the concepts I have, but the language skill is lacking. So had they been put in one record, the key would have been location still?
since I had to
for k,v in t do
anyhow, to get output tables I thought I could--
index = 0
location = ' b'
while location ~= "" do
index = index + 1
tblLocation[index] = tblData.Location
etc....
end
or does the .... render table functions ineffective... make ipairs (it means integer pairs, and not indexed pairs) and the read by text key goners?
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
ipairs only reads consecutive INTEGER index keys starting from 1.
NON-INTEGER index keys such as banana can only be read by pairs and the order is undefined.
So it isn't possible to say that banana is the nnth entry, as NON-INTEGER keys have no defined order.
The only way to give such data an order is to have INTEGER entries that refer to NON-INTEGER entries.
e.g.
t = { }
t[1] = "apple"
t[2] = "pear"
t[3] = "banana"
t[4] = "cherry"
t["apple"] = 25
t["pear"] = 96
t["banana"] = 37
t["cherry"] = 84
for index, value in ipairs (t) do this only reads the index entries 1 thru 4
record = t[value]
end
So first time round loop index = 1, value = "apple" & record = 25
The last time round loop index = 4, value = "cherry" & record = 84
Thus to only read the entries from "banana" onwards you would need:
filter = 999
for index, value in ipairs (t) do
if value == "banana" then filter = index end
if index >= filter then record = t[value] end
end
Sorry I don't follow your code examples as they are not valid Lua and values are missing.
e.g. how does while locatation ~= "" do work when location does not appear within the loop?
Yes, ipairs means integer pairs.
NON-INTEGER index keys such as banana can only be read by pairs and the order is undefined.
So it isn't possible to say that banana is the nnth entry, as NON-INTEGER keys have no defined order.
The only way to give such data an order is to have INTEGER entries that refer to NON-INTEGER entries.
e.g.
t = { }
t[1] = "apple"
t[2] = "pear"
t[3] = "banana"
t[4] = "cherry"
t["apple"] = 25
t["pear"] = 96
t["banana"] = 37
t["cherry"] = 84
for index, value in ipairs (t) do this only reads the index entries 1 thru 4
record = t[value]
end
So first time round loop index = 1, value = "apple" & record = 25
The last time round loop index = 4, value = "cherry" & record = 84
Thus to only read the entries from "banana" onwards you would need:
filter = 999
for index, value in ipairs (t) do
if value == "banana" then filter = index end
if index >= filter then record = t[value] end
end
Sorry I don't follow your code examples as they are not valid Lua and values are missing.
e.g. how does while locatation ~= "" do work when location does not appear within the loop?
Yes, ipairs means integer pairs.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
i had meant read from banana onward indexed must the index integer be consecutive?
1 alpha
2 bravo
4 delta
6 foxtrot
?
because I thought perhaps I could order like this in place without using table.sort and its machinations:
(sort of hash the index) y=mx + b
where m would be the soundex count of each letter added, x would be 1.4 and b say; 20 for clash space slots, to move lesser or greater by n to an empty slot for equivalent soundex
tblSorted[y] = text that wants indexed keying ordered
it would allow read within limits, read previous or next record indexed, where you might have two Mike Tate(s) in the file.
and in my LUA code would be rife with errors, lol
1 alpha
2 bravo
4 delta
6 foxtrot
?
because I thought perhaps I could order like this in place without using table.sort and its machinations:
(sort of hash the index) y=mx + b
where m would be the soundex count of each letter added, x would be 1.4 and b say; 20 for clash space slots, to move lesser or greater by n to an empty slot for equivalent soundex
tblSorted[y] = text that wants indexed keying ordered
it would allow read within limits, read previous or next record indexed, where you might have two Mike Tate(s) in the file.
and in my LUA code would be rife with errors, lol
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
For ipairs the index must be consecutive and must start from 1.
Also the table functions, such as table.sort, have the same requirements.
The tactics I suggested work well for Address fields (they are NOT records).
They also work well for Place fields/records because the Place name MUST be unique.
For records, where the Title/Name may not be unique, then always utilise the Record Id as that MUST be unique.
Either use it on its own as the index key, or prefix it to the Title/Name to make the string a unique key.
Remember that Record Id may not be consecutive nor start from 1 so cannot rely on ipairs function.
Also the table functions, such as table.sort, have the same requirements.
The tactics I suggested work well for Address fields (they are NOT records).
They also work well for Place fields/records because the Place name MUST be unique.
For records, where the Title/Name may not be unique, then always utilise the Record Id as that MUST be unique.
Either use it on its own as the index key, or prefix it to the Title/Name to make the string a unique key.
Remember that Record Id may not be consecutive nor start from 1 so cannot rely on ipairs function.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Re: build a summary table
BTW I tried the move tbl* to before functions and make them local (still having trouble with what is seen where local) and uncovered an interesting error of name clash, easily solved. but tblLoc was always [.0] and could not be displayed. the rest...well, I been needing that for awhile, it should speed my understanding of tables now I can see inside them. So, the short of it is that tables cannot robustly mimic files and their operations (databases to most of you).
FH V.6.2.7 Win 10 64 bit
- tatewise
- Megastar
- Posts: 28347
- Joined: 25 May 2010 11:00
- Family Historian: V7
- Location: Torbay, Devon, UK
- Contact:
Re: build a summary table
Tables can usually mimic any data structures, but not necessarily with the built in ipairs and pairs iterators.
What I described earlier is just a summary of the basics of how tables can be used ~ there is much more.
BUT until you've grasped those basics and the other Lua language features I suggest it's best to work within those limitations.
What I described earlier is just a summary of the basics of how tables can be used ~ there is much more.
BUT until you've grasped those basics and the other Lua language features I suggest it's best to work within those limitations.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry