Skip to main content
added 4 characters in body
Source Link
Kadir Şahbaz
  • 78k
  • 57
  • 257
  • 404

This section of code creates a "preprocessing" directory for storing the CSV files modified with Python's built-in csv()csv() method:

The "encoding=utf-8"encoding="utf-8" might no be necessary here, but I left it in.

This section of code creates a "preprocessing" directory for storing the CSV files modified with Python's built-in csv() method:

The "encoding=utf-8" might no be necessary here, but I left it in.

This section of code creates a "preprocessing" directory for storing the CSV files modified with Python's built-in csv() method:

The encoding="utf-8" might no be necessary here, but I left it in.

added 10834 characters in body
Source Link

However, allHowever, all of the other issues still exist.

The rest of the other issues still existwere resolved by updating variable names consistently throughout the script and changing some methodology used in handling the CSV layers. This is the finished script:

from qgis.core import QgsProject, QgsVectorLayer, QgsLayerTreeGroup, QgsLayerTreeLayer, QgsLayoutNodesItem, QgsMapThemeCollection
from PyQt5 import QtGui
import csv
import os

#creates the project directory and reformats for compatibility with all methods used in script
projectDirRawUri = r"E:\Jason\Documents\2020-01\mapping project\gis\test_automate_all"
projectDirUri = projectDirRawUri.replace("\\", "/")
projDirErrorMsg = "{} directory already exists."
#creates the layer directory
layerDirName = "layers"
layerDirUri = projectDirUri + "/" + layerDirName
if not os.path.isdir(layerDirUri):
    os.mkdir(layerDirUri)
else:
    print(projDirErrorMsg.format(layerDirName))
#creates the data layer directory
dataLayerDirName = "datasets"
dataLayerDirUri = layerDirUri + "/" + dataLayerDirName
if not os.path.isdir(dataLayerDirUri):
    os.mkdir(dataLayerDirUri)
else:
    print(projDirErrorMsg.format(dataLayerDirName))
#creates the data preprocessing directory
dataPreprocDirName = "preprocessing"
dataPreprocDirUri = dataLayerDirUri + "/" + dataPreprocDirName
if not os.path.isdir(dataPreprocDirUri):
    os.mkdir(dataPreprocDirUri)
else:
    print(projDirErrorMsg.format(dataPreprocDirName))

#deselects all nodes in the "layers panel"/"map legend"
QgsLayoutNodesItem.deselectNode

#creates the root variable
root = QgsProject.instance().layerTreeRoot()

#creates the group for storing the CSV layers
dataGroup = QgsLayerTreeGroup("data_layers")
root.addChildNode(dataGroup)

## reading prj file 
# wktRawUri = r"E:\Jason\Documents\2020-01\mapping project\gis\test_automate_all\sources\Public Use Microdata Areas (PUMA)\geo_export_0ca223b7-207e-4bc2-bf55-9947aa4998c5.prj"
# wktUri = wktRawUri.replace("\\", "/")
#with open(wktUri, 'r') as wkt: 
#    # creating a wkt reader object 
#    wktInfo = wkt.read() 
#    # extracting field names through first row 
#    crs = QgsCoordinateReferenceSystem(wkt)
#    assert crs.isValid()
#print(crs)

#populates the CSV source URI and layer name lists
csvSrcRawUri = r"E:\Jason\Documents\2020-01\mapping project\gis\test_automate_all\sources\datasetsrekeithsstudy"
csvSrcUri = csvSrcRawUri.replace("\\", "/")
csvSrcUriList = []
csvSrcUriIndex = 0
csvLayerNameList = []
for root, dirs, files in os.walk(csvSrcUri):
    for file in files:
        if(file.endswith(".csv")):
            csvSrcUriList.append(os.path.join(root,file))
            csvLayerNameList.append(os.path.join(file))

#sorts the CSV source URI and layer name lists alphabetically to match eachother
csvSrcUriList.sort()
csvLayerNameList.sort()

#populates the CSV preprocessing URI list
csvPreprocDirUri = dataPreprocDirUri
csvPreprocUriList = []
csvPreprocUriIndex0 = 0
while csvPreprocUriIndex0 < len(csvSrcUriList):
    csvPreprocUri = csvPreprocDirUri + "/" + csvLayerNameList[csvPreprocUriIndex0]
    csvPreprocUriList.append(csvPreprocUri)
    csvPreprocUriIndex0 += 1

#reformat fields as percentages
csvPreprocUriIndex1 = 0
for csvFile in csvSrcUriList:
    rowList = []
    fldList = []
    with open(csvFile, 'r', encoding="utf-8", newline='') as csvSrcFile, open(csvPreprocUriList[csvPreprocUriIndex1], 'w', encoding="utf-8", newline='') as csvTrgtFile:
        csvreader = csv.reader(csvSrcFile)
        csvwriter = csv.writer(csvTrgtFile)
        fldList = next(csvreader)
        csvwriter.writerow(fldList)
        for row in csvreader:
            rowList.append(row)
        for row in rowList:
            rowIdx = 1
            while rowIdx < len(row):
                percentValue = format(float(row[rowIdx])*100, ".9g")
#                percentValue = str(float(row[rowIdx])*100)
                row[rowIdx] = percentValue
                rowIdx += 1
        csvwriter.writerows(rowList)
    csvPreprocUriIndex1 += 1

#copies the CSV preprocessing URI list and reformats the items in it so they can be used by the QgsVectorLayer() method
csvVectorLayerUriList = csvPreprocUriList.copy()
csvVectorLayerUriIndex = 0
for file in csvVectorLayerUriList:
    filePrefix = 'file:///'
    fileSuffix = '?delimeter=,'
    fileLocation = filePrefix + file + fileSuffix
    csvVectorLayerUriList[csvVectorLayerUriIndex] = fileLocation
    csvVectorLayerUriIndex += 1

#populates the CSV layer URI list
csvLayerDirUri = dataLayerDirUri
csvLayerUriList = []
csvLayerUriIndex = 0
while csvLayerUriIndex < len(csvSrcUriList):
    csvLayerUri = csvLayerDirUri + "/" + csvLayerNameList[csvLayerUriIndex]
    csvLayerUriList.append(csvLayerUri)
    csvLayerUriIndex += 1

#removes the .csv extention from the items in the CSV layer name list
csvLayerNameIndex = 0
for file in csvLayerNameList:
    layerName =  file.replace(".csv", "")
    csvLayerNameList[csvLayerNameIndex] = layerName
    csvLayerNameIndex += 1

#loop to create and perform all operations on all CSV layers including grouping
csvSavedLayerList = []
csvLayerIndex = 0
for csvLayerName in csvLayerNameList:
    csvLayerUri = csvVectorLayerUriList[csvLayerIndex]
    #creates the CSV layer name from the list of csv names and fields
    csvLayerName = csvLayerNameList[csvLayerIndex]
    #adds the initial CSV layer to the project and checks the layer validity
    csvLayer = QgsVectorLayer(csvLayerUri, csvLayerName, 'delimitedtext')
    QgsProject.instance().addMapLayer(csvLayer)
    if not csvLayer or not csvLayer.isValid():
        csvAddLayerErrorMsg = csvLayerName + " failed to load!"
        print(csvAddLayerErrorMsg)
    #copies the shape layer and places the copy in the correct group
    root = QgsProject.instance().layerTreeRoot()
    csvGroup = root.findGroup(dataGroup.name())
    csvOriginalLayer = root.findLayer(csvLayer.id())
    csvGroupedLayer = csvOriginalLayer.clone()
    csvGroupedLayer = csvOriginalLayer.clone()
    csvGroup.insertChildNode(-1, csvGroupedLayer)
    csvSaveOptions = QgsVectorFileWriter.SaveVectorOptions()
    csvSaveOptions.driverName = "CSV"
    csvSaveOptions.fileEncoding = "UTF-8"
    csvSavedLayer = csvGroupedLayer.layer()
    QgsVectorFileWriter.writeAsVectorFormatV2(csvSavedLayer, csvLayerUriList[csvLayerIndex], QgsCoordinateTransformContext(), csvSaveOptions)
    if not csvGroupedLayer.layer() or not csvGroupedLayer.layer().isValid():
        csvSaveLayerErrorMsg = csvLayerName + " failed to save!"
        print(csvAddLayerErrorMsg)
    #removes the ungrouped shape layer
    parent = csvOriginalLayer.parent()
    parent.removeChildNode(root.findLayer(csvLayer.id()))
    #populates in the CSV saved layer list for use in table joins
    csvSavedLayerList.append(csvSavedLayer)
    
    csvLayerIndex +=1

This section of code creates a "preprocessing" directory for storing the CSV files modified with Python's built-in csv() method:

#creates the data preprocessing directory
dataPreprocDirName = "preprocessing"
dataPreprocDirUri = dataLayerDirUri + "/" + dataPreprocDirName
if not os.path.isdir(dataPreprocDirUri):
    os.mkdir(dataPreprocDirUri)
else:
    print(projDirErrorMsg.format(dataPreprocDirName))

This section does the preprocessing(multiplying the CSV values by 100) and saving the modified CSV values in a new CSV file:

#populates the CSV source URI and layer name lists
csvSrcRawUri = r"E:\Jason\Documents\2020-01\mapping project\gis\test_automate_all\sources\datasetsrekeithsstudy"
csvSrcUri = csvSrcRawUri.replace("\\", "/")
csvSrcUriList = []
csvSrcUriIndex = 0
csvLayerNameList = []
for root, dirs, files in os.walk(csvSrcUri):
    for file in files:
        if(file.endswith(".csv")):
            csvSrcUriList.append(os.path.join(root,file))
            csvLayerNameList.append(os.path.join(file))

#sorts the CSV source URI and layer name lists alphabetically to match eachother
csvSrcUriList.sort()
csvLayerNameList.sort()

#populates the CSV preprocessing URI list
csvPreprocDirUri = dataPreprocDirUri
csvPreprocUriList = []
csvPreprocUriIndex0 = 0
while csvPreprocUriIndex0 < len(csvSrcUriList):
    csvPreprocUri = csvPreprocDirUri + "/" + csvLayerNameList[csvPreprocUriIndex0]
    csvPreprocUriList.append(csvPreprocUri)
    csvPreprocUriIndex0 += 1

#reformat fields as percentages
csvPreprocUriIndex1 = 0
for csvFile in csvSrcUriList:
    rowList = []
    fldList = []
    with open(csvFile, 'r', encoding="utf-8", newline='') as csvSrcFile, open(csvPreprocUriList[csvPreprocUriIndex1], 'w', encoding="utf-8", newline='') as csvTrgtFile:
        csvreader = csv.reader(csvSrcFile)
        csvwriter = csv.writer(csvTrgtFile)
        fldList = next(csvreader)
        csvwriter.writerow(fldList)
        for row in csvreader:
            rowList.append(row)
        for row in rowList:
            rowIdx = 1
            while rowIdx < len(row):
                percentValue = format(float(row[rowIdx])*100, ".9g")
#                percentValue = str(float(row[rowIdx])*100)
                row[rowIdx] = percentValue
                rowIdx += 1
        csvwriter.writerows(rowList)
    csvPreprocUriIndex1 += 1

The "encoding=utf-8" might no be necessary here, but I left it in.

Finally, several lines were added to the section that groups and saves the layer to clean up the duplicate layers that were appearing in the Layers Panel:

    #copies the shape layer and places the copy in the correct group
    root = QgsProject.instance().layerTreeRoot()
    csvGroup = root.findGroup(dataGroup.name())
    csvOriginalLayer = root.findLayer(csvLayer.id())
    csvGroupedLayer = csvOriginalLayer.clone()
    csvGroupedLayer = csvOriginalLayer.clone()
    csvGroup.insertChildNode(-1, csvGroupedLayer)
    csvSaveOptions = QgsVectorFileWriter.SaveVectorOptions()
    csvSaveOptions.driverName = "CSV"
    csvSaveOptions.fileEncoding = "UTF-8"
    csvSavedLayer = csvGroupedLayer.layer()
    QgsVectorFileWriter.writeAsVectorFormatV2(csvSavedLayer, csvLayerUriList[csvLayerIndex], QgsCoordinateTransformContext(), csvSaveOptions)
    if not csvGroupedLayer.layer() or not csvGroupedLayer.layer().isValid():
        csvSaveLayerErrorMsg = csvLayerName + " failed to save!"
        print(csvAddLayerErrorMsg)
    #removes the ungrouped shape layer
    parent = csvOriginalLayer.parent()
    parent.removeChildNode(root.findLayer(csvLayer.id()))

I was trying to cheat and skip the routine where the layer is duplicated, saved, and the original removed from the project, but that seems to break it. If anyone knows how to do this, please reply to this thread.

However, all of the other issues still exist.

However, all of the other issues still exist.

The rest of the issues were resolved by updating variable names consistently throughout the script and changing some methodology used in handling the CSV layers. This is the finished script:

from qgis.core import QgsProject, QgsVectorLayer, QgsLayerTreeGroup, QgsLayerTreeLayer, QgsLayoutNodesItem, QgsMapThemeCollection
from PyQt5 import QtGui
import csv
import os

#creates the project directory and reformats for compatibility with all methods used in script
projectDirRawUri = r"E:\Jason\Documents\2020-01\mapping project\gis\test_automate_all"
projectDirUri = projectDirRawUri.replace("\\", "/")
projDirErrorMsg = "{} directory already exists."
#creates the layer directory
layerDirName = "layers"
layerDirUri = projectDirUri + "/" + layerDirName
if not os.path.isdir(layerDirUri):
    os.mkdir(layerDirUri)
else:
    print(projDirErrorMsg.format(layerDirName))
#creates the data layer directory
dataLayerDirName = "datasets"
dataLayerDirUri = layerDirUri + "/" + dataLayerDirName
if not os.path.isdir(dataLayerDirUri):
    os.mkdir(dataLayerDirUri)
else:
    print(projDirErrorMsg.format(dataLayerDirName))
#creates the data preprocessing directory
dataPreprocDirName = "preprocessing"
dataPreprocDirUri = dataLayerDirUri + "/" + dataPreprocDirName
if not os.path.isdir(dataPreprocDirUri):
    os.mkdir(dataPreprocDirUri)
else:
    print(projDirErrorMsg.format(dataPreprocDirName))

#deselects all nodes in the "layers panel"/"map legend"
QgsLayoutNodesItem.deselectNode

#creates the root variable
root = QgsProject.instance().layerTreeRoot()

#creates the group for storing the CSV layers
dataGroup = QgsLayerTreeGroup("data_layers")
root.addChildNode(dataGroup)

## reading prj file 
# wktRawUri = r"E:\Jason\Documents\2020-01\mapping project\gis\test_automate_all\sources\Public Use Microdata Areas (PUMA)\geo_export_0ca223b7-207e-4bc2-bf55-9947aa4998c5.prj"
# wktUri = wktRawUri.replace("\\", "/")
#with open(wktUri, 'r') as wkt: 
#    # creating a wkt reader object 
#    wktInfo = wkt.read() 
#    # extracting field names through first row 
#    crs = QgsCoordinateReferenceSystem(wkt)
#    assert crs.isValid()
#print(crs)

#populates the CSV source URI and layer name lists
csvSrcRawUri = r"E:\Jason\Documents\2020-01\mapping project\gis\test_automate_all\sources\datasetsrekeithsstudy"
csvSrcUri = csvSrcRawUri.replace("\\", "/")
csvSrcUriList = []
csvSrcUriIndex = 0
csvLayerNameList = []
for root, dirs, files in os.walk(csvSrcUri):
    for file in files:
        if(file.endswith(".csv")):
            csvSrcUriList.append(os.path.join(root,file))
            csvLayerNameList.append(os.path.join(file))

#sorts the CSV source URI and layer name lists alphabetically to match eachother
csvSrcUriList.sort()
csvLayerNameList.sort()

#populates the CSV preprocessing URI list
csvPreprocDirUri = dataPreprocDirUri
csvPreprocUriList = []
csvPreprocUriIndex0 = 0
while csvPreprocUriIndex0 < len(csvSrcUriList):
    csvPreprocUri = csvPreprocDirUri + "/" + csvLayerNameList[csvPreprocUriIndex0]
    csvPreprocUriList.append(csvPreprocUri)
    csvPreprocUriIndex0 += 1

#reformat fields as percentages
csvPreprocUriIndex1 = 0
for csvFile in csvSrcUriList:
    rowList = []
    fldList = []
    with open(csvFile, 'r', encoding="utf-8", newline='') as csvSrcFile, open(csvPreprocUriList[csvPreprocUriIndex1], 'w', encoding="utf-8", newline='') as csvTrgtFile:
        csvreader = csv.reader(csvSrcFile)
        csvwriter = csv.writer(csvTrgtFile)
        fldList = next(csvreader)
        csvwriter.writerow(fldList)
        for row in csvreader:
            rowList.append(row)
        for row in rowList:
            rowIdx = 1
            while rowIdx < len(row):
                percentValue = format(float(row[rowIdx])*100, ".9g")
#                percentValue = str(float(row[rowIdx])*100)
                row[rowIdx] = percentValue
                rowIdx += 1
        csvwriter.writerows(rowList)
    csvPreprocUriIndex1 += 1

#copies the CSV preprocessing URI list and reformats the items in it so they can be used by the QgsVectorLayer() method
csvVectorLayerUriList = csvPreprocUriList.copy()
csvVectorLayerUriIndex = 0
for file in csvVectorLayerUriList:
    filePrefix = 'file:///'
    fileSuffix = '?delimeter=,'
    fileLocation = filePrefix + file + fileSuffix
    csvVectorLayerUriList[csvVectorLayerUriIndex] = fileLocation
    csvVectorLayerUriIndex += 1

#populates the CSV layer URI list
csvLayerDirUri = dataLayerDirUri
csvLayerUriList = []
csvLayerUriIndex = 0
while csvLayerUriIndex < len(csvSrcUriList):
    csvLayerUri = csvLayerDirUri + "/" + csvLayerNameList[csvLayerUriIndex]
    csvLayerUriList.append(csvLayerUri)
    csvLayerUriIndex += 1

#removes the .csv extention from the items in the CSV layer name list
csvLayerNameIndex = 0
for file in csvLayerNameList:
    layerName =  file.replace(".csv", "")
    csvLayerNameList[csvLayerNameIndex] = layerName
    csvLayerNameIndex += 1

#loop to create and perform all operations on all CSV layers including grouping
csvSavedLayerList = []
csvLayerIndex = 0
for csvLayerName in csvLayerNameList:
    csvLayerUri = csvVectorLayerUriList[csvLayerIndex]
    #creates the CSV layer name from the list of csv names and fields
    csvLayerName = csvLayerNameList[csvLayerIndex]
    #adds the initial CSV layer to the project and checks the layer validity
    csvLayer = QgsVectorLayer(csvLayerUri, csvLayerName, 'delimitedtext')
    QgsProject.instance().addMapLayer(csvLayer)
    if not csvLayer or not csvLayer.isValid():
        csvAddLayerErrorMsg = csvLayerName + " failed to load!"
        print(csvAddLayerErrorMsg)
    #copies the shape layer and places the copy in the correct group
    root = QgsProject.instance().layerTreeRoot()
    csvGroup = root.findGroup(dataGroup.name())
    csvOriginalLayer = root.findLayer(csvLayer.id())
    csvGroupedLayer = csvOriginalLayer.clone()
    csvGroupedLayer = csvOriginalLayer.clone()
    csvGroup.insertChildNode(-1, csvGroupedLayer)
    csvSaveOptions = QgsVectorFileWriter.SaveVectorOptions()
    csvSaveOptions.driverName = "CSV"
    csvSaveOptions.fileEncoding = "UTF-8"
    csvSavedLayer = csvGroupedLayer.layer()
    QgsVectorFileWriter.writeAsVectorFormatV2(csvSavedLayer, csvLayerUriList[csvLayerIndex], QgsCoordinateTransformContext(), csvSaveOptions)
    if not csvGroupedLayer.layer() or not csvGroupedLayer.layer().isValid():
        csvSaveLayerErrorMsg = csvLayerName + " failed to save!"
        print(csvAddLayerErrorMsg)
    #removes the ungrouped shape layer
    parent = csvOriginalLayer.parent()
    parent.removeChildNode(root.findLayer(csvLayer.id()))
    #populates in the CSV saved layer list for use in table joins
    csvSavedLayerList.append(csvSavedLayer)
    
    csvLayerIndex +=1

This section of code creates a "preprocessing" directory for storing the CSV files modified with Python's built-in csv() method:

#creates the data preprocessing directory
dataPreprocDirName = "preprocessing"
dataPreprocDirUri = dataLayerDirUri + "/" + dataPreprocDirName
if not os.path.isdir(dataPreprocDirUri):
    os.mkdir(dataPreprocDirUri)
else:
    print(projDirErrorMsg.format(dataPreprocDirName))

This section does the preprocessing(multiplying the CSV values by 100) and saving the modified CSV values in a new CSV file:

#populates the CSV source URI and layer name lists
csvSrcRawUri = r"E:\Jason\Documents\2020-01\mapping project\gis\test_automate_all\sources\datasetsrekeithsstudy"
csvSrcUri = csvSrcRawUri.replace("\\", "/")
csvSrcUriList = []
csvSrcUriIndex = 0
csvLayerNameList = []
for root, dirs, files in os.walk(csvSrcUri):
    for file in files:
        if(file.endswith(".csv")):
            csvSrcUriList.append(os.path.join(root,file))
            csvLayerNameList.append(os.path.join(file))

#sorts the CSV source URI and layer name lists alphabetically to match eachother
csvSrcUriList.sort()
csvLayerNameList.sort()

#populates the CSV preprocessing URI list
csvPreprocDirUri = dataPreprocDirUri
csvPreprocUriList = []
csvPreprocUriIndex0 = 0
while csvPreprocUriIndex0 < len(csvSrcUriList):
    csvPreprocUri = csvPreprocDirUri + "/" + csvLayerNameList[csvPreprocUriIndex0]
    csvPreprocUriList.append(csvPreprocUri)
    csvPreprocUriIndex0 += 1

#reformat fields as percentages
csvPreprocUriIndex1 = 0
for csvFile in csvSrcUriList:
    rowList = []
    fldList = []
    with open(csvFile, 'r', encoding="utf-8", newline='') as csvSrcFile, open(csvPreprocUriList[csvPreprocUriIndex1], 'w', encoding="utf-8", newline='') as csvTrgtFile:
        csvreader = csv.reader(csvSrcFile)
        csvwriter = csv.writer(csvTrgtFile)
        fldList = next(csvreader)
        csvwriter.writerow(fldList)
        for row in csvreader:
            rowList.append(row)
        for row in rowList:
            rowIdx = 1
            while rowIdx < len(row):
                percentValue = format(float(row[rowIdx])*100, ".9g")
#                percentValue = str(float(row[rowIdx])*100)
                row[rowIdx] = percentValue
                rowIdx += 1
        csvwriter.writerows(rowList)
    csvPreprocUriIndex1 += 1

The "encoding=utf-8" might no be necessary here, but I left it in.

Finally, several lines were added to the section that groups and saves the layer to clean up the duplicate layers that were appearing in the Layers Panel:

    #copies the shape layer and places the copy in the correct group
    root = QgsProject.instance().layerTreeRoot()
    csvGroup = root.findGroup(dataGroup.name())
    csvOriginalLayer = root.findLayer(csvLayer.id())
    csvGroupedLayer = csvOriginalLayer.clone()
    csvGroupedLayer = csvOriginalLayer.clone()
    csvGroup.insertChildNode(-1, csvGroupedLayer)
    csvSaveOptions = QgsVectorFileWriter.SaveVectorOptions()
    csvSaveOptions.driverName = "CSV"
    csvSaveOptions.fileEncoding = "UTF-8"
    csvSavedLayer = csvGroupedLayer.layer()
    QgsVectorFileWriter.writeAsVectorFormatV2(csvSavedLayer, csvLayerUriList[csvLayerIndex], QgsCoordinateTransformContext(), csvSaveOptions)
    if not csvGroupedLayer.layer() or not csvGroupedLayer.layer().isValid():
        csvSaveLayerErrorMsg = csvLayerName + " failed to save!"
        print(csvAddLayerErrorMsg)
    #removes the ungrouped shape layer
    parent = csvOriginalLayer.parent()
    parent.removeChildNode(root.findLayer(csvLayer.id()))

I was trying to cheat and skip the routine where the layer is duplicated, saved, and the original removed from the project, but that seems to break it. If anyone knows how to do this, please reply to this thread.

Source Link

So, the empty row issue was resolved for the following line:

    with open(csvFile, 'r') as csvSrcFile, open(csvLayerUriList[csvLayerUriIndex1], 'w') as csvTrgtFile:

The Python open() function requires the newline = ''argument in Windows as explained here. So, the corrected code looks like this:

    with open(csvFile, 'r', newline='') as csvSrcFile, open(csvLayerUriList[csvLayerUriIndex1], 'w', newline='') as csvTrgtFile:

However, all of the other issues still exist.