def import_mtgfile(filename): """ parameters: ----------- filename : names of mtg return: ------- a function which import mtg corresponding to the mtg names """ def name(f): "return base name without extension" return f.basename().splitext()[0] filenames = filename files = shared_data(openalea.strawberry).glob('*.mtg') mtg_path = dict((name(f), f) for f in files) mtgfile = dict((k, f) for k, f in mtg_path.items() if k in filenames) if len(filenames) == 1: g = MTG(mtgfile[filenames[0]]) return g else: metaMTG = MTG() for i in mtgfile: metaMTG = algo.union(metaMTG, MTG(mtgfile[i])) return metaMTG
def debug_mtg_build(): g = MTG() vidP = g.add_component(g.root, label='P', edge_type='/') vidL = g.add_component(vidP, label='L', edge_type='/') vidb = g.add_component(vidL, label='base', edge_type='/') vidt = g.add_child(vidb, label='top', edge_type='<') vide = g.insert_parent(vidt, edge_type='<', label='elt1')
def build_mtg(self): """ Build an MTG structure from data. The MTG is composed of 3 scales: Plant, Crown, Phytomer """ self._axis_vid = [] self.g = MTG() g = self.g # build 2 elements: P plante and C crown #self._vid = plant_id = g.add_component(g.root, label='Plant') # add crown #self._vid = g.add_component(self._vid, label='Crown') self._order = 0 self._scale = 3 self._vid = None #self._axis_vid.append(self._vid) nb_lines = len(self.content) - self.prop_no for i in range(nb_lines): #print (self._vid) self.read_line() self.g = fat_mtg(g)
def convertToMyMTG(g): from openalea.mtg import MTG def addProperties(mtg, vid, px, py, pz, radius): mtg.property('position')[vid] = Vector3(px, py, pz) mtg.property('radius')[vid] = radius mtg = MTG() mtg.add_property('position') mtg.add_property('radius') plantroot = mtg.root branchroot = mtg.add_component(plantroot, label='B') noderoot = mtg.add_component(branchroot, label='N') rdic = g.property('radius') for k, r in rdic.iteritems(): parentid = g.parent(k) px = g.property('XX')[k] py = g.property('YY')[k] pz = g.property('ZZ')[k] if parentid == None: addProperties(mtg, k, px, py, pz, r) else: label = g.label(k) if label == 'N': vid = mtg.add_child(parentid, edge_type='<', label='N') else: vid = mtg.add_child(parentid, edge_type='+', label='B') addProperties(mtg, vid, px, py, pz, r) return mtg
def simple_tree(): """ create a simple tree """ from openalea.mtg import MTG g = MTG() p = g.add_component(g.root, edge_type='/') # plant # primary axe a1 = g.add_component(p, edge_type='/') # the axe s11 = g.add_component(a1, position=(1, 1, 0), edge_type='/') # segment 1 s12 = g.add_child(s11, position=(1, 2, 0), edge_type='<') # segment 2 s13 = g.add_child(s12, position=(1, 3, 0), edge_type='<') # segment 3 s14 = g.add_child(s13, position=(1, 4, 0), edge_type='<') # segment 4 # 1st lateral axe a2 = g.add_child(a1, edge_type='/') # the axe s21 = g.add_component(a2, position=(0, 2, 0), edge_type='/') # segment 1 s21 = g.add_child(s12, s21, edge_type='+') # attach on parent segment s22 = g.add_child(s21, position=(0, 3, 0), edge_type='<') # segment 2 # 2nd lateral axe a3 = g.add_child(a1, edge_type='/') # the axe s31 = g.add_component(a3, position=(2, 3, 0), edge_type='/') # segment 1 s31 = g.add_child(s13, s31, edge_type='+') # attach on parent segment return g
def test_add_metamer(): g = MTG() add_plant(g) vid_plant, vid_axe, metamers = find_metamers(g) assert len(metamers) == 1 vid = add_vegetative_metamer(g) vid_plant, vid_axe, metamers = find_metamers(g) metamer = g.node(vid) assert len(metamers) == 2 assert metamer.label == 'metamer1'
def test_insert_elements(): g = MTG() labels = g.property('label') add_plant(g) elts = [{'label': 'elt1'}, {'label': 'elt2'}] collar = find_label('collar', g)[0] insert_elements(g, collar, elts) elt1 = find_label('elt1', g)[0] assert labels[g.parent(elt1)] == 'baseElement' assert labels[g.children(elt1)[0]] == 'elt2'
def initialize_mtg(root, nodelabel='N'): from openalea.mtg import MTG mtg = MTG() plantroot = mtg.root branchroot = mtg.add_component(plantroot, label='P') noderoot = mtg.add_component(branchroot, label=nodelabel) mtg.property('position')[noderoot] = root mtg.property('radius')[noderoot] = None assert len(mtg.property('position')) == 1 return mtg
def import_mtgfile(filename): """Import a MTG file from genotype name, in sharedata repo :param filename: genotype = name of the file :type filename: string :return: a MTG loaded from the file :rtype: MTG """ filenames = filename files = shared_data(openalea.strawberry).glob('*.mtg') mtg_path = dict((name(f), f) for f in files) mtgfile = dict((k, f) for k, f in mtg_path.items() if k in filenames) if len(filenames) == 1: g = MTG(mtgfile[filenames[0]]) return g else: metaMTG = MTG() for i in mtgfile: metaMTG = algo.union(metaMTG, MTG(mtgfile[i])) return metaMTG
def test_add_axe(): g = MTG() labels = g.property('label') p1 = add_plant(g) p2 = add_plant(g) vid_axe = add_axe(g, 'T0') assert g.complex(vid_axe) == p1 assert labels[g.parent(vid_axe)] == 'MS' vid_axe = add_axe(g, 'T1.3', plant_number=2) assert g.complex(vid_axe) == p2 assert labels[g.parent(vid_axe)] == 'T1' vid_metamer0 = g.component_roots_at_scale(vid_axe, 3)[0] assert labels[g.parent(vid_metamer0)] == "metamer3"
def spanning_mtg(graph): """ Extract an MTG from the GroIMP graph. Parameters ---------- - graph is a RootedGraph created from the GroIMP Graph TODO: - compress vertices to only usefull vertices (geometry) - compress edges to spanning mtg """ # Manage a mapping between the graph and the mtg graph2mtg = {} g = graph edge_type = g.edge_property('edge_type') mtg = MTG() mtg.root = graph.root # Check if the graph contains decomposition (/) edges if not is_multiscale(graph): pass # Compute the scale from each vertex. # Select one decomposition path if there are several in the GroIMP graph _scales = scales(g) # Set the internal scale information to the MTG mtg._scale = _scales # Set the edge_type for each vertex (<, +) _edge_type = _build_edge_type(g, mtg) # Compute the tree information at all scales _children_and_parent(g, mtg) # Compute the complex (upscale) and components (downscale) for each vertex _complex_and_components(g, mtg) print "scales :", mtg._scale # Extract all the vertex properties. _vertex_properties(g, mtg) # Compute missing links to have constant time access (O(1)) to neighbourhood fat_mtg(mtg) print "scales :", mtg._scale return mtg
def simple_tree(): """ create a simple tree """ from openalea.mtg import MTG g = MTG() p = g.add_component(g.root, edge_type='/') # plant # primary axe geom = [[0,0,0],[0,1,0],[0,3,0]] a1 = g.add_component(p, edge_type='/', geometry=geom) # primary axe # secondary axe geom = [[0,1,0],[1,1,0]] a2 = g.add_child(a1, edge_type='+', geometry=geom) # 2ndary axe return g
def build_stand(self): g = MTG() plants = self.axeT() sample = [int(p) for p in plantSample(self.pars)] for i, plant in plants.groupby('plant'): plant_properties = {'position': self.positions[i - 1], 'azimuth': self.plant_azimuths[i - 1], 'refplant_id': sample[i - 1]} ms = plant.loc[plant['axe'] == 'MS', :].to_dict('list') ms_properties = {'HS_final': float(ms['HS_final'][0]), 'nff': int(ms['nf'][0]), 'hasEar': bool(int(ms['hasEar'][0])), 'azimuth': float(ms['azTb'][0])} add_plant(g, i, plant_properties=plant_properties, axis_properties=ms_properties) return g
def test_add_plant(): g = MTG() vid = add_plant(g) plant = g.node(vid) assert plant.label == 'plant1' vid = add_plant(g) plant = g.node(vid) assert plant.label == 'plant2' vid = add_plant(g, 5) plant = g.node(vid) assert plant.label == 'plant5' vid = add_plant(g) plant = g.node(vid) assert plant.label == 'plant6' vid = add_plant(g, 1) plant = g.node(vid) assert plant.label == 'plant1' assert len(find_plants(g)) == 4
def parse(self, filename, debug=False): self.debug = debug self.trash = [] self._g = MTG() # Current proxy node for managing properties self._node = None doc = xml.parse(filename) root = doc.getroot() # recursive call of the functions to add neww plants/root axis to the MTG self.dispatch(root) g = fat_mtg(self._g) # Add metadata as property of the graph #g.graph_property() return g
def tpg2mtg(graph, properties=['index'], root_ids=None, mtg=None, binary_sorter=None): """ Args: graph:(TPG) - a tempora property graph, properties:(list) - list of properties to export in MTG root_ids:(list) - list of root ids (@t0) to build the MTG """ if root_ids is None: root_ids = [ i for i in graph.vertices() if len(graph.parents(i)) == 0 and len(graph.children(i)) > 0 ] from openalea.mtg import MTG if mtg is None: mtg = MTG() mtg.add_property('tpg_cid') for p in properties: mtg.add_property(p) meristem_id = mtg.add_component(mtg.root, label='M') def translate_property(mtg, graph, mcid, tcid): mtg.property('tpg_cid')[mcid] = tcid for p in properties: try: mtg.property(p)[mcid] = graph.vertex_property(p)[tcid] except: continue def iterable(obj): try: iter(obj) return True except TypeError, te: return False
def mtg_tree(height=2, crown_radius=1, n_leaves=500, leaf_area=0.1, inner=True): leaves = random_leaves(n_leaves=n_leaves, leaf_area=leaf_area, crown_radius=crown_radius, crown_center=(0, 0, height), inner=inner) g = MTG() vid = g.add_component(g.root, label='plant', edge_type='/') vid = g.add_child(vid, edge_type='<', label='trunk', diameter=0.1, length=2) for leaf in leaves: g.add_child(vid, edge_type='+', label='leaf', size=0.1, geometry=leaf) return g
def on_change_get_files(widget, event, data): # load mtgs misc.all_mtg = MTG() for file in data: g = read_mtg_file(file_paths[file]) misc.all_mtg = union(misc.all_mtg, g) # update table if misc.all_mtg: df = get_table_mtg(misc.all_mtg) # TODO: update_grid(df, tableMTG) else: update_grid(pd.DataFrame(), tableMTG) # update genotype selections update_selection_items() # update file description print_files_description()
def test_extract_at_plant_scale(): files = shared_data(openalea.strawberry).glob('*.mtg') mtg_path = dict((name(f), f) for f in files) mtg = MTG() for k, genotype in enumerate(mtg_path): if (genotype=="Sicile") or (genotype=="Nils") or (genotype=='origine_stolon_gariguetteDV_6novembre2018') \ or (genotype=='friendlyfruit_varieties'): pass else: mtg = union(mtg, read_mtg_file(mtg_path[genotype])) genotypes = mtg.property('Genotype') for geno in set(genotypes.values()): vids = [ vid for vid in mtg.vertices(scale=1) if genotypes.get(vid) == geno ] df = extract_at_plant_scale(mtg, vids) assert not df.empty assert set(df['Genotype']) == {geno}
def __init__(self, graph=None): GraphAdapterBase.__init__(self) Observed.__init__(self) self.set_graph(MTG() if graph is None else graph) self.mapping = {}
def mtg_nenuphar(area=1): g = MTG() vid = g.add_component(g.root, label='plant', edge_type='/') geom = pgl.Disc(numpy.sqrt(area / 0.9 / numpy.pi)) g.add_child(vid, edge_type='<', label='trunk', area=area, geometry=geom) return g
def new_mtg_factory(parameters, metamer_factory=adel_metamer, leaf_sectors=1, leaves=None, stand=None, axis_dynamics=None, add_elongation=False, topology=('plant', 'axe_id', 'numphy'), split=False, aborting_tiller_reduction=1.0, leaf_db=None): """A 'clone' of mtg_factory that uses mtg_edition functions """ if leaf_db is not None: raise AdelDeprecationError( 'leaf_db argument is deprecated, use leaves argument instead') if leaves is None: dynamic_leaf_db = {0: False} leaves = {0: None} else: dynamic_leaf_db = {k: leaves[k].dynamic for k in leaves} g = MTG() # buffers # for detection of newplant/newaxe prev_plant = 0 prev_axe = -1 dp = parameters nrow = len(dp['plant']) species = 0 for i in range(nrow): plant, num_metamer = [int(convert(dp.get(x)[i], undef=None)) for x in [topology[e] for e in [0, 2]]] axe = dp.get(topology[1])[i] args = properties_from_dict(dp, i, exclude=topology) # Add plant if new if plant != prev_plant: if axe != 'MS': raise ValueError('Main stem is expected first when a new plant ' 'is declared') position, azimuth = (0, 0, 0), 0 if stand and len(stand) >= plant: position, azimuth = stand[plant - 1] plant_properties = {'position': position, 'azimuth': azimuth, 'refplant_id': args.get('refplant_id'), 'species': species} timetable = None if axis_dynamics: timetable = axis_dynamics[str(plant)][str(axe)] mainstem_properties = dict(timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) add_plant(g, plant_number=plant, plant_properties=plant_properties, axis_properties=mainstem_properties) prev_plant = plant # Add axis if axe != prev_axe and axe != 'MS': timetable = None if axis_dynamics: timetable = axis_dynamics[str(plant)][str(axe)] axe_properties = dict(timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) add_axe(g, axe, plant, axis_properties=axe_properties) prev_axe = axe # Add metamer assert num_metamer > 0 # args are added to metamers only if metamer_factory is none, # otherwise compute metamer components components = [] if metamer_factory: xysr_key = None if leaves[species] is not None and 'LcType' in args and 'LcIndex' in args: lctype = int(args['LcType']) lcindex = int(args['LcIndex']) if lctype != -999 and lcindex != -999: age = None if dynamic_leaf_db[species]: age = float(args[ 'rph']) - 0.3 # age_db = HS - rank + 1 = ph - 1.3 - rank +1 = rph - .3 if age != 'NA': age = max(0, int(float(age))) xysr_key = leaves[species].get_leaf_key(lctype, lcindex, age) elongation = None if add_elongation: startleaf = -.4 endleaf = 1.6 stemleaf = 1.2 startE = endleaf endE = startE + (endleaf - startleaf) / stemleaf endBlade = endleaf if args['Gl'] > 0: endBlade = args['Ll'] / args['Gl'] * (endleaf - startleaf) elongation = {'startleaf': startleaf, 'endBlade': endBlade, 'endleaf': endleaf, 'endE': endE} if not 'ntop' in args: args.update({'ntop': None}) if not 'Gd' in args: args.update({'Gd': 0.19}) args.update({'split': split}) if args.get('HS_final') < args.get('nff'): for what in ( 'Ll', 'Lv', 'Lr', 'Lsen', 'L_shape', 'Lw_shape', 'Gl', 'Gv', 'Gsen', 'Gd', 'El', 'Ev', 'Esen', 'Ed'): args.update( {what: args.get(what) * aborting_tiller_reduction}) components = metamer_factory(Lsect=leaf_sectors, shape_key=xysr_key, elongation=elongation, leaves=leaves[species], **args) args = {'L_shape': args.get('L_shape')} # metamer_properties = args internode, sheath, blade = None, None, None elts = {k: [] for k in ('internode', 'sheath', 'blade')} if len(components) > 0: internode, sheath, blade = components internode.pop('label') sheath.pop('label') blade.pop('label') elts['internode'] = internode.pop('elements') elts['sheath'] = sheath.pop('elements') elts['blade'] = blade.pop('elements') vid_metamer = add_vegetative_metamer(g, plant, axe, metamer_properties=metamer_properties, internode_properties=internode, sheath_properties=sheath, blade_properties=blade) for organ in g.components(vid_metamer): label = g.property('label')[organ] if label in elts and len(elts[label]) > 0: insert_elements(g, organ, elts[label]) return fat_mtg(g)
def getMTG(name): return MTG(get_filename(name))
def mtg_factory(parameters, metamer_factory=adel_metamer, leaf_sectors=1, leaves=None, stand=None, axis_dynamics=None, add_elongation=False, topology=['plant', 'axe_id', 'numphy'], split=False, aborting_tiller_reduction=1.0, leaf_db=None): """ Construct a MTG from a dictionary of parameters. The dictionary contains the parameters of all metamers in the stand (topology + properties). metamer_factory is a function that build metamer properties and metamer elements from parameters dict. leaf_sectors is an integer giving the number of LeafElements per Leaf blade leaves is a {species:adel.geometric_elements.Leaves} dict stand is a list of tuple (xy_position_tuple, azimuth) of plant positions axis_dynamics is a 3 levels dict describing axis dynamic. 1st key level is plant number, 2nd key level is axis number, and third ky level are labels of values (n, tip, ssi, disp) topology is the list of key names used in parameters dict for plant number, axe number and metamer number aborting_tiller_reduction is a scaling factor applied to reduce all dimensions of organs of tillers that will abort Axe number 0 is compulsory """ if leaf_db is not None: raise AdelDeprecationError( 'leaf_db argument is deprecated, use leaves argument instead') if leaves is None: dynamic_leaf_db = {0: False} leaves = {0: None} else: dynamic_leaf_db = {k: leaves[k].dynamic for k in leaves} g = MTG() # buffers # for detection of newplant/newaxe prev_plant = 0 prev_axe = -1 # current vid vid_plant = -1 vid_axe = -1 vid_metamer = -1 vid_node = -1 vid_elt = -1 # vid of top of stem nodes and elements vid_topstem_node = -1 vid_topstem_element = -1 # vid of plant main stem (axe0) vid_main_stem = -1 # buffer for the vid of main stem anchor points for the first metamer, node and element of tillers metamers = [] nodes = [] elts = [] dp = parameters nrow = len(dp['plant']) for i in range(nrow): plant, num_metamer = [ int(convert(dp.get(x)[i], undef=None)) for x in [topology[e] for e in [0, 2]] ] axe = dp.get(topology[1])[i] mspos = int(convert(dp.get('ms_insertion')[i], undef=None)) args = properties_from_dict(dp, i, exclude=topology) # Add plant if new if plant != prev_plant: label = 'plant' + str(plant) position = (0, 0, 0) azimuth = 0 species = 0 if 'species' in args: species = args['species'] if stand and len(stand) >= plant: position, azimuth = stand[plant - 1] vid_plant = g.add_component(g.root, label=label, edge_type='/', position=position, azimuth=azimuth, refplant_id=args.get('refplant_id'), species=species) # reset buffers prev_axe = -1 vid_axe = -1 vid_metamer = -1 vid_node = -1 vid_elt = -1 vid_topstem_node = -1 vid_topstem_element = -1 vid_main_stem = -1 metamers = [] nodes = [] elts = [] # Add axis if axe != prev_axe: label = ''.join(axe.split('.')) timetable = None if axis_dynamics: timetable = axis_dynamics[str(plant)][str(axe)] if axe == 'MS': vid_axe = g.add_component(vid_plant, edge_type='/', label=label, timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) vid_main_stem = vid_axe else: vid_axe = g.add_child(vid_main_stem, edge_type='+', label=label, timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) # Add metamer assert num_metamer > 0 # args are added to metamers only if metamer_factory is none, otherwise compute metamer components components = [] if metamer_factory: xysr_key = None if leaves[ species] is not None and 'LcType' in args and 'LcIndex' in args: lctype = int(args['LcType']) lcindex = int(args['LcIndex']) if lctype != -999 and lcindex != -999: age = None if dynamic_leaf_db[species]: age = float( args['rph'] ) - 0.3 # age_db = HS - rank + 1 = ph - 1.3 - rank +1 = rph - .3 if age != 'NA': age = max(0, int(float(age))) xysr_key = leaves[species].get_leaf_key( lctype, lcindex, age) elongation = None if add_elongation: startleaf = -.4 endleaf = 1.6 stemleaf = 1.2 startE = endleaf endE = startE + (endleaf - startleaf) / stemleaf endBlade = endleaf if args['Gl'] > 0: endBlade = args['Ll'] / args['Gl'] * (endleaf - startleaf) elongation = { 'startleaf': startleaf, 'endBlade': endBlade, 'endleaf': endleaf, 'endE': endE } if not 'ntop' in args: args.update({'ntop': None}) if not 'Gd' in args: args.update({'Gd': 0.19}) args.update({'split': split}) if args.get('HS_final') < args.get('nff'): for what in ('Ll', 'Lv', 'Lr', 'Lsen', 'L_shape', 'Lw_shape', 'Gl', 'Gv', 'Gsen', 'Gd', 'El', 'Ev', 'Esen', 'Ed'): args.update( {what: args.get(what) * aborting_tiller_reduction}) components = metamer_factory(Lsect=leaf_sectors, shape_key=xysr_key, elongation=elongation, leaves=leaves[species], **args) args = {'L_shape': args.get('L_shape')} # label = 'metamer' + str(num_metamer) new_metamer = g.add_component(vid_axe, edge_type='/', label=label, **args) if axe == 'MS' and num_metamer == 1: vid_metamer = new_metamer elif num_metamer == 1: # add the edge with the bearing metamer on main stem vid_metamer = metamers[mspos - 1] vid_metamer = g.add_child(vid_metamer, child=new_metamer, edge_type='+') else: vid_metamer = g.add_child(vid_metamer, child=new_metamer, edge_type='<') # add metamer components, if any if len(components) > 0: # deals with first component (internode) and first element node, elements = get_component(components, 0) element = elements[0] new_node = g.add_component(vid_metamer, edge_type='/', **node) new_elt = g.add_component(new_node, edge_type='/', **element) if axe == 'MS' and num_metamer == 1: # root of main stem vid_node = new_node vid_elt = new_elt elif num_metamer == 1: # root of tiller vid_node = nodes[mspos - 1] vid_node = g.add_child(vid_node, child=new_node, edge_type='+') vid_elt = elts[mspos - 1] vid_elt = g.add_child(vid_elt, child=new_elt, edge_type='+') else: vid_node = g.add_child(vid_topstem_node, child=new_node, edge_type='<') vid_elt = g.add_child(vid_topstem_element, child=new_elt, edge_type='<') # add other elements of first component (the internode) for i in range(1, len(elements)): element = elements[i] vid_elt = g.add_child(vid_elt, edge_type='<', **element) vid_topstem_node = vid_node vid_topstem_element = vid_elt # last element of internode # add other components for i in range(1, len(components)): node, elements = get_component(components, i) if node['label'] == 'sheath': edge_type = '+' else: edge_type = '<' vid_node = g.add_child(vid_node, edge_type=edge_type, **node) element = elements[0] new_elt = g.add_component(vid_node, edge_type='/', **element) vid_elt = g.add_child(vid_elt, child=new_elt, edge_type=edge_type) for j in range(1, len(elements)): element = elements[j] vid_elt = g.add_child(vid_elt, edge_type='<', **element) # update buffers if axe == 'MS': metamers.append(vid_metamer) if len(components) > 0: nodes.append(vid_topstem_node) elts.append(vid_topstem_element) prev_plant = plant prev_axe = axe return fat_mtg(g)
def load_mtg(fn): g = MTG(fn) g = transform_date(g) g.properties()['order'] = orders(g) return g
def init_allmtg(): global all_mtg all_mtg = MTG()
def cereals(json=None, classic=False, unit='cm', seed=None, plant=None): """ Generate a 'geometric-based' MTG representation of cereals Args: json: a dict of parameters with: leaf_order : a list of int defining leaf rank leaf_polylines : [[(x, y, z, r), ..., ], ...] list of list tuple sampling leaf midribs. r is leaf width at position x, y, z along leaf midrib stem : [(x, y, z, r), ..., ] list of tuples sampling stem from its base to its end. r is the stem diameter at x,y,z position along the stem classic: (bool) should stem cylinders be classical pgl cylinders ? unit: (string) desired length unit for the output mtg seed: (int) a seed for the random number generator """ if plant is None: blade_dimensions, stem_dimensions, leaves = as_plant(json) dim = blade_dimensions.merge(stem_dimensions) dim = dim.sort_values('ntop', ascending=False) relative_azimuth = dim.leaf_azimuth.copy() relative_azimuth[1:] = numpy.diff(relative_azimuth) else: dim = plant leaves = { row['ntop']: row['leaf_shape'] for index, row in dim.iterrows() } g = MTG() vid_node = g.add_component(g.root, label='plant', edge_type='/') for i, row in dim.iterrows(): internode = { 'label': 'StemElement', 'length': row['L_internode'], 'is_green': True, 'diameter_base': row['W_internode'], 'diameter_top': row['W_internode'], 'azimuth': row['leaf_azimuth'] } vid_node = g.add_child(vid_node, edge_type='<', **internode) blade = { 'label': 'LeafElement', 'shape': leaves[row['ntop']], 'shape_mature_length': row['L_blade'], 'length': row['L_blade'], 'visible_length': row['L_blade'], 'is_green': True, 'srb': 0, 'srt': 1, 'lrolled': 0, 'd_rolled': 0, 'shape_max_width': row['W_blade'], 'stem_diameter': row['W_internode'] } vid_blade = g.add_child(vid_node, edge_type='+', **blade) g = fat_mtg(g) # Compute geometry g = mtg_interpreter(g, classic=classic) return g