Can't create a valid Web Map from a JSON definition using the Python API

989
3
Jump to solution
11-06-2018 10:45 AM
JonathanBailey
Occasional Contributor III

I want to create a new Web Map item using the Python API. I manually created a Web Map with the correct configuration, and then used

Item.get_data()

to get a JSON representation of the Web Map, which is as follows:

{
    "operationalLayers": [],
    "baseMap": {
        "baseMapLayers": [{
            "id": "CBMT_CBCT_GEOM_3857_8319",
            "layerType": "ArcGISTiledMapServiceLayer",
            "url": "http://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_CBCT_GEOM_3857/MapServer",
            "visibility": true,
            "opacity": 1,
            "title": "CBMT_CBCT_GEOM_3857"
        }, {
            "id": "CBMT_TXT_3857_1321",
            "layerType": "ArcGISTiledMapServiceLayer",
            "url": "http://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_TXT_3857/MapServer",
            "visibility": true,
            "opacity": 1,
            "title": "CBMT_TXT_3857",
            "showLegend": true
        }],
        "title": "The Canada Base Map - Transportation (CBMT)"
    },
    "spatialReference": {
        "wkid": 102100,
        "latestWkid": 3857
    },
    "authoringApp": "WebMapViewer",
    "authoringAppVersion": "10.6.1",
    "version": "2.11"
}

I then saved this to a JSON file, CBMT.json.

Next, I tried to create a new Web Map using this JSON as a template:

item_properties = {
    "type": "Web Map",
    "tags": "basemap",
    "access": "org"
}

cbmt = tc_gis.content.add(item_properties, "CBMT.json", folder = "Basemaps")

The portal item is created, however, the web map appears to not be valid. In Portal, clicking on the Settings tab on the Portal item hangs, as does trying to open the web map in the map viewer.

0 Kudos
1 Solution

Accepted Solutions
EarlMedina
Esri Regular Contributor

Hi Jonathan,

I believe I am indirectly assisting you with this issue but for the benefit of others this is how you would accomplish the result. You can do this two ways:

Using only the ArcGIS API for Python:

  • It is recommended to use an in-memory python dictionary object.
  • Since we're dealing with a Web Map you don't want to use data=jsonfile.json. Rather, you want to set the aforementioned in-memory dictionary as the value of the ‘text’ attribute in the 'item_properties' argument. This is explained here: arcgis.gis module — arcgis 1.5.1 documentation 
    textOptional string. For text based items such as Feature Collections & WebMaps

I used a simplified version of your original JSON so you'll just need to add/update the parts you need...

# Import modules
from arcgis.gis import GIS
from arcgis.mapping import WebMap

# Login into portal
gis = GIS("PORTALURL","LOGIN","PASSWORD")

# This is the JSON used to create the Web Map, using your two layers as a basemap
data = {"operationalLayers": [],"baseMap": {"baseMapLayers": [{"id": "labels","opacity": 1,"visibility": True,"url": "https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_CBCT_GEOM_3857/MapServer"},{"id": "base","opacity": 1,"visibility": True,"url": "https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_TXT_3857/MapServer"}],"title": "Text"}}

# Fill this out as you see fit, the key part is the "text" attribute
item_properties_dict = {"type": "Web Map","title": "Test Map","tags": ["test","basemap","pythonapi"],"snippet":"This is a snippet", "text":data}

newmap = gis.content.add(item_properties = item_properties_dict)
newmap # Optionally, to display the result in Jupyter Notebook‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Reading from a JSON File:

  • If you prefer to read from a file, then you will need to incorporate the JSON module:

 

# Import modules
from arcgis.gis import GIS
from arcgis.mapping import WebMap
import json

# Login into portal
gis = GIS("PORTALURL","LOGIN","PASSWORD")

# Read the json file (here named test2.json
with open('/path/to/file/test2.json') as json_data:
    data = json.load(json_data)

# Again, fill this out as you see fit with the key part being the "text" attribute
item_properties_dict = {"type": "Web Map","title": "Test Map","tags": ["test","basemap","pythonapi"],"snippet":"This is a snippet", "text":data}

newmap = gis.content.add(item_properties = item_properties_dict)
newmap # Optionally, to display the result in Jupyter Notebook‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

Where test2.json is a file with the below contents:

{
    "operationalLayers": [],
    "baseMap": {
        "baseMapLayers": [{
                "id": "labels",
                "opacity": 1,
                "visibility": true,
                "url": "https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_CBCT_GEOM_3857/MapServer"
            }, {
                "id": "base",
                "opacity": 1,
                "visibility": true,
                "url": "https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_TXT_3857/MapServer"
            }
        ],
        "title": "Text"
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Here note that true is lowercase - in this case, you need to make this lowercase or else the json will fail to load. It needs to be capitalized, on the other hand, if you just use the API.

View solution in original post

3 Replies
EarlMedina
Esri Regular Contributor

Hi Jonathan,

I believe I am indirectly assisting you with this issue but for the benefit of others this is how you would accomplish the result. You can do this two ways:

Using only the ArcGIS API for Python:

  • It is recommended to use an in-memory python dictionary object.
  • Since we're dealing with a Web Map you don't want to use data=jsonfile.json. Rather, you want to set the aforementioned in-memory dictionary as the value of the ‘text’ attribute in the 'item_properties' argument. This is explained here: arcgis.gis module — arcgis 1.5.1 documentation 
    textOptional string. For text based items such as Feature Collections & WebMaps

I used a simplified version of your original JSON so you'll just need to add/update the parts you need...

# Import modules
from arcgis.gis import GIS
from arcgis.mapping import WebMap

# Login into portal
gis = GIS("PORTALURL","LOGIN","PASSWORD")

# This is the JSON used to create the Web Map, using your two layers as a basemap
data = {"operationalLayers": [],"baseMap": {"baseMapLayers": [{"id": "labels","opacity": 1,"visibility": True,"url": "https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_CBCT_GEOM_3857/MapServer"},{"id": "base","opacity": 1,"visibility": True,"url": "https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_TXT_3857/MapServer"}],"title": "Text"}}

# Fill this out as you see fit, the key part is the "text" attribute
item_properties_dict = {"type": "Web Map","title": "Test Map","tags": ["test","basemap","pythonapi"],"snippet":"This is a snippet", "text":data}

newmap = gis.content.add(item_properties = item_properties_dict)
newmap # Optionally, to display the result in Jupyter Notebook‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Reading from a JSON File:

  • If you prefer to read from a file, then you will need to incorporate the JSON module:

 

# Import modules
from arcgis.gis import GIS
from arcgis.mapping import WebMap
import json

# Login into portal
gis = GIS("PORTALURL","LOGIN","PASSWORD")

# Read the json file (here named test2.json
with open('/path/to/file/test2.json') as json_data:
    data = json.load(json_data)

# Again, fill this out as you see fit with the key part being the "text" attribute
item_properties_dict = {"type": "Web Map","title": "Test Map","tags": ["test","basemap","pythonapi"],"snippet":"This is a snippet", "text":data}

newmap = gis.content.add(item_properties = item_properties_dict)
newmap # Optionally, to display the result in Jupyter Notebook‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

Where test2.json is a file with the below contents:

{
    "operationalLayers": [],
    "baseMap": {
        "baseMapLayers": [{
                "id": "labels",
                "opacity": 1,
                "visibility": true,
                "url": "https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_CBCT_GEOM_3857/MapServer"
            }, {
                "id": "base",
                "opacity": 1,
                "visibility": true,
                "url": "https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_TXT_3857/MapServer"
            }
        ],
        "title": "Text"
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Here note that true is lowercase - in this case, you need to make this lowercase or else the json will fail to load. It needs to be capitalized, on the other hand, if you just use the API.

JonathanBailey
Occasional Contributor III

Perfect. Thanks, Earl.

Jon.

0 Kudos
EarlMedina
Esri Regular Contributor

No problem. If anyone out there is interested, you can greatly simplify your work by creating a Web Map with some sample data and adding whatever styles, labels, options, etc. From there, you can go to (where itemID is the item id of the Web Map):

https://machine.domain.com/portal/sharing/rest/content/items/<itemID>/data 

or

https://www.arcgis.com/sharing/content/items/<itemID>/data 

to get the dictionary used in:

data ={"operationalLayers": [],"baseMap": {"baseMapLayers"........

This is probably the easiest way to figure out how to structure the JSON to create a Web Map.

Note that if the Web Map is secured you'll need to append a token to the URL. Also, remember that if you're not reading the JSON from a file true will need to be changed to True.

0 Kudos