biodiv / anycluster

Server-side clustering of map markers for (Geo)Django

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AttributeError at /anycluster/kmeans/2/128/: 'str' object has no attribute 'x'

clime opened this issue · comments

Getting the exception for kmeans method:

/srv/www/cwu/anycluster/clusterer.py in points_calcPixelDistance
        distance_m = math.sqrt( (pointA.x - pointB.x)**2 + (pointA.y - pointB.y)**2 ) ...
▼ Local vars
pointA  
'0101000020E6100000A0FD481119B760C06E8B321B64165140'
pointB  
'0101000020E6100000079964E42CC65CC0AD6EF59CF4F45040'
zoom    
2
self    
<anycluster.clusterer.MapTools instance at 0x7f2bd02437e8>

For some reason, the geometry in your case is returned as a string and not a Point() . Could you please check if you have set your django model field correctly to a PointField like

coordinates = models.PointField(srid=4326)

If not, we still might be able to convert the string to a point in python before merging near clusters.

My definition of the point is:

    location = models.PointField('location', null=True, default=None)

I think the problem occurs around here:

                     580.  dist = self.maptools.points_calcPixelDistance(cluster.coordinates,point.coordinates, zoom)

cause the coordinates attribute returns the string.

If I look at local variables in distanceCluster(), I see this:

point   
Error in formatting: City matching query does not exist. Lookup parameters were {'pk': 1}
i   
0
c_distance  
50
self    
<anycluster.clusterer.MapClusterer instance at 0x7f81700ff248>
zoom    
2
cluster 
Error in formatting: City matching query does not exist. Lookup parameters were {'pk': 0}
points  
Error in formatting: City matching query does not exist. Lookup parameters were {'pk': 1}
current_clist   
Error in formatting: City matching query does not exist. Lookup parameters were {'pk': 1}

I don't know what these errors are and if it is relevant to the issue.

Grid clustering works for me.

I assume you have not applied anyclusters filter method. This means the grid cluster uses generic Q() objects for the query and not raw queries like the kmeans does. It seems the .raw() queries return a different format on your installation. If so, this will be easy to fix, but we have to make sure we're on the right track first. Could you please perform the following in a django python shell and post the output (of line 4 and 5) here?:

from yourapp.models import your_geodjango_model as G
test = G.objects.raw('SELECT id, location FROM your_geodjango_table WHERE id =1')
coords =test[0].location
print coords
coords.x

where the corresponding id is a row which contains a location geometry (as you allow null values here).
Which version of django are you using?

>>> from web.models import Crag as G
>>> test = G.objects.raw('SELECT id, location FROM web_crag WHERE id=10')
>>> coords = test[0].location
>>> print coords
POINT (5.3318988872000004 43.8144654369000008)
>>> coords.x
5.3318988872

Django 1.5. You are right, I don't use filtering of anycluster.

This is the query that is being run:

SELECT kmeans AS id, count(*), ST_Centroid(ST_Collect(location)) AS coordinates FROM (
  SELECT  kmeans(ARRAY[ST_X(location), ST_Y(location)], 6) OVER (), location FROM web_crag 
  WHERE ST_Within(location, ST_GeomFromText('POLYGON((-90.000000 40.979898, -90.000000 -0.000000, -135.000000 -0.000000, -135.000000 40.979898, -90.000000 40.979898))',4326) )) AS ksub 
GROUP BY kmeans ORDER BY kmeans;

Run on postgres console, it returns:

 id | count |                    coordinates                     
----+-------+----------------------------------------------------
  0 |    31 | 0101000020E610000022D5D90600A85DC028432C997B0A4240
  1 |    21 | 0101000020E6100000C0E1145DDA145CC0EDABB16FB9324340
  2 |    23 | 0101000020E6100000AF7480E71E2759C023DF247C5FFC3440
  3 |     7 | 0101000020E6100000359B7DBF20035BC0EA030CACB0544140
  4 |     8 | 0101000020E61000003CE89B6DFCB957C09F0C12826C094140
  5 |    18 | 0101000020E6100000BB4BC9FBC65C5AC0DD7D702DFDDC4340

Here is what happens on python console:

>>> points = G.objects.raw("SELECT kmeans AS id, count(*), ST_Centroid(ST_Collect(location)) AS coordinates FROM (SELECT  kmeans(ARRAY[ST_X(location), ST_Y(location)], 6) OVER (), location FROM web_crag WHERE ST_Within(location, ST_GeomFromText('POLYGON((-90.000000 40.979898, -90.000000 -0.000000, -135.000000 -0.000000, -135.000000 40.979898, -90.000000 40.979898))',4326) )) AS ksub GROUP BY kmeans ORDER BY kmeans;")
>>> point_list = list(points)
>>> for point in point_list:
...   print point
... 
Traceback (most recent call last):
  File "<console>", line 2, in <module>
  File "/srv/www/envs/cwu/lib/python2.7/site-packages/django/db/models/base.py", line 433, in __str__
    return force_text(self).encode('utf-8')
  File "/srv/www/envs/cwu/lib/python2.7/site-packages/django/utils/encoding.py", line 99, in force_text
    s = s.__unicode__()
  File "/srv/www/cwu/web/models.py", line 48, in __unicode__
    return self.name
  File "/srv/www/envs/cwu/lib/python2.7/site-packages/django/db/models/query_utils.py", line 103, in __get__
    instance._state.db).get(pk=instance.pk),
  File "/srv/www/envs/cwu/lib/python2.7/site-packages/django/db/models/query.py", line 401, in get
    (self.model._meta.object_name, kwargs))
DoesNotExist: Crag matching query does not exist. Lookup parameters were {'pk': 0}
>>> for point in point_list:
...   print point.coordinates
... 
0101000020E610000022D5D90600A85DC028432C997B0A4240
0101000020E6100000C0E1145DDA145CC0EDABB16FB9324340
0101000020E6100000AF7480E71E2759C023DF247C5FFC3440
0101000020E6100000359B7DBF20035BC0EA030CACB0544140
0101000020E61000003CE89B6DFCB957C09F0C12826C094140
0101000020E6100000BB4BC9FBC65C5AC0DD7D702DFDDC4340

Thank you very much, I think I now know what causes the error. In my database, the PointField() is named coordinates, and therefore triggers Djangos Point conversion - also if a raw query is made and the field is not directly targeted. I will upload a fix for this today.

fixed with commit #29

I would appreciate it if you let me know if the fix worked for you. Thanks!