carey136 / Standalone-Export-Atlas-QGIS3

Standalone Script to Export Atlas to PDF/images
GNU General Public License v3.0
10 stars 0 forks source link

Script runs with success but nothing outputting #3

Open mtravis opened 6 years ago

mtravis commented 6 years ago

Here's the script I'm using.

Thanks, Matt

#### importing libraries ####
import sys
import os
from os.path import expanduser
from qgis.utils import *
from qgis.core import *
from PyQt5.QtCore import QFileInfo
from PyQt5.QtWidgets import QApplication
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-P',
    metavar=('\"Project file\"'), help='Usage: Override QGS project file')
parser.add_argument('-F',nargs=3,
    metavar=('\"Column\"','\"operator\"','\"value\"'),help='Usage: Override Atlas filter')
parser.add_argument('-C',
    metavar=('\"Coverage Layer Name\"'), help='Usage: Override atlas coverage layer')
parser.add_argument('-O',
    metavar=('\"Output Format\"'),help='Usage: Either "image" or "pdf" (default)')
parser.add_argument('-D',
    metavar=('\"Output Directory\"'), help='Usage: Override output directory (exclude trailing "\\"')
parser.add_argument('-N',
    metavar=('\"Output Name\"'),help='Usage: Override image output name using unique value query. e.g. \"@atlas_featurenid\"')
parser.add_argument('-Q',
    metavar=('\"Output pdf Name\"'), help='Usage: Override output name for PDFs (cannot parse column values as image filter can')
parser.parse_args()

####      Hardcode variables here      ####
#### Or use flags to override defaults ####

# -P = Project file
myProject = 'c:\\Users\\matt\\Documents\\gomaps\\Postcode Map\\postcode map.qgs'

# -L = Layout ("Layout name")
layoutName = 'atlas_name'

# -C = Coverage Layer Name ("Layer Name")
coverageLayer = 'postcodes_union'

# -F = filter ("column" "operator" "value")
atlasFilter = '"pc_area" = "PL"'

# -O = Output Format (pdf or image)
outputFormat = 'pdf'

# -D = Output Directory ("c:your\output" - exclude trailing "\")
outputFolder = 'c:temp\py\output'

# -N = Image output Query
outputName = '@atlas_featurenumber' #e.g.\"Parish\" || \' \' || \"Number\" where parish and number are columns

# -Q = PDF Name
pdfName = 'Export'

#### Setting variables using flags ####
if("-P" in sys.argv):
    myProject = sys.argv[sys.argv.index("-P") + 1]
if("-L" in sys.argv):
    layoutName = sys.argv[sys.argv.index("-L") + 1]
if("-C" in sys.argv):
    coverageLayer = sys.argv[sys.argv.index("-C") + 1]
if("-F" in sys.argv):
    atlasFilter = "\"" + sys.argv[sys.argv.index("-F") + 1] + "\" " + sys.argv[sys.argv.index("-F") + 2] + " \'" + sys.argv[sys.argv.index("-F") + 3] + "\'"
if("-O" in sys.argv):
    outputFormat = sys.argv[sys.argv.index("-O") + 1]
if("-D" in sys.argv):
    outputFolder = sys.argv[sys.argv.index("-D") + 1]
if("-N" in sys.argv):
    outputName = sys.argv[sys.argv.index("-N") + 1]
if("-Q" in sys.argv):
    pdfName = sys.argv[sys.argv.index("-Q") + 1]

#### Initialising QGIS in back end (utilising users temp folder) ####
home = expanduser("~")
QgsApplication( [], False, home + "/AppData/Local/Temp" )
QgsApplication.setPrefixPath("C:/OSGeo4W64/apps/qgis", True) #Change path for standalone QGIS install
app = QApplication([])
QgsApplication.initQgis()

#### Defining map path and contents ####
QgsProject.instance().read(myProject)
myLayout = QgsProject.instance().layoutManager().layoutByName(layoutName)
myAtlas = myLayout.atlas()
myAtlasMap = myAtlas.layout()

#### atlas query ####
if(coverageLayer in locals()):
    myAtlas.setCoverageLayer(QgsProject.instance().mapLayersByName(coverageLayer))
myAtlas.setFilterFeatures(True) 
myAtlas.setFilterExpression(atlasFilter)

#### image output name ####
myAtlas.setFilenameExpression( outputName )

#### image and pdf settings ####
pdf_settings=QgsLayoutExporter(myAtlasMap).PdfExportSettings()
image_settings = QgsLayoutExporter(myAtlasMap).ImageExportSettings()
image_settings.dpi = 200
imageExtension = '.jpg'
#### Export images or PDF (depending on flag) ####
if outputFormat == "image":
    for myLayout in QgsProject.instance().layoutManager().printLayouts():
        if myAtlas.enabled():
            result, error = QgsLayoutExporter.exportToImage(myAtlas, 
                                baseFilePath=outputFolder + '\\', extension=imageExtension, settings=image_settings)
            if not result == QgsLayoutExporter.Success:
                print(error)
if outputFormat == "pdf":
    for myLayout in QgsProject.instance().layoutManager().printLayouts():
        if myAtlas.enabled():
            result, error = QgsLayoutExporter.exportToPdf(myAtlas, outputFolder + '\\' + pdfName + '.pdf', settings=pdf_settings)
            if not result == QgsLayoutExporter.Success:
                print(error)
print("Success!")
carey136 commented 6 years ago

Hi Matt,

If the script has reached 'Success!' (I'll probably change the text printed at the end for various reasons), then it has at least ran through the script without declaring any immediate errors.

Most likely issue

The most common issue I've had when no maps are exported is due to the filter and output names syntax.

I can see that I've incorrectly quoted the syntax for atlasFilter at line 40. . Atlas filter should print in the following format: "Column" = 'Value'

However, for columns and values, the " or ' need escaping using a backslash . When using the argument -F, the 3 arguments following it are concatenated into the above syntax automatically to save trouble! You can either try using the -F flag first, or hard code it as below:

The syntax for the hardcoded value (including a demo of the output) would be :

>>> atlasFilter = '\"Column\" = \'Value\''
>>> print(atlasFilter)
"Column" = 'Value'
>>>

Using your filter values, this makes atlasFilter = '\"pc_area\" = \'PL\''

A similar approach is required for outputName. As this is set to \@atlas_featurenumber it shouldn't be a problem. For both of these though, the best advice is the following:

  1. Set up the output name and filter query in qgis with the correct syntax
  2. Copy the syntax and escape all required " and '
  3. Run Python (use C:\OSGeo4W64\bin\python-qgis.bat if needed) and copy my method above, defining atlasFilter, then printing the result to see if the syntax is right.
  4. Add the corrected syntax to the code and run again to see if it works

If it's something else:

If you still get no results when the syntax is corrected, run the code piece by piece in python to see where it trips up. Avoid any sections with if() relating to flags / overrides and see where the issue lies. If it's with the core code, then I can change that.

Keep me posted!

* As a note, when adding code to an issue / comment, you can use syntax highlighting and display it as a code block as follows: ```python \<your code here> ```

mtravis commented 6 years ago

Hi Rob

Thanks for the tips. Made the changes and now getting this error:

C:\Users\matt>C:\OSGeo4W64\bin\python-qgis.bat C:\\temp\\py\\AtlasExport.py
Cannot write to c:temp/py/PL.png. This file may be open in another application.
Cannot write to c:temp/py/PL.png. This file may be open in another application.
Success!

Odd it repeats that line. There is no PL currently in that folder either so not sure why it thinks there is.

carey136 commented 6 years ago

It appears then that it doesn't like the format of the output path. c:temp/py/ is not a valid path, so it may be trying to write to a location that does not exist. It would still be a strange error message if this was the case though.

Instead of outputFolder = 'c:temp\py' Use outputFolder = 'c:\temp\py'

and see how you get on.

mtravis commented 6 years ago

I used outputFolder = 'c:\\temp\\py' in the end to get it to work.

Wonder why it's different for you? Anyway it's a great tool and I can see myself using it a lot.

carey136 commented 6 years ago

Glad you have found some use in it. It's been a fun learning curve getting it set up and 'working'. I don't think it would take too much to modify it to work with qgis 2.18.* if anyone wanted to adapt the code, but I though moving forward it would be best to use this version.

If you're happy with the formatting now, I'll close the issue.