Git Product home page Git Product logo

Comments (4)

jdbcode avatar jdbcode commented on May 5, 2024

The proposed function above (that renders the entire tree) won't work. It's slow to load a single Landsat 9 TOA image's metadata and, at least in free Colab, won't even render the tree with two images in the collection. Test these data with above function - collection limit set at 2:

data = ee.ImageCollection("LANDSAT/LC09/C02/T1_TOA").limit(2).getInfo()

tree = Tree(animation=0)
tree.add_node(create_tree(data))
tree

from earthengine-jupyter.

jdbcode avatar jdbcode commented on May 5, 2024

Maybe in the current implementation the JSON data can be stored as an added attribute, like add a json parameter to the Node class ~e.g.:

class CustomNode(Node):
    def __init__(self, name=None, children=None, json=None):
        super().__init__(name=name, children=children)
        self.json = json

Instead of storing the JSON data as the name attribute, store it in the new json attribute and use an empty string or <em>Loading</em> as the name attribute. When a person opens a node, fetch the JSON and update the name.

from earthengine-jupyter.

jdbcode avatar jdbcode commented on May 5, 2024

Here is a potential fix. It adds a Node subclass with an ee_data attribute for storing the JSON data (MyNode is not a good name, need to change).

class MyNode(ipytree.Node):
    def __init__(self, *args, ee_data=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.ee_data = ee_data

The StructureTree class is modified so that the name of "JSON" nodes is Loading and JSON data is stored in the ee_data attribute.

class StructureTree(ipytree.Tree):

    JSON_PREFIX = 'JSON: '

    def __init__(self, data, **kwargs):
        self.data = data
        super().__init__(StructureTree.__ipytreeify(data))

    @staticmethod
    def __ipytreeify(data) -> tuple:
        """Return a sequence of nodes"""

        def is_json(in_str):
            '''Determines if a string is JSON.'''
            return bool(in_str) and in_str.startswith(StructureTree.JSON_PREFIX)

        def inline_style(x, color='#af00db'):
            '''Wrap a string with inline HTML styling.'''
            return f'<B><SPAN style="color:{color}">{x}</SPAN></B>'

        def handle_node_open(change):
            if change['new']:
                nodes_unpacked = []
                for node in change['owner'].nodes:
                    # If there no subnodes, try to populate the subnodes.
                    if len(node.nodes) == 0:
                        if is_json(node.ee_data):
                          unpacked_json = json.loads(node.ee_data[len(StructureTree.JSON_PREFIX):])
                          if isinstance(unpacked_json, list):
                              nodes_unpacked = StructureTree.__ipytreeify(unpacked_json)
                          elif isinstance(unpacked_json, dict):
                              nodes_unpacked = StructureTree.__ipytreeify(unpacked_json)
                          else:
                              raise
                        else: # ~is_json(node.name)
                          nodes_unpacked.append(node)
                        change['owner'].nodes = nodes_unpacked

        if isinstance(data, list):
            node_list = []
            for count, el in enumerate(data):
                if isinstance(el, list):
                    subnode = MyNode(
                        name=f'{inline_style("List")} ({len(el)} elements)',
                        nodes=[MyNode('<em>Loading</em>', ee_data=f'{StructureTree.JSON_PREFIX}{json.dumps(el)}', show_icon=False)],
                        opened=False,
                        show_icon=False)
                    subnode.observe(handle_node_open, names='opened')
                elif isinstance(el, dict):
                    subnode = MyNode(
                        name=f'{inline_style("Object")} ({len(el)} elements)',
                        nodes=[MyNode('<em>Loading</em>', ee_data=f'{StructureTree.JSON_PREFIX}{json.dumps(el)}', show_icon=False)],
                        opened=False,
                        show_icon=False)
                    subnode.observe(handle_node_open, names='opened')
                else:
                    subnode = MyNode(f'{el}', show_icon=False)
                node_list.append(subnode)
            return node_list
        elif isinstance(data, dict):
            node_list = []
            for key, value in data.items():
                if isinstance(value, list):
                    subnode = MyNode(
                        name=f'{inline_style(key)}: List ({len(value)} elements)',
                        nodes=[MyNode('<em>Loading</em>', ee_data=f'{StructureTree.JSON_PREFIX}{json.dumps(value)}', show_icon=False)],
                        opened=False,
                        show_icon=False)
                    subnode.observe(handle_node_open, names='opened')
                elif isinstance(value, dict):
                    subnode = MyNode(
                        name=f'{inline_style(key)}: Object ({len(value)} elements)',
                        nodes=[MyNode('<em>Loading</em>', ee_data=f'{StructureTree.JSON_PREFIX}{json.dumps(value)}', show_icon=False)],
                        opened=False,
                        show_icon=False)
                    subnode.observe(handle_node_open, names='opened')
                else:
                    subnode = MyNode(f'{inline_style(key)}: {value}', show_icon=False)
                node_list.append(subnode)
            return node_list
        else:
            return (data, )

Since ee_data default is None, is_json function needed to add a check for None so that the startswith string method does not bonk. I tested it with the same Landsat data from above and it works great. It also works for the map inspector demo in the 01_ipyleaflet.ipynb (some other bug seems to crop up when implemented in the map panel - also happens with current implementation, I'll file a separate issue).

from earthengine-jupyter.

jdbcode avatar jdbcode commented on May 5, 2024

Here is a refactored version of StructureTree from previous comment (still uses badly named MyNode class).

class MyNode(ipytree.Node):
    def __init__(self, *args, ee_data=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.ee_data = ee_data

class StructureTree(ipytree.Tree):
    JSON_PREFIX = 'JSON: '

    def __init__(self, data, **kwargs):
        self.data = data
        super().__init__(StructureTree.__ipytreeify(data))

    @staticmethod
    def __ipytreeify(data) -> tuple:
        """Return a sequence of nodes"""

        def is_json(in_str):
            '''Determines if a string is JSON.'''
            return bool(in_str) and in_str.startswith(StructureTree.JSON_PREFIX)

        def inline_style(x, color='#af00db'):
            '''Wrap a string with inline HTML styling.'''
            return f'<B><SPAN style="color:{color}">{x}</SPAN></B>'

        def handle_node_open(change):
            if change['new']:
                nodes_unpacked = []
                for node in change['owner'].nodes:
                    if not node.nodes:
                        if is_json(node.ee_data):
                            unpacked_json = json.loads(node.ee_data[len(
                                StructureTree.JSON_PREFIX):])
                            nodes_unpacked = StructureTree.__ipytreeify(unpacked_json)
                        else:
                            nodes_unpacked.append(node)
                        change['owner'].nodes = nodes_unpacked

        NODE_PARAMS = {
            'show_icon': False,
            'opened': False,
            'observe': handle_node_open,
        }

        def create_loading_node(data):
            return MyNode('<em>Loading</em>',
                          ee_data=f'{StructureTree.JSON_PREFIX}{json.dumps(data)}',
                          **NODE_PARAMS)

        def create_node_name(label, modifer, data):
            return f'{inline_style(label)}{modifer} ({len(data)} elements)'

        node_list = []
        if isinstance(data, list):
            for count, el in enumerate(data):
                if isinstance(el, (list, dict)):
                    node_type = 'List' if isinstance(el, list) else 'Object'
                    subnode = MyNode(
                        name=create_node_name(node_type, '', el),
                        nodes=[create_loading_node(el)],
                        **NODE_PARAMS)
                    subnode.observe(handle_node_open, names='opened')
                else:
                    subnode = MyNode(f'{el}', **NODE_PARAMS)
                node_list.append(subnode)
        elif isinstance(data, dict):
            for key, value in data.items():
                if isinstance(value, (list, dict)):
                    node_type = ': List' if isinstance(value, list) else ': Object'
                    subnode = MyNode(
                        name=create_node_name(key, node_type, value),
                        nodes=[create_loading_node(value)],
                        **NODE_PARAMS)
                    subnode.observe(handle_node_open, names='opened')
                else:
                    subnode = MyNode(f'{inline_style(key)}: {value}', **NODE_PARAMS)
                node_list.append(subnode)
        else:
            node_list.append(MyNode(str(data), show_icon=False))

        return tuple(node_list)

from earthengine-jupyter.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.