-
Notifications
You must be signed in to change notification settings - Fork 3
RootSystemTracker support and fix loader/writer round-trip PR #34
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| """ XML SmartRoot / RootNav reader and writer | ||
| """ XML SmartRoot / RootNav / RootSystemTracker reader and writer | ||
|
|
||
| TODO: | ||
| * Manage metadata | ||
|
|
@@ -18,7 +18,7 @@ | |
|
|
||
| """ | ||
| ############################################################################## | ||
| # XML SmartRoot / RootNav reader and writer | ||
| # XML SmartRoot / RootNav / RootSystemTracker reader and writer | ||
| ############################################################################## | ||
|
|
||
| from ast import literal_eval | ||
|
|
@@ -48,7 +48,18 @@ def parse(self, filename, debug=False): | |
| root = doc.getroot() | ||
| # recursive call of the functions to add neww plants/root axis to the MTG | ||
| self.dispatch(root) | ||
|
|
||
|
|
||
| # if some functions are defined in the MTG properties but not in metadata, add them | ||
| graph = self._g | ||
| if graph.graph_properties().get('metadata', {}).get('functions') is None: | ||
| graph.graph_properties()['metadata']['functions'] = [] | ||
| if graph.properties().get('time'): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. props is a dict, isn't it? Just do if 'time' in props: |
||
| graph.graph_properties()['metadata']['functions'].append('time') | ||
| if graph.properties().get('time_hours'): | ||
| graph.graph_properties()['metadata']['functions'].append('time_hours') | ||
| if graph.properties().get('diameter'): | ||
| graph.graph_properties()['metadata']['functions'].append('diameter') | ||
|
|
||
| g = fat_mtg(self._g) | ||
|
|
||
| # Add metadata as property of the graph | ||
|
|
@@ -87,6 +98,7 @@ def metadata(self, elts, **properties): | |
| meta = self._metadata = dict() | ||
| gprop = self._g.graph_properties() | ||
| #print([elt.tag for elt in elts]) | ||
| pixel_size = None | ||
| for elt in elts: | ||
| elt_tag = elt.tag | ||
| #print(elt_tag) | ||
|
|
@@ -97,12 +109,20 @@ def metadata(self, elts, **properties): | |
| elif elt_tag in ['user','file-key','software','unit']: | ||
| meta[elt_tag] = elt.text | ||
| elif elt_tag in ["property-definitions","time-sequence","image",'private']: | ||
| #print(elt_tag) | ||
| self.dispatch(elt) | ||
| elif elt_tag == "observation-hours": | ||
| elt_text = elt.text | ||
| meta[elt_tag] = [literal_eval(v) for v in elt_text.split(',') if v] | ||
| elif elt_tag in ['size', 'pixel_size']: | ||
| pixel_size = float(elt.text) # RootSystemTracker use size for pixel_size before image element D: | ||
| elif elt_tag=='mtg_graph_properties': | ||
| gprop.update(read_xml_tree(elt)) | ||
| else: | ||
| meta[elt_tag] = read_xml_tree(elt) | ||
|
|
||
| if pixel_size: | ||
| meta['resolution'] = meta.get('image',{}) | ||
| meta['image']['resolution'] = pixel_size | ||
|
|
||
| gprop['metadata'] = meta | ||
|
|
||
|
|
@@ -134,7 +154,7 @@ def function_definition(self, elts, **properties): | |
| label = prop.pop('label') | ||
| if label: | ||
| self._propdef[label]=prop | ||
|
|
||
| def time_sequence(self, elts, **properties): | ||
| """ A plant with parameters and a recursive structure. | ||
|
|
||
|
|
@@ -218,6 +238,7 @@ def polyline(self, elts, **properties): | |
| self._polyline = [] # will store all points in `elts` | ||
| self._time = [] | ||
| self._time_hours = [] | ||
| # self._diameter = [] | ||
| for elt in elts: | ||
| self.dispatch(elt) | ||
|
|
||
|
|
@@ -230,13 +251,16 @@ def polyline(self, elts, **properties): | |
| if self._time_hours : | ||
| self._node.time_hours = self._time_hours | ||
| self._time_hours = None | ||
|
|
||
| # if self._diameter : | ||
| # self._node.diameter = self._diameter | ||
| # self._diameter = None | ||
|
|
||
| def point(self, elts, **properties): | ||
| poly = self._polyline | ||
| point = [] | ||
| times = self._time | ||
| times_hours = self._time_hours | ||
| # diameters = self._diameter | ||
| if properties: | ||
| if 'x' in properties or 'coord_x' in properties: | ||
| coords = ['x', 'y', 'z'] | ||
|
|
@@ -250,13 +274,14 @@ def point(self, elts, **properties): | |
| coords = ['th', 'coord_th'] | ||
| time_hours = [float(properties[c]) for c in coords if c in properties] | ||
| times_hours.append(time_hours[0]) | ||
| # if 'diameter' in properties: | ||
| # diameter = float(properties['diameter']) | ||
| # diameters.append(diameter) | ||
| else: | ||
| point = [float(elt.text) for elt in elts] | ||
| poly.append(point) | ||
|
|
||
| #print('point', point) | ||
|
|
||
|
|
||
| #print('point', point) | ||
|
|
||
| def functions(self, elts, **properties): | ||
| """ A root axis with geometry, functions, properties. | ||
|
|
@@ -412,18 +437,26 @@ def mtg(self): | |
| def metadata(self): | ||
| g = self._g | ||
| self.xml_meta = xml.SubElement(self.xml_root,'metadata') | ||
|
|
||
| gmetadata = metadata.set_metadata(g) | ||
|
|
||
| for tag in metadata.flat_metadata: | ||
| self.SubElement(self.xml_meta, tag=tag, text=str(gmetadata[tag])) | ||
|
|
||
| # image metadata | ||
| self.observation_hours(gmetadata) | ||
| self.image(gmetadata) | ||
| self.property_definitions(gmetadata) | ||
| # print('TODO: time-sequence') | ||
|
|
||
| def observation_hours(self,metadata): | ||
| """ dump observation-hours element of metadata """ | ||
| obs = metadata.get('observation-hours') # List of observation hours | ||
| if obs is None: return | ||
|
|
||
| obs_elt = self.SubElement(self.xml_meta, 'observation-hours') | ||
| txt = ','.join(str(hour) for hour in obs) | ||
| obs_elt.text = txt | ||
|
|
||
| def image(self,metadata): | ||
| """ dump image element of metadata """ | ||
| image = metadata.get('image') | ||
|
|
@@ -485,8 +518,6 @@ def scene(self): | |
|
|
||
| # self.process_vertex(vid) | ||
|
|
||
|
|
||
|
|
||
| def plant(self, vid): | ||
| g = self._g | ||
|
|
||
|
|
@@ -512,16 +543,17 @@ def root(self, xml_parent, mtg_vid): | |
| self.xml_nodes[vid] = axis = self.SubElement(xml_parent, 'root') | ||
|
|
||
| # set xml attributes | ||
| props = g[vid] | ||
| props = g[vid] | ||
| axis.attrib['id'] = str(props.pop('id', vid)) | ||
| axis.attrib['label'] = str(props.pop('label', g.label(vid))) | ||
| if 'po:accession' in props: | ||
| axis.attrib['po:accession'] = str(props.pop('po:accession')) | ||
|
|
||
| # set xml axis element | ||
| self.properties(vid, axis) | ||
| ##self.functions(axis,**props) | ||
| self.geometry(axis,**props) | ||
| self.functions(axis,**props) | ||
| self.properties(vid, axis) | ||
|
|
||
|
|
||
| # process children root axis | ||
| # -------------------------- | ||
|
|
@@ -583,21 +615,19 @@ def functions(self, axis, **props): | |
| for tag in pname: | ||
| if tag in props: | ||
| if functions_elt is None: | ||
| functions_elt = self.SubElement(xml_elt, 'functions') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good. |
||
| functions_elt = self.SubElement(axis, 'functions') | ||
| function_elt = self.SubElement(functions_elt, 'function') | ||
| function_elt.attrib['domain'] = 'polyline' | ||
| function_elt.attrib['name'] = tag | ||
| function_elt.attrib['name'] = tag | ||
|
|
||
| for sample in attrib[tag]: | ||
| for sample in props[tag]: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep. |
||
| sample_elt = self.SubElement(function_elt, 'sample') | ||
| if isinstance(sample, (tuple, list)) and len(sample) == 2: | ||
| sample_elt.attrib['position'] = str(sample[0]) | ||
| sample_elt.attrib['value'] = str(sample[1]) | ||
| else: | ||
| sample_elt.attrib['value'] = str(sample) | ||
|
|
||
|
|
||
|
|
||
| ########################################################################## | ||
| # Wrapper functions for OpenAlea usage. | ||
|
|
||
|
|
@@ -621,4 +651,4 @@ def mtg2rsml(g, rsml_file): | |
| with open(rsml_file, 'wb') as f: # F. Bauget 2022-04-11: with python 3 xml.tostring(self.xml_root, encoding='UTF-8') gives bytes so I open in binary mode | ||
| f.write(s) | ||
| else: | ||
| rsml_file.write(s) | ||
| rsml_file.write(s) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,14 +25,13 @@ | |
| function also fill missing items, folowing the specified behavior describe in | ||
| the function documentation. | ||
| """ | ||
| import xml.etree.ElementTree as xml | ||
|
|
||
|
|
||
| # ordered list of metadata attribute name | ||
| flat_metadata = ['version','unit','resolution','software','user', | ||
| 'last-modified','file-key'] | ||
| metadata_names = flat_metadata + ['image', 'property-definitions', | ||
| 'function-definitions', 'time-sequence', | ||
| 'observation-hours', | ||
| 'private'] | ||
|
|
||
| # default values | ||
|
|
@@ -91,9 +90,17 @@ def set_metadata(g): | |
| from os.path import getctime | ||
| creation = getctime(image['name']) | ||
| image['captured'] = datetime.fromtimestamp(creation).isoformat() | ||
| except KeyError: # not defined | ||
| pass | ||
| except OSError: # no such file | ||
| pass | ||
|
|
||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not... |
||
| if 'observation-hours' in metadata: | ||
| # table of observation times | ||
| obs = metadata['observation-hours'] | ||
| if isinstance(obs, str): | ||
| import ast | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. import at the begining of the file with ... imports |
||
| metadata['observation-hours'] = list(ast.literal_eval(obs)) # convert string to list | ||
|
|
||
| if metadata['file-key']!=default['file-key']: | ||
| import uuid | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get just ones graph_properties rather than calling each time.
Code will be simpler, nicer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or directly for metadata