0

In QGIS v3.8.3 I have one shapefile of all US Census Tracts and another of ~1,000 US Counties. There are multiple tracts in a county. So I did a many-to-one join in Join attributes by location to add a 'county' column to the Tracts file.

I'd like to export shapefiles for each county-based group of tracts. For example, one shapefile for the ten tracts in County 1, another shapefile for the twelve tracts in County 2...all the way to County 1,000. I'd prefer not to click Export > Save selected features as a thousand times.

Here's what I've tried and looked at so far, but I didn't think that any of them were specifically focused on batch exporting based on the value of a specific column (but I may be wrong, I'm not super Python-literate):

  • Batch save layers plugin
  • Exporting several files at same time in QGIS?
  • QGIS batch conversion
  • Automate SHP to JPG creation
    • I need to ask: is there a specific reason for file system based storage (or using shapefiles for that matter)? It is a lot more convenient to work with data structured by attributes as with your column; there are modern relational data model formats out there (e.g. GeoPackage), and the grouping, filtering, processing, extraction and analysis of a single relational data set is largely focussed on in most GIS. – geozelot Jan 7 at 21:15
    • I completely agree, this is incredibly inconvenient. Unfortunately, I am at the mercy of other in-house software at my company that requires I provide it with individual shapefiles (must be .shp format) in this exact way. – ellory Jan 7 at 21:35
    1

    The tool Split Vector Layer lets you batch export a layer based on the value in a column.

    This tool outputs in whatever format you have chosen for Processing output file type, which by default is geopackage. To change this setting, go to the Processing options tab in the Settings menu. Change the "default output vector layer extension" to "shp". (For more details on this workaround see this answer.)

    |improve this answer|||||
    1

    You could achieve this with a short Python script which chains together a couple of processing algorithms- Select by location and Save selected features. If we put these into a for loop, iterating over each feature in your County layer, selecting it and running Select by location (on selected features only) to select all census tracts which intersect the selected county feature and saving these as a new shapefile.

    Firstly, create a folder in your local directory in which the output files will be saved.

    Paste the following code into a new editor in the Python console (see image below).

    enter image description here

    Change the file path and layer names to match yours, and click run.

    Disclaimer: I am not sure how long this will take to run on 1000 features.

    import os
    
    # change path to point to the folder you created earlier
    path = 'C:/Users/Username/Desktop/Counties'
    
    # change name strings below to match your layers
    county_layer = QgsProject().instance().mapLayersByName('US_Counties')[0]
    census_layer = QgsProject().instance().mapLayersByName('US_Census_Tracts')[0]
    for f in county_layer.getFeatures():
        county_layer.selectByIds([f.id()])
        processing.run('native:selectbylocation', {'INPUT': census_layer,'PREDICATE':[0],
        'INTERSECT':QgsProcessingFeatureSourceDefinition(county_layer.id(), True),'METHOD':0})
        processing.run('native:saveselectedfeatures', {'INPUT': census_layer,
        'OUTPUT': os.path.join(path, 'County_{}.shp'.format(str(f.id()+1)))})
        # alternatively, you could use:
        # 'OUTPUT': os.path.join(path, '{}.shp'.format(f['Name']))
        # where 'Name' is the field in your county layer which contains the county name
    county_layer.selectByIds([])
    census_layer.selectByIds([])
    
    |improve this answer|||||
    • The only reason I couldn't fully accept this as an answer was because I do not know enough Python to get it to work on my computer (I copied and pasted it into the console and followed all the instructions, but am getting errors too complex for me to troubleshoot). But I'm glad you thought through a Python solution... I'm sure it will come in handy for others who are more Python-literate and have the same question as me. Thank you. – ellory Jan 8 at 18:44
    • No problem @ellory, csk's answer is the better solution! – Ben W Jan 8 at 23:41

    Your Answer

    By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

    Not the answer you're looking for? Browse other questions tagged or ask your own question.