Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QGIS crashes every Python code testing #60025

Open
2 tasks done
ELJuliao opened this issue Dec 29, 2024 · 3 comments
Open
2 tasks done

QGIS crashes every Python code testing #60025

ELJuliao opened this issue Dec 29, 2024 · 3 comments
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter! Feedback Waiting on the submitter for answers

Comments

@ELJuliao
Copy link

What is the bug or the crash?

I am trying to create a Python code that reads a .csv with groundwater data to generate a vector file with potentiometric curves, however, everytime I test the code, the program crashes.

The code I tried to use is the one below:

from qgis.core import *
from qgis.gui import *
from qgis.analysis import QgsInterpolator, QgsIDWInterpolator
import os
from osgeo import gdal
import numpy as np
from PyQt5.QtWidgets import QFileDialog, QInputDialog, QApplication
import csv
import gc # Para gerenciamento de memória

def desenhar_curvas_potenciometricas():
"""
Script para desenhar curvas potenciométricas com base em arquivo CSV e parâmetros fornecidos pelo usuário.
"""
# Abrir diálogo para selecionar arquivo CSV
caminho_csv, _ = QFileDialog.getOpenFileName(None, "Selecione o arquivo CSV", "", "CSV Files (*.csv)")

if not caminho_csv:
    print("Nenhum arquivo selecionado.")
    return

# Abrir e ler o arquivo CSV
with open(caminho_csv, 'r', encoding='utf-8') as csvfile:
    leitor = csv.DictReader(csvfile)
    campos = leitor.fieldnames

    # Identificar colunas de coordenadas automaticamente
    colunas_x = [col for col in campos if col.lower() in ['x', 'longitude']]
    colunas_y = [col for col in campos if col.lower() in ['y', 'latitude']]

    if not colunas_x or not colunas_y:
        print("Não foi possível identificar colunas de coordenadas X e Y no arquivo.")
        return

    coluna_x = colunas_x[0]
    coluna_y = colunas_y[0]
    print(f"Coordenadas identificadas: X='{coluna_x}', Y='{coluna_y}'")

    # Solicitar ao usuário a coluna para interpolação
    coluna_valor, ok = QInputDialog.getItem(None, "Selecionar Coluna", "Selecione a coluna a ser interpolada:", campos, 0, False)

    if not ok or not coluna_valor:
        print("Nenhuma coluna selecionada para interpolação.")
        return

    # Solicitar intervalo entre curvas
    intervalo, ok = QInputDialog.getDouble(None, "Intervalo Entre Curvas", "Informe o intervalo entre as curvas potenciométricas:", 10.0, 0.1, 1000.0, 1)

    if not ok:
        print("Nenhum intervalo definido.")
        return

    # Solicitar curva inicial
    curva_inicial, ok = QInputDialog.getDouble(None, "Curva Inicial", "Informe o valor da curva potenciométrica inicial:", 0.0, -1000.0, 1000.0, 1)

    if not ok:
        print("Nenhuma curva inicial definida.")
        return

    # Criar URI para carregar o CSV como camada
    uri = f"file:///{caminho_csv}?delimiter=,&xField={coluna_x}&yField={coluna_y}&crs=EPSG:4326"
    camada_csv = QgsVectorLayer(uri, "Camada CSV", "delimitedtext")

    if not camada_csv.isValid():
        print("Erro ao carregar o arquivo CSV como camada.")
        return

    # Adicionar camada ao projeto QGIS
    QgsProject.instance().addMapLayer(camada_csv)

    # Configurar interpolador IDW
    layer_data = QgsInterpolator.LayerData()
    layer_data.vectorLayer = camada_csv
    layer_data.zCoordInterpolation = False
    layer_data.interpolationAttribute = camada_csv.fields().indexFromName(coluna_valor)

    interpolador = QgsIDWInterpolator([layer_data])

    # Configurar interpolação em lotes
    extent = camada_csv.extent()
    largura = int(extent.width() / intervalo)
    altura = int(extent.height() / intervalo)
    raster_path = "interpolacao.tif"

    batch_size = 20  # Tamanho do lote de processamento reduzido

    # Criar raster final
    driver = gdal.GetDriverByName("GTiff")
    dataset = driver.Create(raster_path, largura, altura, 1, gdal.GDT_Float32)
    dataset.SetGeoTransform([extent.xMinimum(), intervalo, 0, extent.yMaximum(), 0, -intervalo])
    band = dataset.GetRasterBand(1)
    band.SetNoDataValue(-9999)

    try:
        for batch_row in range(0, altura, batch_size):
            max_row = min(batch_row + batch_size, altura)

            for batch_col in range(0, largura, batch_size):
                max_col = min(batch_col + batch_size, largura)

                matriz = np.full((max_row - batch_row, max_col - batch_col), -9999, dtype=np.float32)

                for row in range(batch_row, max_row):
                    y = extent.yMaximum() - row * intervalo
                    for col in range(batch_col, max_col):
                        x = extent.xMinimum() + col * intervalo
                        z, ok = interpolador.interpolatePoint(x, y)
                        matriz[row - batch_row, col - batch_col] = z if ok else -9999

                # Escrever lote diretamente no raster final
                band.WriteArray(matriz, batch_col, batch_row)

                # Liberar memória do lote
                gc.collect()

        dataset.FlushCache()
        dataset = None

        # Adicionar raster ao projeto
        raster_layer = QgsRasterLayer(raster_path, "Curvas Potenciométricas")
        if not raster_layer.isValid():
            print("Erro ao carregar o raster como camada.")
            return

        QgsProject.instance().addMapLayer(raster_layer)

        # Criar contornos
        processamento = QgsProcessingFeedback()
        parametros = {
            'INPUT': raster_layer,
            'BAND': 1,
            'INTERVAL': intervalo,
            'FIELD_NAME': 'potencial',
            'OUTPUT': 'memory:'
        }

        resultado = processing.run("qgis:contour", parametros, processamento)
        camada_contornos = resultado['OUTPUT']
        QgsProject.instance().addMapLayer(camada_contornos)

        print("Curvas potenciométricas geradas com sucesso!")

    except Exception as e:
        print(f"Erro durante a interpolação ou criação do raster: {e}")

Inicialização do QGIS

QgsApplication.setPrefixPath("/path/to/qgis/installation", True)
qgs = QgsApplication([], False)
qgs.initQgis()

Chamar a função

desenhar_curvas_potenciometricas()

Finalizar o QGIS

qgs.exitQgis()

And here is the program report:

User Feedback

I am trying to create a Python code that access a .csv with groundwater data to generate a vetor file with potentiometric curves, however, everytime i test the code, the program crashes. If you can help me with this task, please, feel free to send an email at eduljuliao@gmail.com to talk about it.

Report Details

Python Stack Trace

Windows fatal exception: access violation

Current thread 0x00002760 (most recent call first):
  <no Python frame>

Stack Trace


QListData::size :
QgsExpressionNodeFunction::QgsExpressionNodeFunction :
QgsExpressionNodeLiteral::evalNode :
QgsExpressionNodeLiteral::evalNode :
QgsExpression::QgsExpression :
QgsGeometryGeneratorSymbolLayer::QgsGeometryGeneratorSymbolLayer :
QgsGeometryGeneratorSymbolLayer::create :
QgsSymbolLayerUtils::loadSymbolLayer :
QgsSymbolLayerUtils::loadSymbol :
QgsStyle::load :
QgsStyle::defaultStyle :
QgsCombinedStyleModel::addDefaultStyle :
QgsProject::QgsProject :
QgsProject::instance :
QgsMapCanvas::createExpressionContext :
QgsMapCanvas::refreshMap :
QObject::qt_static_metacall :
QTimer::timerEvent :
QObject::event :
QApplicationPrivate::notify_helper :
QApplication::notify :
QgsApplication::notify :
QgsPresetSchemeColorRamp::clone :
QCoreApplication::notifyInternal2 :
QEventDispatcherWin32Private::sendTimerEvent :
QEventDispatcherWin32::event :
QApplicationPrivate::notify_helper :
QApplication::notify :
QgsApplication::notify :
QgsPresetSchemeColorRamp::clone :
QCoreApplication::notifyInternal2 :
QCoreApplicationPrivate::sendPostedEvents :
qt_plugin_query_metadata :
QEventDispatcherWin32::processEvents :
qt_plugin_query_metadata :
QEventLoop::exec :
QCoreApplication::exec :
main :
BaseThreadInitThunk :
RtlUserThreadStart :

QGIS Info
QGIS Version: 3.34.13-Prizren
QGIS code revision: 222b599
Compiled against Qt: 5.15.13
Running against Qt: 5.15.13
Compiled against GDAL: 3.9.3
Running against GDAL: 3.9.3

System Info
CPU Type: x86_64
Kernel Type: winnt
Kernel Version: 10.0.19045

Steps to reproduce the issue

  1. Generated a .csv file to use as a test (please find it attached below, the EPSG is 31983)
    Potenciométrico.csv
  2. Opened the Python terminal and added the code at the edit window.
  3. After adding the inputs, the program crashed.

Versions

Versão do QGIS
3.34.13-Prizren
Código da versão do QGIS
222b599
Versão Qt
5.15.13
Versão do Python
3.12.7
Versão GDAL/OGR
3.9.3
Versão PROJ
9.5.0
Versão da base de dados do registro EPSG
v11.016 (2024-08-31)
Versão GEOS
3.13.0-CAPI-1.19.0
Versão SQLite
3.46.1
Versão PDAL
2.8.1
Versão cliente PostgreSQL
16.2
Versão SpatiaLite
5.1.0
Versão QWT
6.3.0
Versão QScintilla2
2.14.1
Versão OS
Windows 10 Version 2009

Plugins Python ativos
quick_map_services
0.19.36
db_manager
0.1.20
grassprovider
2.12.99
MetaSearch
0.3.6
processing
2.12.99

Supported QGIS version

  • I'm running a supported QGIS version according to the roadmap.

New profile

Additional context

No response

@ELJuliao ELJuliao added the Bug Either a bug report, or a bug fix. Let's hope for the latter! label Dec 29, 2024
@nyalldawson
Copy link
Collaborator

Are you running this from within qgis or externally? If you're running within, you need to remove the QgsApplication initialisation and exit lines.

@nyalldawson nyalldawson added the Feedback Waiting on the submitter for answers label Dec 29, 2024
@tsmcgrath
Copy link

tsmcgrath commented Jan 9, 2025

Similarly I am seeing QGIS 3.40.1 and 3.40.2 consistently crashing in the for loop of this snippet in the Python console:

# Get the root of the layer tree
root = QgsProject.instance().layerTreeRoot()

# Replace 'GeoCatch_v1-0' with the name of your layer
layer_name = 'GeoCatch_v1-0'  # Replace with your layer name
layer_tree_layer = root.findLayer(QgsProject.instance().mapLayersByName(layer_name)[0].id())
legend_model = QgsLayerTreeModel(root)
# Iterate over the legend items for the layer
for index in range(legend_model.rowCount()):
    item = legend_model.index(index, 0).internalPointer()
    item.printLegend()

I'm on a Mac Pro M1 with Sequoia 15.1.1. Native ARM QGIS build from:
https://github.com/opengisch/qgis-conda-builder/releases

@tsmcgrath
Copy link

Here's the crash log. Repro's every time.
legendcrash_20250110.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter! Feedback Waiting on the submitter for answers
Projects
None yet
Development

No branches or pull requests

3 participants