Labelling points with attached photos

1296
5
01-26-2022 04:29 AM
Labels (1)
MatthewLaw_MM
New Contributor II

Could anyone help me work out how to use photos, stored as attachments, to label points in ArcGIS Pro?

From the documentation here (shown in the screenshot below), I'm fairly sure that this is possible, but I can't work out how to go about doing it and haven't been able to find any walkthroughs/tutorials/similar questions.

MatthewLaw_MM_0-1643199279392.png

I have a layer of points with images attached as below:

MatthewLaw_MM_1-1643199881045.png

and have got as far as trying to set attribute-level image marker symbols for the points, but when I click the highlighted button to set the attribute mapping, there are no available options to use the attached images.

MatthewLaw_MM_2-1643199968621.png

Do I need to attach the images in a different format in order to be able to use them in this context?

Additionally (and I fear this may be a deal breaker), I need the actual points to be visible, ie the images should be plotted around the points and not directly on top of them, ideally using the labelling engine used for text labels. There are several areas where there are many points close to each other, and so if I can't control where the images get plotted relative to the point location, I'll end up with lots of images on top of each other and their corresponding points obscured.

0 Kudos
5 Replies
jcarlson
MVP Honored Contributor

In order to place things using the labeling engine, they've got to be labels. But within the labeling settings, you can configure a point symbol to function as a label. I think that's under callout or background, but I'm not at my workstation with Pro at the moment.

Labels don't have quite the same ability to access feature attributes, though. And even if they could, I am not sure that an attachment can be accessed in this way... For instance, how would Pro know which attachment to use, in the event that there were multiple? And what if the attachment were not an image?

- Josh Carlson
Kendall County GIS
MatthewLaw_MM
New Contributor II

Thanks for your speedy response Josh! I've tried to get the functionality I want using labels before, but run into the issue you mention of labels not being able to access feature attributes in the same way that point marker symbols can (or at least should be able to) - do you think there would be any way to do what I want without using labels themselves?

0 Kudos
JohannesLindner
MVP Regular Contributor

A working, but basic approach:

  1. Join the Attachment table to the feature class.
    JohannesLindner_1-1643210744993.png

  2. You can now choose the DATA field of the attachment table as input for the picture marker
    JohannesLindner_2-1643210883792.png

     

Basically, that's it. To make it prettier:

  1. Set size and quality, set position to "Center bottom"
    JohannesLindner_3-1643211071173.png

     

  2. Add a marker layer on top of the picture layer, style it
    JohannesLindner_4-1643211172494.png

     

  3. rotate the whole symbol using a rotation field
    JohannesLindner_5-1643211268989.png

     

 

 

Before:

JohannesLindner_0-1643210513139.png

After:

JohannesLindner_6-1643211316927.png

 

I'm sure you could hack together a border around the picture somehow.

Unlike labels, symbols don't seem to have options for dynamic placement. Position and offset are either taken as values provided by the user or by a table field.

 

I haven't found a way to use labels for this task. You can't use the Attachments() and FeatureSetBy*() function in the Arcade label expression, and the DATA field of the joined attachment table is also not available.

 

I thought I had something using a Python label expression and trying to return an HTML <img> tag with a data uri, but it doesn't seem to work (it's because there are only a few text formatting tags allowed; I'll still leave the code here, maybe it helps):

def FindLabel([GlobalID]):
    import arcpy
    import base64
    att_table = 'path:/to/database.sde/Fotos__ATTACH'
    sql = "REL_GLOBALID = '{}'".format([GlobalID])
    cur = arcpy.da.SearchCursor(att_table, ['CONTENT_TYPE', 'DATA'], sql)
    for row in cur:
        b64 = base64.encodebytes(row[1])
        data_uri = 'data:{};base64,{}'.format(row[0], b64)
        #return data_uri[:30]  # this returns the start of the data_uri correctly
        return '<img src="{}"/>'.format(data_uri)  # this returns without error, but doesn't do anything
    return "N/A"

 

Don't know anything about JScript, maybe you can do something with that.


Have a great day!
Johannes
MatthewLaw_MM
New Contributor II

Thanks Johannes! What format do the photos in the attachment table need to be? The ones I have now are saved as attachments (I think they were collected via Field Maps and automatically stored in this way) but I also have them all downloaded to a local folder so could re-upload as a given file type if necessary.

And do you think there would be a way to dynamically offset all the labels so that the points don't get obscured (maybe in Python)? If not, seeing as using actual labels won't work with feature-level attribute mapping, I don't think I'm going to be able to do what I want/need to.

0 Kudos
JohannesLindner
MVP Regular Contributor

What format do the photos in the attachment table need to be?

The field mapping only recognizes BLOB (Binary Large OBject, so byte data) fields. If you have an ArcGIS Attachment table, there should be a BLOB field in there. If not, you can also create a BLOB field in your feature class and store the images there.

 

And do you think there would be a way to dynamically offset all the labels so that the points don't get obscured (maybe in Python)?

Dynamically? Probably not, for that you need to work with labels, not symbology. Maaaaaybe with Point Clustering in 2.9, but it doesn't seem likely.

With Python? You could map X and Y offset to fields in your feature class. You could then calculate these fields with Python, using the distance to nearby points as input. This could work for a fixed map scale and picture marker size. But as soon as you zoom out, the images will overlap each other again.

A simple approach to that with Arcade:

// calculate field OffsetX

// load other features
var gid = $feature.GlobalID
var fs = Filter(FeatureSetByName($datastore, "FeatureClass"), "GlobalID <> @gid")
// get nearby features
var nearby_features = Intersects(fs, Buffer($feature, 50))
// gravitational force in horizontal direction
var force = 0
for(var f in nearby_features) {
  var dist = Distance($feature, f)
  var dx = Geometry(f).X - Geometry($feature).X
  force -= dx / (dist * dist)
}
// magical number dependent on map scale and picture marker size
var magic_factor = 100

return force * magic_factor
// calculate field OffsetY

// load other features
var gid = $feature.GlobalID
var fs = Filter(FeatureSetByName($datastore, "FeatureClass"), "GlobalID <> @gid")
// get nearby features
var nearby_features = Intersects(fs, Buffer($feature, 50))
// gravitational force in vertical direction
var force = 0
for(var f in nearby_features) {
  var dist = Distance($feature, f)
  var dy = Geometry(f).Y - Geometry($feature).Y
  force -= dy / (dist * dist)
}
// magical number dependent on map scale and picture marker size
var magic_factor = 100

return force * magic_factor

 

Without offsets:

JohannesLindner_0-1643285830423.png

 

With offsets:

JohannesLindner_1-1643286262933.png

 

But it only works for a fix scale. When you zoom out, the images overlap again:

JohannesLindner_2-1643286369465.png

 


Have a great day!
Johannes