Read domain descriptions into spatially enabled dataframe

762
3
Jump to solution
05-05-2022 03:11 AM
HanliePetoors
New Contributor III

Hi,

I'm reading hosted feature layers from AGOL into a spatially enabled dataframe.

The fields that have coded value domains on them pass through the code from the domain, not the description.

Is there any way to substitute the code with the description when creating the dataframe? I can't find anything about that in the documentation.

Thanks

Hanlie

0 Kudos
1 Solution

Accepted Solutions
jcarlson
MVP Esteemed Contributor

You can't sub in the descriptions initially, but a simple replacement is quite easy. I have a little function I use in scripts where I want the descriptions instead of the codes.

 

def domain_descriptions(df, service):
    """
    Takes a queried dataframe and its parent service and applies all fieldname aliases and domain names.
    Not especially useful for updating web layers, but *great* for when the queried dataframe will be exported to some other format.

        Parameters:
            df (DataFrame): A dataframe queried out of a hosted feature service or table.
            service (FeatureLayer or Table): A layer or table from a Feature Service.

        Returns:
            None, just modifies the input DataFrame.
    """
    aliases = {f'{i["name"]}':f'{i["alias"]}' for (i) in service.properties['fields']}
    domains = {i['name']:{str(j['code']):j['name'] for (j) in i['domain']['codedValues']} for (i) in service.properties["fields"] if 'domain' in i and i['domain'] is not None}

    for d in domains:
        if d in df.columns.to_list():
            df[d] = df[d].astype('str').replace(domains[d])

    df.rename(columns=aliases, inplace=True)

 

Try it out! In practice, it might look like this:

fl = gis.content.get('some-itemid').layers[0]

df = fl.query(as_df=True)

domain_descriptions(df, fl)
- Josh Carlson
Kendall County GIS

View solution in original post

3 Replies
jcarlson
MVP Esteemed Contributor

You can't sub in the descriptions initially, but a simple replacement is quite easy. I have a little function I use in scripts where I want the descriptions instead of the codes.

 

def domain_descriptions(df, service):
    """
    Takes a queried dataframe and its parent service and applies all fieldname aliases and domain names.
    Not especially useful for updating web layers, but *great* for when the queried dataframe will be exported to some other format.

        Parameters:
            df (DataFrame): A dataframe queried out of a hosted feature service or table.
            service (FeatureLayer or Table): A layer or table from a Feature Service.

        Returns:
            None, just modifies the input DataFrame.
    """
    aliases = {f'{i["name"]}':f'{i["alias"]}' for (i) in service.properties['fields']}
    domains = {i['name']:{str(j['code']):j['name'] for (j) in i['domain']['codedValues']} for (i) in service.properties["fields"] if 'domain' in i and i['domain'] is not None}

    for d in domains:
        if d in df.columns.to_list():
            df[d] = df[d].astype('str').replace(domains[d])

    df.rename(columns=aliases, inplace=True)

 

Try it out! In practice, it might look like this:

fl = gis.content.get('some-itemid').layers[0]

df = fl.query(as_df=True)

domain_descriptions(df, fl)
- Josh Carlson
Kendall County GIS
HanliePetoors
New Contributor III

Thanks very much Josh, your script does exactly what I needed. 🙂

0 Kudos
Clubdebambos
Occasional Contributor III

This is excellent. I was coding something very similar.  Just adding to the thread... I also have range domains in my data so had to ignore these by just looking at the coded domains.

 

coded_domains = {fld.name:{str(entry.code):entry.name for entry in fld.domain.codedValues} for fld in lyr.properties.fields if fld.domain and fld.domain.type == "codedValue"}

 

~ learn.finaldraftmapping.com
0 Kudos