4

I'm trying to plot one point "jumping" each second in the canvas (like a gps tracking). I need to take points from a .csv file.

This functionality is made in a QWidget of my application, so the code is the next:

class StartTrack(QWidget):
def __init__(self, MapExplorer):
 QWidget.__init__(self)
 self.MapExplorer = MapExplorer # MapExplorer is my principal class
def starting(self): # I call this method when push a button in the UI
 self.j = 0
 self.addTarget()
def addTarget(self):
 with open('C:\Users\Nacho\SkyLife\GIS4Ship\Archivos\Lex\data\Targets_com.csv') as f:
 self.j += 1
 self.lector = csv.reader(f)
 for i in range(0,self.j):
 row = self.lector.next()
 x = row[1]
 y = row[2]
 # I have this on MapExplorer:
 # self.target_layer = QgsVectorLayer('Point?crs=EPSG:4326', 'points' , 'memory')
 # self.trackprovider = self.target_layer.dataProvider()
 # QgsMapLayerRegistry.instance().addMapLayer(self.target_layer)
 trackprovider = self.MapExplorer.trackprovider
 target = self.MapExplorer.target_layer
 features = []
 feature = QgsFeature()
 feature.setGeometry(QgsGeometry.fromWkt("POINT ("+x+" "+y+")"))
 features.append(feature)
 trackprovider.addFeatures(features)
 target.updateExtents()
 target.triggerRepaint()
 print(self.j, row)
 QTimer.singleShot(1000, self.addTarget) # Recursive call

My problem is that I can't "delete" the previous point at canvas. I really delete each feature in each iteration, because I'm redefining everything: trackprovider (QgsVectorLayer.dataProvider), target (QgsVectorLayer), features (list of feature), and feature (point).

I want to see only one point each iteration (like moving through canvas) instead of this: enter image description here

I've already tried to delete feature from list and from layer too, but not results.

Am I missing something related to refreshing canvas, layer or provider?

PolyGeo
65.5k29 gold badges115 silver badges350 bronze badges
asked Sep 16, 2016 at 10:31
6
  • You can find a similar example here: gis.stackexchange.com/questions/189735/… Instead of deleting features you could filter them out with a where clause (see setSubsetString). Commented Sep 16, 2016 at 12:31
  • I'm not familiar with the MapExplorer.trackprovider method, have you looked into creating a in-memory point layer as a QgsVectorLayer? You may have better control commuting and deleting features from this layer type. Commented Sep 19, 2016 at 12:47
  • Thank you for your comments and sorry for my late answer, I've been busy and also have tried more ways to get my goal. First, @artwork21, trackprovider is my assignment to the dataProvider method. And for the in-memory point layer you referred, the next is the way for that no? # self.target_layer = QgsVectorLayer('Point?crs=EPSG:4326', 'points' , 'memory') # self.trackprovider = self.target_layer.dataProvider() Commented Sep 29, 2016 at 7:57
  • @GermánCarrillo, I took this recursive idea from that example and I investigated about setSubsetString, but I don't know what is the syntax to use it, I'm not familiarised with SQL and can't find useful list or tables for that, so if could tell me some reference I will be grateful. I tried others ways to get the points appear and dissapear in each loop iteration (deleting or filtering), and I get that the only way is by using dataProvider, isn't it? Thank you again. Commented Sep 29, 2016 at 7:57
  • What do you intend to do for each feature. Do you intend to generate an image with the canvas content? Commented Sep 29, 2016 at 16:05

1 Answer 1

1

I wrote my own script running it in QGIS. And I use my postgresql database with postgis extension to store and load the layers.

First, I create a points layer via my add_layer function and give it to the QgsMapLayerRegistry. Afterwards I start recursive function calling itself every 2000 milliseconds to show next point. Therefore, I use the setSubsetString on the point_id of the layer.

from qgis.core import QgsDataSourceURI, QgsVectorLayer, QgsMapLayerRegistry
from PyQt4.QtCore import QTimer
def show_next_point():
 global current_point
 if current_point == 10:
 current_point = 0
 subset = '"point_id" = {}'.format(current_point)
 point_layer.setSubsetString(subset)
 current_point += 1
 QTimer.singleShot(2000, show_next_point)
def add_layer():
 uri = QgsDataSourceURI()
 uri.setConnection('localhost', '5432', 'postgres', 'postgres', password)
 uri.setDataSource('', '(SELECT * FROM points)', 'geom', '', 'point_id')
 return QgsVectorLayer(uri.uri(), 'point_layer', 'postgres')
map_registry = QgsMapLayerRegistry.instance()
point_layer = add_layer()
map_registry.addMapLayer(point_layer)
# Start recursive function to iterate trough points:
current_point = 0
show_next_point()

To create the point-table and fill it with 10 points I used:

import psycopg2
# Insert your password:
connection_string = (
 'dbname=postgres ' +
 'host=localhost ' +
 'port=5432 ' +
 "user='postgres' " +
 "password='" + password + "'"
)
connection = psycopg2.connect(connection_string)
cursor = connection.cursor()
def create_table():
 cursor.execute('CREATE EXTENSION postgis')
 create_sql = (
 'CREATE TABLE points ('
 'point_id integer NOT NULL, '
 'geom geometry(Point, 4326), '
 'CONSTRAINT points_pkey PRIMARY KEY (point_id)'
 ')'
 )
 cursor.execute(create_sql)
 for i in range(10):
 sql = (
 'INSERT INTO '
 'points '
 '(point_id, geom) '
 'VALUES '
 '(%(point_id)s, ST_SetSRID(ST_MakePoint( %(lon)s, %(lat)s), 4326)) '
 )
 params = {
 'lat': i*10,
 'lon': 90,
 'point_id': i
 }
 cursor.execute(sql, params)
 connection.commit()
create_table()

Hope this helps!

answered Oct 30, 2016 at 12:59
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.