Сделайте обновление слоя Qgis из измененного источника данных

13

Я пытаюсь заставить слои обновляться автоматически при изменении источника данных. Я использую R, чтобы написать шейп-файл с атрибутом и раскрасить в соответствии с этим атрибутом в QGIS.

Я хочу написать новый шейп-файл с другими значениями атрибутов и обновить цвета карты Qgis. Шаг 1 запускает этот процесс, шаг 2 заставляет слой перезагрузиться из измененного шейп-файла. Его шаг 2, о котором я беспокоюсь здесь.

Другие вопросы / списки рассылки, которые упоминаются triggerRepaintв слое - это не работает. Другие предложения включают setCacheImage(None)и снова это не работает. Слой обновляется в конце концов, но я действительно не вижу логики, и иногда это происходит неожиданно после того, как я ничего не сделал. Или, может быть, я сделал что-то две минуты назад.

Единственный воспроизводимый способ обновить его - дублировать слой из меню легенды - дубликат всегда получает свои данные из текущего шейп-файла, а оригинальный слой тоже обновляется! Так что должен быть какой-то способ сделать это.

Я думаю, что он работал лучше в 2.8, но это 2.10, так что, возможно, где-то есть новая ошибка.

Связано, но у меня не работает в 2.10:

Как автоматически перезагрузить растровые слои, если источник изменился в QGIS?

Другие вещи, которые я пробовал:

  • layer.dataProvider().dataChanged.emit() - работал один раз, потом не снова на том же слое

Я думаю, что я выяснил, почему дублирование слоя работает - если я создаю новый одноуровневый слой на основе обновленного слоя, а затем вызываю .triggerRepaint()обновленный слой, он обновляется на холсте карты:

QgsVectorLayer( layer.source(), "layer copy", layer.providerType() )
layer.triggerRepaint()

Если я использую другой источник слоя, он не будет работать, так что, похоже, если вы создадите объект слоя на основе того же источника слоя ...

Быстрый тест только что с растровым слоем (из GeoTIFF), и просто вызов, rlayer.triggerRepaint()кажется, надежно обновляет вид растра на холсте карты.

Spacedman
источник
Возможно, вам придется опубликовать пример кода.
Натан W
@NathanW большая часть того, что я делаю, это из графического интерфейса - загрузите слой, стилизуйте его, а затем просто получите слой и эти несколько строк в консоли Python. Я не склонен вставлять это в рамки плагина, пока не узнаю, что смогу заставить принцип работать! Я надеялся, что будет быстрый ответ ("call layer.updateFromNewDataYouFool ()"), но я заполню его большим количеством кода (включая код R для создания шейп-файлов) позже.
Spacedman
Чтобы быть уверенным, вы пытались использовать обе команды впоследствии: layer.setCacheImage(None)и layer.triggerRepaint()?
Матиас Кун
Да @MatthiasKuhn - хотя иногда это работает, но не часто. Я только что написал измененный шейп-файл, сделал обе эти вещи в консоли Python (на правом уровне), без визуального обновления. Самая простая вещь, которая до сих пор работала на 100%, - это создание нового одноуровневого объекта слоя на основе исходного источника слоя, как упомянуто выше, а затем triggerRepaint()на исходном слое. v 2.10.1-Пиза
Spacedman
У меня есть подозрение, что это может быть связано с введением пула соединений OGR. Можете ли вы выполнить некоторые тесты, если есть разница, если вы замените файл на диске или отредактируете существующий файл?
Матиас Кун

Ответы:

5

Это связано с введением пула соединений OGR. [1]

До QGIS 2.10 файл открывался при каждом доступе (например, перерисовка).

Начиная с QGIS 2.10, дескриптор файла остается открытым, и это означает, что при замене файла дескриптор по-прежнему указывает на старый файл в системах на основе Unix.

QGIS 2.10: обходной путь

К сожалению, нет API, который бы принудительно заставлял QGIS повторно открывать файл в QGIS 2.10. В качестве обходного пути вы можете использовать некрасивый хак:

layer.dataProvider().changeAttributeValues( { -1: { 0: 0 } } )
layer.triggerRepaint()

QGIS 2.12: решение

Я только что представил новый метод, который будет доступен начиная с QGIS 2.12:

layer.dataProvider().forceReload()
layer.triggerRepaint()

Общий подход

Если у вас есть возможность контролировать, как файл перезаписывается, вы можете открыть существующие файлы с разрешениями на запись и изменить содержимое вместо полной замены файлов (удаления / воссоздания) на диске.

[1] Пул соединений был введен, чтобы значительно ускорить доступ к определенным источникам данных.

Матиас Кун
источник
Похоже, лучшее решение. В .changeAttributeValuesрезультате появляется «ОШИБКА 1: Попытка чтения формы с идентификатором функции (-1) вне доступного диапазона». но это нормально.
Spacedman
2

Если вы перемещаетесь или обновляете карту, она должна обновиться.

В этой статье говорится, что вы можете использовать следующее в PyQGIS:

myLayer.triggerRepaint()

Для обновления всех слоев можно использовать следующую функцию:

def refresh_layers(self):
    for layer in qgis.utils.iface.mapCanvas().layers():
         layer.triggerRepaint()
Алекс Лейт
источник
Как я уже сказал в своем вопросе и как упомянуто в ссылке, которую я дал, triggerRepaint()не работает. refresh()на карте холст не работает. Установка изображения кэша в None(что сейчас не рекомендуется в документации API) не работает. Я просто пробовал все эти вещи на новом измененном слое шейп-файла, панорамировал карту, включал и выключал, это не сработало. «Дублируйте» слой, и он мгновенно обновляется. Вы сами пробовали эти вещи (2.10)?
Spacedman
Я думаю, нам нужен @ nathan-w, чтобы ответить на это. Я сам не пробовал ...
Алекс Лейт,
Я пробовал #qgis в IRC, но, возможно, мне нужно публиковать сообщения в списке рассылки qgis-dev ...
Spacedman