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

ArcGIS API for Python StoryMaps v 2.3.0 Issues on StoryMap Publishing ("get" & "node" deprecation and content_list alternative) #1825

Open
nvshamblin opened this issue May 14, 2024 · 11 comments
Assignees

Comments

@nvshamblin
Copy link

Describe the bug
After the release of 2.3.0, code that was previously functioning for StoryMap updating is now causing an error that I'm unable to troubleshoot. From the release documentation, it seems that both get and node functions are deprecated, however I've been able to run my script without error up until the step to publish the StoryMap.

To Reproduce
Steps to reproduce the behavior:

Below is a reduced version of the script. Its steps include setting the extent of each of the sidecar webmaps to a determined extent based on a shapefile input. The "webmap_list" contains a list of the webmap nodes.

storymap_name = 'examplestorymapid'
...
#Get sidecar
sidecar = my_story.content_list[17]
#For all webmaps in side car, set viewpoint to extent for aoi
webmap_list = [...]
try:
    for item in webmap_list:
        webmap = sidecar.get(item)
        webmap.set_viewpoint(extent, Scales.TOWN)
except Exception:
my_story.save()

error:

When I silence the "my_story.save()" code, no errors are returned. Otherwise, the following error occurs:

<UnicodeEncodeError                        Traceback (most recent call last)
In  [24]:
Line 75:    my_story.save()

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\site-packages\arcgis\apps\storymap\story.py, in save:
Line 942:   return utils.save(self, title, tags, access, publish)

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\site-packages\arcgis\apps\storymap\_utils.py, in save:
Line 191:   json.dump(story._properties, temp, ensure_ascii=False)

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\json\__init__.py, in dump:
Line 180:   fp.write(chunk)

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\tempfile.py, in func_wrapper:
Line 500:   return func(*args, **kwargs)

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\encodings\cp1252.py, in encode:
Line 19:    return codecs.charmap_encode(input,self.errors,encoding_table)[0]

UnicodeEncodeError: 'charmap' codec can't encode character '\u202f' in position 207: character maps to <undefined>

Expected behavior
The sidecar webmaps should all be set to the established extent based on a shapefile input.

Platform (please complete the following information):

  • Python API Version 2.3.0

I'm fairly green with coding and any help here is appreciated. Any help on using the new content_list property (recommended as an alternative to the deprecated get and node functions) for the StoryMaps API would be greatly appreciated. Thanks for your help!

@nvshamblin nvshamblin added the bug label May 14, 2024
@nanaeaubry nanaeaubry self-assigned this May 14, 2024
@nanaeaubry
Copy link
Contributor

@nvshamblin Thanks for bringing this up! I will take a look and get back to you soon with some workaround if possible and see if this is an unintended bug! :)

@nvshamblin
Copy link
Author

Thank you, Nanae! Through some experimenting, I've discovered that this error is resulting after I've updated my ArcGIS Pro to the latest 3.3.0 version. My colleagues still working in the earlier version (3.2.2) have not reported this issue, so just wanted to provide that additional info. Thanks for your help!

@nanaeaubry
Copy link
Contributor

@nvshamblin
Sorry there are no guides out for storymap so it is not very intuitive to always understand the changes made. The reason get was deprecated was to move towards an object oriented approach. This means we have classes dedicated to each type of content and rather than having to understand nodes and ids, you can find what you are looking for and directly access the class.

So for example you are using content_list on the Storymap instance. This allows you to get the Sidecar class right away. The content list appears in the order of the content in the story.

In the Sidecar class you will find a similar property called content_list this allows you to also see the list of content (as classes) that is held within that instance of Sidecar.

A simple example here:
image

What we see is that my sidecar has 4 slides. Each sub-list is one slide.
So the first slide has a Text instance, a Button instance, and an Image. The second slide has a Text and WebMap instance, and so on.

This means less guessing on what the nodes are to get your content. You can iterate through the list to find what you need.

If I wanted to get all the maps in my Sidecar I can create a nested loop:

webmaps = []

for slide in sidecar.content_list:
    for content in slide:
        if isinstance(content, Map):
            webmaps.append(content)

In my case this will return:
image

Since I only have one webmap present. You can then use this list of webmaps to loop through and change the viewpoint as you are doing above but without the get.

for item in webmaps:
    item.set_viewpoint(extent, Scales.TOWN)

@nanaeaubry
Copy link
Contributor

@nvshamblin As far as the save error goes I do not see it and it is probably specific to the storymap content you have and a bug on our end. Is this occurring if you just read the story item into the Storymap class and save without making any changes?

@nvshamblin
Copy link
Author

Thank you so much @nanaeaubry! I really appreciate your thorough and prompt response. The content_list explanation and examples are incredibly helpful. I will be testing those out once I've resolved the other "save" error.

I hadn't even thought to test out the "save" after simply reading the story item into the StoryMap class, but as you suggested, it did error out, so it must be something within the storymap content of my StoryMap.

Based on this, I think I have narrowed the cause of the UnicodeEncodeError to something in the text of the sidecar slide descriptions. Do you think, if I can iterate a replacement of the unicode code, ie. Replace ('\u202f', '') in all of the sidecar 'text' instances, that this might solve the issue? If so, could you help in suggesting how to going about that process?

Here's my initial thought process based on your advice above:

sidecar_text = []

for slide in sidecar.content_list:
    for content in slide:
        if isinstance(content, Text):
            sidecar_text.append(content)

for item in sidecar_text:
    item.replace('\u202f', '')

Thanks again for your help; your patience and support are much appreciated! :)

@nanaeaubry
Copy link
Contributor

@nvshamblin The code looks good! You're right that is probably the issue. There are some known complications with saving unicode text since we have to pass everything to json and back.

I would try that and see if it works! Good luck!

@nvshamblin
Copy link
Author

nvshamblin commented May 16, 2024

@nanaeaubry Sorry to keep this thread going, but I have somewhat solved the initial issue only to expose a new error! :(

I attempted the .replace() code I mentioned above to no avail (it prompted the following error: AttributeError: ‘dict’ object has no attribute ‘replace’)

However, it is okay because I was able to scrub my StoryMap for the unicode '\u202f' symbol using the .properties property of my sidecar.content_list and clean up my template so there were no strange unicode symbols.

Next, I updated my .set_viewpoint loop using your crisp and clean code (thank you!!), which worked flawlessly.

However, strangely enough, after running the script and opening the StoryMap to publish the edits, it exposed some weird symbols (see below).

Screenshot 2024-05-16 135115

So then I simply cleaned up the symbols hoping to have a clean StoryMap to work off of. Then, for safe measure, I ran the same code as I had before on the same published StoryMap, just wanting to ensure that no other errors would arise, and I got a new error! :(

KeyError                                  Traceback (most recent call last)
In  [22]:
Line 75:    for slide in sidecar.content_list:

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\site-packages\arcgis\apps\storymap\story_content.py, in content_list:
Line 3442:  content.append(self.get(media))

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\site-packages\arcgis\apps\storymap\story_content.py, in get:
Line 3539:  return utils._assign_node_class(self._story, node_id)

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\site-packages\arcgis\apps\storymap\_utils.py, in _assign_node_class:
Line 770:   node = Content.Map(story=story, node_id=node_id)

File C:\Users\...\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\Lib\site-packages\arcgis\apps\storymap\story_content.py, in __init__:
Line 1513:  self._lighting_date = self._story._properties["resources"][

KeyError: 'lightingDate'

Any idea on what could be the issue here?

Thanks so much for all your help!

@nanaeaubry
Copy link
Contributor

@nvshamblin
No worries for continuing to post! That's why we have this repo :)

For that first error that is my bad I missed something in your code.
When you do:

sidecar_text = []

for slide in sidecar.content_list:
    for content in slide:
        if isinstance(content, Text):
            sidecar_text.append(content)

for item in sidecar_text:
    item.replace('\u202f', '')

The item is an instance of the Text class. To get the text within it you have to use the text property.

So the correct code is:

sidecar_text = []

for slide in sidecar.content_list:
    for content in slide:
        if isinstance(content, Text):
            sidecar_text.append(content)

for item in sidecar_text:
    new_text = item.text.replace('\u202f', '')
    item.text = new_text

You can make it all one line but this way you see the workflow a bit better. Sorry about that oversight!


For the next part of the issue that is odd. That property only applies if your map is a webscene and not a webmap...

If you are in fact using a webscene then it seems that it is missing a resource when it got added to the Storymap. This could be for a few reasons... One suggestion is to find the webscene and re-add it. Replacing the one you have now and seeing if that works.

You can get the current map item by getting that instance where it is failing and using the map property to set it.

So something like this:

# Let's say this is your list of maps that are in your sidecar
webmaps_in_sidecar = [Web Map, Web Map, Web Scene, Web Map]

# take the map you want to edit
scene = webmaps_in_sidecar[2]

# look at the current map (in a notebook it will show the item iframe)
item = scene.map
item

# try replacing the scene with the same scene to have it update (this is my best guess to 'refresh' it)
scene.map = item

# update the viewpoint
scene.set_viewpoint(...)

storymap.save()

Let me know if that works! Also odd that you get the weird symbols...
If you can send me the text I can put it into my storymap and see what is happening.
Best way to get that text is to use the text property.

some pseudo-ish code:

text_list = []
list_of_text_in_sidecar = [Text, Text, Text...]
for text_class in list_of_text_in_sidecar:
    text_list.append(text_class.text)
print(text_list)

If there are too many text just get the first two or three so I can test. I think it has to do with JSON encoding going wrong and I can ask the storymap team as well for some insight on how to accomplish what you want with the text.

FYI: I am in a different time zone incase I don't reply until next week ;)

@nanaeaubry
Copy link
Contributor

@nvshamblin
One more suggestion!

You can also make a smaller storymap that has just one or two maps and some text in a sidecar and share that publicly with me so I can test directly on it if that is easier.

@nvshamblin
Copy link
Author

Hi @nanaeaubry, thank you so much for your code to replace the unicode text in the sidecar text, it worked flawlessly!

After scouring through the sidecar properties, I found these symbols to be the "problem children":

  • \u202f
  • \u200b
  • \xa0
  • ²
  • \ufffd

So, using your code, I replaced these as needed. Even after that, I was still having an error come up :( . So, after further review I realized there was one of these symbols ("—") in the titles of one of the map layers in an underlying StoryMap map that was causing the issue! So, I renamed the layer and re-added the map to StoryMap and that did the trick!

What's so strange is that I've been using the same StoryMap template for over a year now and have never had this issue. Goes to show, maybe I should've updated it a while ago ;)

As for the web scene error, you were totally right about that. It was a web scene that was causing the "lightingDate" key error. I replaced the web scene per your suggestion, but that unfortunately didn't do the trick. So, I simply performed the "set_viewpoint" code on all maps less the web scene and that seems to work just fine!

Do you know if the set_viewpoint works on web scenes (and/or swipes)? Up to now, I've been operating under the assumption that you can't set the viewpoints on those types of StoryMap items, which might explain why I was getting an error, but if this is not the case, I'm not sure...

Thanks so much again for your help, you're a rockstar!

@nanaeaubry
Copy link
Contributor

@nvshamblin
On the swipe you can't edit the Map yet. I will put in an enhancement issue so we can tackle that in the near future. You would have to dig into the dictionary structure of the swipe a bit to do that now.
Normally set_viewpoint should work on a webscene but it seems that isn't the case so I will take a look and open an issue if needed!
Thanks for all the details, it helps us a lot since it's difficult to anticipate all workflows so this helps us understand how to make improvements. :) I will post any further updates here!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants