1
votes

Note: I have a workaround, so this is only an attempt to understand the error.

Summary: I get a syntax error (failed to write table) when using putpdf. The error seems to be connected to using the bold option, but disappears when this option is replaced or erased.

I am trying to write a pdf with a series of tables using putpdf. This is a new built-in command (Stata 15 only), so I can't tell if what I am experiencing is a bug or a problem with the way I have formatted things. Unfortunately, this issue is impossible to replicate without the data I am using: The same general idea using sysuse auto couldn't replicate, so this is a weird one.

Start by adding in the data (this is from an ongoing survey I am checking daily, so I have trimmed it down to the parts that are replicating an error and replaced names with dummy names):

    clear
    cd [DIRECTORY] // Change this to yours
    input str70 label str6 district str11 ta str23 village str27 cluster float(sdate coupons) byte shopid str33 reason
    "Amosi - 1000001 - First Last (MARK-01-001)"       "Mwan" "Kand" "Amosi"       "First Last 22" 21266 . 13 "Not Yet Replaced"
    "Amosi - 1000002 - First Last (MARK-01-001)"       "Mwan" "Kand" "Amosi"       "First Last 22" 21266 . 13 "Not Yet Replaced"
    "Bello - 1000003 - First Last (MARK-01-001)"       "Neno" "Damb" "Bello"       "First Last 2"  21266 1 11 "Not Yet Replaced"
    "Bello - 1000004 - First Last (MARK-01-001)"       "Neno" "Chek" "Bello"       "First Last 5"  21266 . 11 "Not Yet Replaced"
    "Bello - 1000005 - First Last (MARK-01-001)"       "Neno" "Damb" "Bello"       "First Last 24" 21266 . 11 "Not Yet Replaced"
    "Benalita - 1000006 - First Last (MARK-01-001)"    "Neno" "Damb" "Benalita"    "First Last 7"  21260 1 12 "Not Yet Replaced"
    "Chakhumbira - 1000007 - First Last (MARK-01-001)" "Neno" "Damb" "Chakhumbira" "First Last 28" 21269 .  8 "Not Yet Replaced"
    "Chapita - 1000008 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chapita"     "First Last 32"     . 1  1 ""                
    "Chapita - 1000009 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chapita"     "First Last 3"      . .  1 ""                
    "Chapita - 1000010 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chapita"     "First Last 20" 21266 .  1 "Not Yet Replaced"
    "Chapita - 1000011 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chapita"     "First Last 9"      . 1  1 ""                
    "Chapita - 1000012 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chapita"     "First Last 31" 21262 .  1 "Not Yet Replaced"
    "Chasesa - 1000013 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 16"     . . 20 ""                
    "Chasesa - 1000014 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 30" 21263 1  3 "Not Yet Replaced"
    "Chasesa - 1000015 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 16"     . . 20 ""                
    "Chasesa - 1000016 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 25"     . 1 20 ""                
    "Chasesa - 1000017 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 21"     . . 20 ""                
    "Chasesa - 1000018 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 14"     . . 20 ""                
    "Chasesa - 1000019 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 29" 21266 . 20 "Not Yet Replaced"
    "Chasesa - 1000020 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 30"     . .  3 ""                
    "Chasesa - 1000021 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 14"     . . 20 ""                
    "Chasesa - 1000022 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 12"     . 1 20 ""                
    "Chasesa - 1000023 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 26" 21251 .  1 "Not Yet Replaced"
    "Chasesa - 1000024 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 21" 21249 . 20 "Not Yet Replaced"
    "Chasesa - 1000025 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 27" 21250 . 20 "Not Yet Replaced"
    "Chasesa - 1000026 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 11" 21249 . 20 "Not Yet Replaced"
    "Chasesa - 1000027 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 26"     . .  1 ""                
    "Chasesa - 1000028 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 4"      . 1 20 ""                
    "Chasesa - 1000029 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 19" 21262 . 20 "Not Yet Replaced"
    "Chasesa - 1000030 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 18" 21250 1 20 "Not Yet Replaced"
    "Chasesa - 1000031 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 26" 21251 1  1 "Not Yet Replaced"
    "Chasesa - 1000032 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 25" 21249 1 20 "Not Yet Replaced"
    "Chasesa - 1000033 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 13"     . 1 20 ""                
    "Chasesa - 1000034 - First Last (MARK-01-001)"     "Neno" "Mlau" "Chasesa"     "First Last 17"     . 1 20 ""                
    "Chidakwani - 1000035 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 23"     . .  2 ""                
    "Chidakwani - 1000036 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 23"     . .  2 ""                
    "Chidakwani - 1000037 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 10"     . .  2 ""                
    "Chidakwani - 1000038 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 23"     . .  2 ""                
    "Chidakwani - 1000039 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 15"     . .  2 ""                
    "Chidakwani - 1000040 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 15"     . 1  2 ""                
    "Chidakwani - 1000041 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 15"     . 1  2 ""                
    "Chidakwani - 1000042 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 1"      . 1  2 ""                
    "Chidakwani - 1000043 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 8"  21252 .  2 "Not Yet Replaced"
    "Chidakwani - 1000044 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 10"     . 1  2 ""                
    "Chidakwani - 1000045 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 23"     . .  2 ""                
    "Chidakwani - 1000046 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 1"  21251 .  2 "Not Yet Replaced"
    "Chidakwani - 1000047 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 6"      . 1  2 ""                
    "Chidakwani - 1000048 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 15"     . .  2 ""                
    "Chidakwani - 1000049 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 10"     . 1  2 ""                
    "Chidakwani - 1000050 - First Last (MARK-01-001)"  "Neno" "Chek" "Chidakwani"  "First Last 10"     . .  2 ""                
    end
    format %td sdate

Now open a document, and create tables within it. Here is the workflow:

  • Use levelsof to create a local macro containing unique village names to loop through (I want a separate table within the same PDF for each village)
  • Begin the PDF document
  • Start the loop on villages
  • Add a title before the table
  • Create a table based on the village name: Rather than just using the data(varlist) way of making a table, I am dropping all observations that do not fall under this village, then looping through each observation and writing a row on the table for each. This gives me control over the column span (the 'label' variable is a long string, while some are byte numbers, so I want different column widths and this seems like the only way putpdf can do what I want it to).
  • Add a new row to the top of the table as a header, then write the individual column cells one at a time
  • Save the pdf

Here is the code:

* Get unique values of village in local vstr
    levelsof village, local(vstr)

* Open the document and start the loop
set trace on    // Helps to see where the code screws up
    putpdf begin, page(A4) landscape margin(top, 0.25in) margin(right, 0.25in) margin(bottom,0.25in) margin(left,0.25in)
    foreach village of local vstr {     
        preserve    
            local name = subinstr("`village'"," ","_",.)    // These aren't impacted here, but in teh rst of my data I have spaces and apostrophes which need to go
            local name = subinstr("`name'","'","_",.)

            * Add a title before each table
            putpdf paragraph, font("Calibri Light",14) halign(center)
                putpdf text ("`village'")

            * Keep only obs in this village (note 'preserve' above)
            qui keep if village == "`village'"

            * Get the number of observations so we can loop through row-by-row
            qui count

            * Start a table with N rows based on the above count
            putpdf table hhs_`name' = (`r(N)',17)

            * Loop through all N rows and write cell contents
            forvalues i=1/`r(N)' {
                putpdf table hhs_`name'(`i',1) = (substr(label[`i'],1,50)), colspan(6)  // Longer string, hence colspan(6)
                putpdf table hhs_`name'(`i',7) = (district[`i'])
                putpdf table hhs_`name'(`i',8) = (ta[`i'])
                putpdf table hhs_`name'(`i',9) = (substr(village[`i'],1,4))
                putpdf table hhs_`name'(`i',10) = (cluster[`i']), colspan(3)
                putpdf table hhs_`name'(`i',13) = (shopid[`i'])
                putpdf table hhs_`name'(`i',14) = (coupons[`i'])
                putpdf table hhs_`name'(`i',15) = (reason[`i']), colspan(2)
                putpdf table hhs_`name'(`i',17) = (string(sdate[`i'],"%td_dm"))
            }

            * Write header row at the top of teh table
            putpdf table hhs_`name'(1,.), addrows(1, before)
                * The line below is where the error seems to be triggered:
                putpdf table hhs_`name'(1,1) = ("Label"), colspan(6) bold bgcolor(lightgray)
                *putpdf table hhs_`name'(1,7) = ("District"), bold bgcolor(lightgray)
                *putpdf table hhs_`name'(1,8) = ("TA"), bold bgcolor(lightgray)
                *putpdf table hhs_`name'(1,9) = ("Village"), bold bgcolor(lightgray)
                *putpdf table hhs_`name'(1,10) = ("Cluster"), colspan(3) bold bgcolor(lightgray)
                *putpdf table hhs_`name'(1,13) = ("Shop ID"), bold bgcolor(lightgray)
                *putpdf table hhs_`name'(1,14) = ("Coupon"), bold bgcolor(lightgray)
                *putpdf table hhs_`name'(1,15) = ("Reason"), colspan(2) bold bgcolor(lightgray)
                *putpdf table hhs_`name'(1,17) = ("Date"), bold bgcolor(lightgray)

        restore
    }

    * Save the document
    putpdf save "Village Remaining Lists.pdf", replace
    set trace off

I commented out all rows within the loop and then un-commented them one-by-one starting at the top (putpdf table hhs_name(i,1) = (substr(label...). Originally, the file had no trouble writing a PDF. The error ("failed to add table; r(198)") is a syntax error.

Now, if you take that line and change the option bold to italic (or nothing at all), the error disappears.

putpdf table hhs_`name'(1,1) = ("Label"), colspan(6) italic bgcolor(lightgray)

Using set trace on doesn't immediately reveal where the problem actually occurs, but when you scroll up in the resulting output (when the option is set to bold), you can see that the loop is starting again with the village "Chidakwani" before the error pops up. And the error seems to occur before the table for Chidakwani begins. So I think that the problem is happening somewhere around "Chasesa" village, and either that table is not stopping, or the Chidakwani table cannot start. And all because of the "bold" option.

The italic workaround is sufficient for now, but I thought I would throw this out there and see if anyone wants to take a stab at figuring out what is going on.

1

1 Answers

1
votes

I had a similar issue and found that this error is also linked to the lenght of the labelname of the previous lines and also somehow to the putpdf paragraph statement.

This code results in the "Failed to add table" - error:

putpdf paragraph
putpdf text ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), linebreak font("Arial",10) bold
putpdf paragraph
putpdf text ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), linebreak font("Arial",12) bold

putpdf table tabq25 = (4,7)

while this code works fine

putpdf paragraph
putpdf text ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), linebreak font("Arial",10) bold
putpdf paragraph
putpdf text ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), linebreak font("Arial",12) bold


putpdf table tabq25 = (4,7)

By deleting or replacing the bold-statement, the Code runs as usual.

Deleting the second putpdf paragraph statement also works:

putpdf paragraph
putpdf text ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), linebreak font("Arial",10) bold
putpdf text ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), linebreak font("Arial",12) bold


putpdf table tabq25 = (4,7)

The error might not be related to the character lenght only, as this works fine:

putpdf paragraph
putpdf text ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), linebreak font("Arial",10) bold


putpdf table tabq25 = (4,7)