# -*- python -*-
#
# Copyright 2015 INRIA - CIRAD - INRA
#
# Distributed under the Cecill-C License.
# See accompanying file LICENSE.txt or copy at
# http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
# WebSite : https://github.com/openalea-incubator/adel
#
# ==============================================================================
"""
A place to develop candidates methods for mtg.py / topological builder
"""
from openalea.adel.exception import AdelDeprecationError
# temporary import
from openalea.adel.mtg import convert, properties_from_dict
# import csv
from openalea.mtg import MTG, fat_mtg
from openalea.mtg.algo import union
import numpy
import pandas
# try:
# from openalea.mtg.traversal import *
# except:
# pass
# from openalea.mtg.io import read_lsystem_string
# from openalea.mtg.algo import union
# import numpy
# try:
# from openalea.plantgl.all import (Scene,Translation, Vector3, Geometry,
# AxisRotation, AxisRotated, Transform4, BaseOrientation,
# Shape, Material, Color3, PglTurtle, Mesh, Translated)
# except:
# Material = tuple
# Color3 = tuple
# pass
# import random
# from math import pi
[docs]
def internode_elements(l, lvis, lsen, az, inc, d, split=False):
"""returns parameters of internode elements (visible parts of the internode).
l is the length of the internode
lv is the visible length (senesced + green)
lsen is the senescent apical length
az is the azimuth angle
inc is the inclination angle
Fisrt element is for the green visible part of the internode
Second element is for senesced visible part of the internode
"""
lhide = None
lgreen = None
is_green = None
Svis = None
Sgreen = None
Ssen = None
Shide = None
try:
lhide = max(l - lvis, 0.0)
lgreen = lvis - min(lsen, lvis)
lsen = lvis - lgreen
#
Shide = numpy.pi * lhide * d
Svis = numpy.pi * lvis * d
Sgreen = numpy.pi * lgreen * d
Ssen = numpy.pi * lsen * d
#
is_green = lgreen >= lsen
except TypeError:
pass
hidden_elt = {
"label": "HiddenElement",
"length": lhide,
"area": Shide,
"is_green": True,
}
if split:
green_elt = {
"label": "StemElementg",
"length": lgreen,
"area": Sgreen,
"is_green": True,
"azimuth": az,
"inclination": inc,
}
sen_elt = {
"label": "StemElements",
"length": lsen,
"area": Ssen,
"is_green": False,
"azimuth": 0,
"inclination": 0,
}
return [hidden_elt, green_elt, sen_elt]
else:
elt = {
"label": "StemElement",
"length": lvis,
"area": Svis,
"green_length": lgreen,
"green_area": Sgreen,
"senesced_length": lsen,
"senesced_area": Ssen,
"is_green": is_green,
"azimuth": az,
"inclination": inc,
}
return [hidden_elt, elt]
[docs]
def sheath_elements(l, lvis, lsen, az, inc, d, split=False):
"""returns parameters of sheath elements (visible parts of the sheath).
l is the length of the sheath
lv is the visible length (senesced + green)
lsen is the senescent apical length
Fisrt elements is for green visible part of the sheath
Second elements is for senesced visible part of the sheath
"""
# same logic as internodes
return internode_elements(l, lvis, lsen, az, inc, d, split)
[docs]
def blade_elements(
sectors, l, lvis, lrolled, lsen, Lshape, Lwshape, shape_key, leaves, split=False
):
"""return parameters of blade elements (visible parts of the blade).
sectors is the number of sectors dividing pattern blade shape
l is the length of the blade
lvis is the visible length (senesced + green, rolled + flat)
lrolled is the visible rolled length of the blade
lsen is the senescent apical length
Lshape is length of the blade used as a pattern shape
"""
lrolled = max(0, min(lrolled, lvis))
if lrolled < 1e-6:
lrolled = 0
lhide = None
lgreen = None
lflat = None
# s (on mature shape) at which leaf becomes flat and visible
s_limvis = Lshape
# s (on mature shape) at which leaf becomes senescent
s_limsen = Lshape
# s(on mature shape) at which leaf becomes rolled
s_limrolled = Lshape
# compute partitioning of visible length
S_hide = 0
try:
lhide = max(l - lvis, 0.0)
if lhide > 0:
S_hide = leaves.blade_elt_area(
shape_key,
Lshape,
Lwshape,
(Lshape - l) / Lshape,
(Lshape - lvis) / Lshape,
)
lflat = lvis - min(lrolled, lvis)
lrolled = lvis - lflat
lgreen = lvis - min(lsen, lvis)
lsen = lvis - lgreen
s_limvis = Lshape - lvis
s_limsen = Lshape - lsen
s_limrolled = Lshape - lflat
# print(lgreen,lsen,s_limvis,s_limsen)
except TypeError:
pass
# hidden part + rolled : area are set to zero as leaf rolled area is already counted in leaf element
# hidden_elt = {'label': 'StemElement', 'offset': lhide, 'length': lrolled, 'area': 0, 'green_length': lrolled, 'green_area': 0, 'senesced_length' : 0, 'senesced_area':0,'is_green': True, 'azimuth': 0, 'inclination':0}
hidden_elt = {
"label": "HiddenElement",
"length": lhide,
"area": S_hide,
"is_green": True,
}
elements = [hidden_elt]
ds = 0
if Lshape is not None:
ds = float(Lshape) / sectors
# compute sectors from leafshape bes to leaf shape top
if lvis > 1e-6:
for isect in range(sectors):
ls_vis = 0
ls_rolled = 0
ls_rolled_green = 0
ls_rolled_sen = 0
d_rolled = 0
ls_green = 0
ls_sen = 0
S_green = 0
S_sen = 0
S_tot = 0
w_green = 0
w_sen = 0
w_tot = 0
srb_green = None
srt_green = None
srb_sen = None
srt_sen = None
try:
st = (isect + 1) * ds
ls_vis = min(ds, max(0.0, st - s_limvis))
if ls_vis > 0:
sb = st - ls_vis
sb_green = sb
st_green = min(st, max(sb_green, s_limsen))
sb_sen = st_green
st_sen = st
ls_green = st_green - sb_green
ls_sen = st_sen - sb_sen
# print(sb_green,st_green,st_sen)
#
# Compute area of elements
if ls_green > 0 and leaves is not None:
S_green = leaves.blade_elt_area(
shape_key,
Lshape,
Lwshape,
sb_green / Lshape,
st_green / Lshape,
)
w_green = leaves.blade_elt_width(
shape_key,
Lshape,
Lwshape,
sb_green / Lshape,
st_green / Lshape,
)
if ls_sen > 0 and leaves is not None:
S_sen = leaves.blade_elt_area(
shape_key, Lshape, Lwshape, sb_sen / Lshape, st_sen / Lshape
)
w_sen = leaves.blade_elt_width(
shape_key, Lshape, Lwshape, sb_sen / Lshape, st_sen / Lshape
)
# made intergration again for avoiding fluctuations
# S_tot = blade_elt_area(xysr_shape, Lshape, Lwshape, sb / Lshape, st / Lshape)
S_tot = S_green + S_sen
w_tot = max(w_green, w_sen)
#
# compute position of flat parts of the element
ls_flat = min(ls_vis, max(0.0, st - s_limrolled))
if ls_flat > 0:
sb = st - ls_flat
sb_green = sb
st_green = min(st, max(sb_green, s_limsen))
sb_sen = st_green
st_sen = st
srb_green = (float(sb_green) - s_limvis) / lvis
srt_green = (float(st_green) - s_limvis) / lvis
srb_sen = (float(sb_sen) - s_limvis) / lvis
srt_sen = (float(st_sen) - s_limvis) / lvis
# print(srb_green,srt_green,srb_sen,srt_sen)
if ls_flat < ls_vis:
ls_rolled = ls_vis - ls_flat
ls_rolled_green = min(ls_rolled, ls_green)
ls_rolled_sen = ls_rolled - ls_rolled_green
S_rolled = S_tot * ls_rolled / ls_vis
d_rolled = float(S_rolled) / numpy.pi / ls_rolled
except TypeError: # input is None
# print "passing"
pass
green_elt = {
"label": "LeafElement" + str(isect + 1) + "g",
"length": ls_green,
"area": S_green,
"is_green": True,
"srb": srb_green,
"srt": srt_green,
"lrolled": ls_rolled_green,
"d_rolled": d_rolled,
"width": w_green,
}
sen_elt = {
"label": "LeafElement" + str(isect + 1) + "s",
"length": ls_sen,
"area": S_sen,
"is_green": False,
"srb": srb_sen,
"srt": srt_sen,
"lrolled": ls_rolled_sen,
"d_rolled": d_rolled,
"width": w_sen,
}
elt = {
"label": "LeafElement" + str(isect + 1),
"length": ls_sen + ls_green,
"area": S_tot,
"green_length": ls_green,
"green_area": S_green,
"senesced_length": ls_sen,
"senesced_area": S_sen,
"is_green": (ls_green > ls_sen),
"srb": srb_green,
"srt": srt_sen,
"lrolled": ls_rolled,
"d_rolled": d_rolled,
"width": w_tot,
}
if split:
elements.extend([green_elt, sen_elt])
else:
elements.extend([elt])
return elements
[docs]
def get_component(components, index):
component = components[index]
elements = component["elements"]
properties = dict(component)
del properties["elements"]
return properties, elements
[docs]
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 an 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 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_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 = -0.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 "ntop" not in args:
args.update({"ntop": None})
if "Gd" not in args:
args.update({"Gd": 0.19})
args.update({"split": split})
hs_f = args.get("HS_final")
if hs_f != "NA":
if float(hs_f) < 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)
[docs]
def update_elements(organ, leaves=None):
if organ.label.startswith("blade"):
elements = blade_elements(
organ.n_sect,
organ.length,
organ.visible_length,
organ.rolled_length,
organ.senesced_length,
organ.shape_mature_length,
organ.shape_max_width,
organ.shape_key,
leaves=leaves,
)
for i, e in enumerate(organ.components()):
for k in elements[i]:
exec("e.%s = elements[i]['%s']" % (k, k))
[docs]
def update_plant(plant, time):
"""update phenology of plant axes"""
plant.time = time
[docs]
def update_axe(axe):
"""update phenology on axes"""
if "timetable" in axe.properties():
axe.phyllochronic_time = numpy.interp(
axe.complex().time, axe.timetable["tip"], axe.timetable["n"]
)
# print 'axe %s phyllochronic time:%f'%(axe.label,axe.phyllochronic_time)
[docs]
def update_organ(organ, h_whorl=0):
rank = int(organ.complex().index())
axe = organ.complex_at_scale(2)
rph = axe.phyllochronic_time - rank
length = organ.length
vlength = organ.visible_length
if "elongation_curve" in organ.properties():
organ.length = numpy.interp(
rph, organ.elongation_curve["x"], organ.elongation_curve["y"]
)
organ.visible_length = organ.length - h_whorl
update_elements(organ)
organ.dl = organ.length - length
organ.dl_visible = organ.visible_length - vlength
[docs]
def update_organ_from_table(organ, metamer, oldmetamer):
neworg = metamer[organ.label]
# oldorg = oldmetamer[organ.label]
new_elts = neworg.pop("elements")
for k in neworg:
if k != "shape_xysr":
exec("organ.%s = neworg['%s']" % (k, k))
for i, e in enumerate(organ.components()):
has_area = False
for k in new_elts[i]:
if k in ["area", "green_area", "senesced_area"]:
exec("e.%s += (new_elts[i]['%s'] - old_elts[i]['%s'])" % (k, k, k))
has_area = True
else:
exec("e.%s = new_elts[i]['%s']" % (k, k))
# control senescence (in case of acceleration by an other process)
if has_area:
if (e.green_area + e.senesced_area) > e.area:
e.green_area = 0
e.senesced_area = e.area
[docs]
def mtg_update_at_time(g, time):
"""Compute plant state at a given time according to dynamical parameters found in mtg"""
for pid in g.component_roots_at_scale_iter(g.root, scale=1):
p = g.node(pid)
update_plant(p, time)
hw = {"0": 0}
for a in p.components_at_scale(2):
update_axe(a)
numaxe = int(a.index())
hwhorl = hw[str(numaxe)]
for o in a.components_at_scale(4):
update_organ(o, hwhorl)
# update whorl
if o.label.startswith("internode"):
if o.inclination < 0:
hwhorl = 0 # redressement
else:
hwhorl = max(0, hwhorl - o.length)
elif o.label.statswith("sheath"):
hwhorl += o.visible_length
# memorise main stem values
if numaxe == 0:
hw[o.complex().index()] = o.length
[docs]
def mtg_update_from_table(g, cantable, old_cantable):
"""Compute plant state at a given time according to dynamical parameters found in mtg"""
df = pandas.DataFrame(cantable)
old_df = pandas.DataFrame(old_cantable)
for pid in g.component_roots_at_scale_iter(g.root, scale=1):
p = g.node(pid)
for ax in p.components_at_scale(2):
for m in ax.components_at_scale(3):
nump = int("".join(list(p.label)[5:]))
numphy = int("".join(list(m.label)[7:]))
dm = df[
(df["plant"] == nump)
& (df["axe_id"] == ax.label)
& (df["numphy"] == numphy)
]
old_dm = old_df[
(old_df["plant"] == nump)
& (old_df["axe_id"] == ax.label)
& (old_df["numphy"] == numphy)
]
# G. Garin 02/08: Addition of the following condition
if len(dm) > 0:
dmd = dict([(k, v[0]) for k, v in dm.to_dict("list").items()])
old_dmd = dict(
[(k, v[0]) for k, v in old_dm.to_dict("list").items()]
)
blade = m.components_at_scale(4)[2]
dmd["xysr_shape"] = blade.shape_xysr
dmd["Lsect"] = blade.n_sect
old_dmd["xysr_shape"] = blade.shape_xysr
old_dmd["Lsect"] = blade.n_sect
met = adel_metamer(**dmd)
newmetamer = dict([(mm["label"], mm) for mm in met])
old_met = adel_metamer(**old_dmd)
oldmetamer = dict([(mm["label"], mm) for mm in old_met])
for o in m.components_at_scale(4):
update_organ_from_table(o, newmetamer, oldmetamer)
[docs]
def adel_label(g, vid):
label = "undef"
if g.scale(vid) == 5:
organ = g.complex(vid)
metamer = g.complex(organ)
axe = g.complex(metamer)
plant = g.complex(axe)
label = "_".join(
[
g.label(plant),
g.label(axe),
g.label(metamer),
g.label(organ),
g.label(vid),
]
)
return label
[docs]
def adel_labels(g, scale=5):
"""return a dict vid:adel_id"""
return {vid: adel_label(g, vid) for vid in g.vertices_iter(scale=scale)}
[docs]
def adel_ids(g, scale=5):
"""return a dict adel_id:vid"""
return {adel_label(g, vid): vid for vid in g.vertices_iter(scale=scale)}
[docs]
def mtg_update(newg, g, refg):
"""update newg with specific properties found in g only and update by increment compared to refg area-like properties"""
specific = set(g.property_names()) - set(newg.property_names())
ids = adel_ids(g, scale=5)
newids = adel_ids(newg, scale=5)
common_labs = set(ids) & set(newids)
for prop in specific:
newg.add_property(prop)
newprop = {
newids[lab]: g.property(prop)[ids[lab]]
for lab in common_labs
if ids[lab] in g.property(prop)
}
newg.property(prop).update(newprop)
# g.remove_property(prop)#helps beeing compatible with ctypes objects
for lab in common_labs:
vid = ids[lab]
newvid = newids[lab]
if (
vid in g.property("area")
and newvid in newg.property("area")
and vid in refg.property("area")
):
if newg.property("length")[newvid] > 0:
dlength = max(
[0, newg.property("length")[newvid] - refg.property("length")[vid]]
)
darea = 0
if dlength > 0: # avoid changing area when length is stabilised
darea = max(
[0, newg.property("area")[newvid] - refg.property("area")[vid]]
) # do not take into account negative variations du to rolling
newarea = g.property("area")[vid] + darea
# correction if last area estimation of area_sen is different from the one of area
if (
newg.property("senesced_length")[newvid]
>= newg.property("length")[newvid]
):
newsen = newarea
newgreen = 0
else:
dlength = max(
[
0,
newg.property("senesced_length")[newvid]
- refg.property("senesced_length")[vid],
]
)
dsen = 0
if dlength > 0:
dsen = max(
[
0,
newg.property("senesced_area")[newvid]
- refg.property("senesced_area")[vid],
]
)
newsen = min([newarea, g.property("senesced_area")[vid] + dsen])
newgreen = max(
[
0,
min(
[
newarea - newsen,
g.property("green_area")[vid] + (darea - dsen),
]
),
]
)
newg.property("area")[newvid] = newarea
newg.property("green_area")[newvid] = newgreen
newg.property("senesced_area")[newvid] = newsen
else: # node is no longer there, specific property are removed
for prop in specific:
if newvid in newg.property(prop):
newg.property(prop).pop(newvid)
return newg
[docs]
def move_properties(g_source, g_dest, filter_length=True, cleanup_source=True):
"""Move properties present in g_source and not in g_dest into g_dest.
if filter_length is True (default), properties attached to node whose length is zero are not transfered
"""
specific = set(g_source.property_names()) - set(g_dest.property_names())
ids = adel_ids(g_source, scale=5)
newids = adel_ids(g_dest, scale=5)
if filter_length:
length = g_dest.property("length")
newids = {lab: vid for lab, vid in newids.items() if length[vid] > 0}
common_labs = set(ids) & set(newids)
for prop in specific:
g_dest.add_property(prop)
newprop = {
newids[lab]: g_source.property(prop)[ids[lab]]
for lab in common_labs
if ids[lab] in g_source.property(prop)
}
g_dest.property(prop).update(newprop)
if cleanup_source:
g_source.remove_property(prop)
[docs]
def exposed_areas(g):
"""returns a Dataframe with all exposed (visible) areas of elements in g"""
data = {}
what = (
"length",
"area",
"green_length",
"green_area",
"senesced_length",
"senesced_area",
)
for vid in g.vertices_iter(scale=g.max_scale()):
n = g.node(vid)
if n.length > 0 and not n.label.startswith("Hidden"):
organ = n.complex()
metamer = organ.complex()
axe = metamer.complex()
plant = axe.complex()
numphy = int("".join(list(metamer.label)[7:]))
nf = axe.nff
node_data = {
"plant": plant.label,
"axe": axe.label,
"metamer": numphy,
"organ": organ.label,
"vid": vid,
"ntop": nf - numphy + 1,
"element": n.label,
"refplant_id": plant.refplant_id,
"nff": nf,
"HS_final": axe.HS_final,
"L_shape": metamer.L_shape,
}
properties = n.properties()
node_data.update({k: properties[k] for k in what})
if "species" in plant.properties():
node_data.update({"species": plant.species})
else:
node_data.update({"species": 0})
data[vid] = node_data
df = pandas.DataFrame(data).T
# hack
df["d_basecol"] = 0
return df
[docs]
def exposed_areas2canS(exposed_areas):
"""adaptor to convert new adel output to old adel output (canS-like) dataframe"""
d = exposed_areas
if len(d) > 0:
grouped = d.groupby(["species", "plant", "axe", "metamer"], group_keys=False)
def _metamer(sub):
met = {
"species": sub.species.values[0],
"plant": sub.plant.values[0],
"refplant_id": sub.refplant_id.values[0],
"axe_id": sub.axe.values[0],
"nff": sub.nff.values[0],
"HS_final": sub.HS_final.values[0],
"numphy": sub.metamer.values[0],
"ntop": sub.ntop.values[0],
"L_shape": sub.L_shape.values[0],
"Lv": sub[sub.organ == "blade"].length.sum(),
"Lvgreen": sub[sub.organ == "blade"].green_length.sum(),
"Lvsen": sub[sub.organ == "blade"].senesced_length.sum(),
"Slv": sub[sub.organ == "blade"].area.sum(),
"Slvgreen": sub[sub.organ == "blade"].green_area.sum(),
"Slvsen": sub[sub.organ == "blade"].senesced_area.sum(),
"Gv": sub[sub.organ == "sheath"].length.sum(),
"Gvgreen": sub[sub.organ == "sheath"].green_length.sum(),
"Gvsen": sub[sub.organ == "sheath"].senesced_length.sum(),
"SGv": sub[sub.organ == "sheath"].area.sum(),
"SGvgreen": sub[sub.organ == "sheath"].green_area.sum(),
"SGvsen": sub[sub.organ == "sheath"].senesced_area.sum(),
"Ev": sub[sub.organ == "internode"].length.sum(),
"Evgreen": sub[sub.organ == "internode"].green_length.sum(),
"Evsen": sub[sub.organ == "internode"].senesced_length.sum(),
"SEv": sub[sub.organ == "internode"].area.sum(),
"SEvgreen": sub[sub.organ == "internode"].green_area.sum(),
"SEvsen": sub[sub.organ == "internode"].senesced_area.sum(),
}
return pandas.DataFrame(met, index=[sub.index[0]])
d = grouped[['plant', 'axe', 'metamer', 'organ', 'vid', 'ntop', 'element',
'refplant_id', 'nff', 'HS_final', 'L_shape', 'length', 'area',
'green_length', 'green_area', 'senesced_length', 'senesced_area',
'species', 'd_basecol']].apply(_metamer)
# hack
d["d_basecol"] = 0
return d
[docs]
def replicate(g, target=1):
"""replicate the plants in g up to obtain target new plants"""
current = g.nb_vertices(scale=1)
if target <= current:
return g
assert target % current == 0
# otherwise use nrem + union
nduplication = int(numpy.log2(1.0 * target / current))
missing = target - current * numpy.power(2, nduplication)
cards = numpy.power(2, list(range(nduplication)))
add_g = [False] * len(cards)
for i in reversed(list(range(len(cards)))):
if cards[i] <= missing:
add_g[i] = True
missing -= cards[i]
assert missing == 0
g_add = None
g_dup = g.sub_mtg(g.root)
for i in range(nduplication):
g1 = g_dup.sub_mtg(g_dup.root)
g_dup = union(g_dup, g1)
if add_g[i]:
g1 = g.sub_mtg(g.root)
if g_add is None:
g_add = g1
else:
g_add = union(g_add, g1)
if g_add is not None:
g_dup = union(g_dup, g_add)
return g_dup
[docs]
def duplicate(g, replicates=1, grem=None):
"""construct a mtg replicating g n times and adding grem"""
g_rep = replicate(g, replicates)
if grem is not None:
g = grem
g = union(g, g_rep)
else:
g = g_rep
return g
# to do
# varaibles sur element : area, senesced_area, senescenece_position (0,1 sur la feuille)
# generer dans alep.wheat.py un tableau axisdynamic
# la fonction grow
#