From a741be28114af5ffac40ae76d6bd89b6b6aa2bdd Mon Sep 17 00:00:00 2001 From: boris-kz Date: Sun, 15 Dec 2024 22:31:52 -0500 Subject: [PATCH] edits with Chee --- frame_2D_alg/deprecated/24.12.py | 59 +++++++------ .../vectorize_edge_blob/agg_recursion.py | 8 +- .../vectorize_edge_blob/comp_slice.py | 19 ++--- .../vectorize_edge_blob/slice_edge.py | 83 +++++++++---------- .../{trace_edge.py => vect_edge.py} | 69 ++++++++------- 5 files changed, 120 insertions(+), 118 deletions(-) rename frame_2D_alg/vectorize_edge_blob/{trace_edge.py => vect_edge.py} (90%) diff --git a/frame_2D_alg/deprecated/24.12.py b/frame_2D_alg/deprecated/24.12.py index 1b4dc214d..8775f3d53 100644 --- a/frame_2D_alg/deprecated/24.12.py +++ b/frame_2D_alg/deprecated/24.12.py @@ -156,42 +156,41 @@ def add_H(HE, He_, sign=1): # unpack derHs down to numericals and sum them return HE # root should be updated by returned HE -def trace(edge): # fill and trace across slices - - adjacent_ = [(P, y,x) for P in edge.P_ for y,x in edge.rootd if edge.rootd[y,x] is P] - bi__ = defaultdict(list) # prelinks (bi-lateral) - while adjacent_: - _P, _y,_x = adjacent_.pop(0) # also pop _P__ - _pre_ = bi__[_P] - for y,x in [(_y-1,_x),(_y,_x+1),(_y+1,_x),(_y,_x-1)]: - try: # if yx has _P, try to form link +def trace_P_adjacency(edge): # fill and trace across slices + + P_map_ = [(P, y,x) for P in edge.P_ for y,x in edge.rootd if edge.rootd[y,x] is P] + prelink__ = defaultdict(list) # uplinks + while P_map_: + _P, _y,_x = P_map_.pop(0) # also pop _P__ + _margin = prelink__[_P] # empty list per _P + for y,x in [(_y-1,_x),(_y,_x+1),(_y+1,_x),(_y,_x-1)]: # adjacent pixels + try: # form link if yx has _P P = edge.rootd[y,x] - pre_ = bi__[P] - if _P is not P and _P not in pre_ and P not in _pre_: - pre_ += [_P] - _pre_ += [P] - except KeyError: # if yx empty, keep tracing - if (y,x) not in edge.dert_: continue # stop if yx outside the edge + margin = prelink__[P] # empty list per P + if _P is not P: + if _P.yx < P.yx and _P not in margin: + margin += [_P] # _P is higher + elif P not in _margin: + _margin += [P] # P is higher + except KeyError: # if yx empty, keep tracing + if (y,x) not in edge.dert_: continue # yx is outside the edge edge.rootd[y,x] = _P - adjacent_ += [(_P, y,x)] - # remove redundant links + P_map_ += [(_P, y,x)] + # remove crossed links for P in edge.P_: yx = P.yx - for __P, _P in combinations(bi__[P], r=2): - if __P not in bi__[P] or _P not in bi__[P]: continue - __yx, _yx = __P.yx, _P.yx # center coords - # start -> end: - __yx1 = np.subtract(__P.yx_[0], __P.axis) - __yx2 = np.add(__P.yx_[-1], __P.axis) + for _P, __P in combinations(prelink__[P], r=2): + _yx, __yx = _P.yx, __P.yx + # get aligned line segments: _yx1 = np.subtract(_P.yx_[0], _P.axis) _yx2 = np.add(_P.yx_[-1], _P.axis) - # remove link(_P,P) crossing __P: + __yx1 = np.subtract(__P.yx_[0], __P.axis) + __yx2 = np.add(__P.yx_[-1], __P.axis) + # remove crossed uplinks: if xsegs(yx, _yx, __yx1, __yx2): - bi__[P].remove(_P) - bi__[_P].remove(P) - # remove link(__P,P) crossing _P): + prelink__[P].remove(_P) elif xsegs(yx, __yx, _yx1, _yx2): - bi__[P].remove(__P) - bi__[__P].remove(P) + prelink__[P].remove(__P) + # for comp_slice: + edge.pre__ = prelink__ - edge.pre__ = {_P:[P for P in bi__[_P] if _P.yx < P.yx] for _P in edge.P_} diff --git a/frame_2D_alg/vectorize_edge_blob/agg_recursion.py b/frame_2D_alg/vectorize_edge_blob/agg_recursion.py index 0e7a386cb..7c5d74034 100644 --- a/frame_2D_alg/vectorize_edge_blob/agg_recursion.py +++ b/frame_2D_alg/vectorize_edge_blob/agg_recursion.py @@ -5,7 +5,7 @@ from functools import reduce from frame_blobs import frame_blobs_root, intra_blob_root, imread from comp_slice import comp_latuple, comp_md_ -from trace_edge import comp_node_, comp_link_, sum2graph, get_rim, CH, CG, ave, ave_d, ave_L, vectorize_root, comp_area, extend_box +from vect_edge import comp_node_, comp_link_, sum2graph, get_rim, CH, CG, ave, ave_d, ave_L, vectorize_root, comp_area, extend_box ''' Cross-compare and cluster Gs within a frame, potentially unpacking their node_s first, alternating agglomeration and centroid clustering. @@ -34,10 +34,10 @@ def cluster_eval(G, N_, fd): if m > ave * r: mlay = CH().add_H([L.derH for L in L_]) # mfork, else no new layer frame.derH = CH(H=[mlay], n=mlay.n, root=frame, Et=copy(mlay.Et)); mlay.root=frame.derH - vd = d - ave_d * r - if vd > 0: # no cross-projection + vd = d * (m/ave) - ave_d * r + if vd > 0: for L in L_: - L.root_ = [frame]; L.extH = CH(); L.rimt = [[],[]] + L.extH, L.root, L.mL_t, L.rimt, L.aRad, L.visited_, L.Et, L.n = CH(), frame, [[],[]], [[],[]], 0, [L], copy(L.derH.Et), L.derH.n lN_,lL_, md = comp_link_(L_) # comp new L_, root.link_ was compared in root-forming for alt clustering vd *= md / ave if lL_: # recursive der+ eval_: cost > ave_match, add by feedback if < _match? diff --git a/frame_2D_alg/vectorize_edge_blob/comp_slice.py b/frame_2D_alg/vectorize_edge_blob/comp_slice.py index 605c10ed0..f661b99fc 100644 --- a/frame_2D_alg/vectorize_edge_blob/comp_slice.py +++ b/frame_2D_alg/vectorize_edge_blob/comp_slice.py @@ -63,12 +63,12 @@ def vectorize_root(frame): for blob in blob_: if not blob.sign and blob.G > aveG * blob.root.rdn: edge = slice_edge(blob) - if edge.G*(len(edge.P_) - 1) > ave_PPm: # eval PP, rdn=1 + if edge.G * (len(edge.P_) - 1) > ave_PPm: # eval PP, rdn=1 comp_slice(edge) def comp_slice(edge): # root function - edge.Et, edge.vertuple = np.zeros(2), np.array([np.zeros(6), np.zeros(6)]) # m_,d_ + edge.Et, edge.vertuple, edge.n = np.zeros(2), np.array([np.zeros(6), np.zeros(6)]), 0 # m_,d_,n for P in edge.P_: # add higher links P.vertuple = np.array([np.zeros(6), np.zeros(6)]) P.rim = []; P.lrim = []; P.prim = [] @@ -125,7 +125,7 @@ def comp_md_(_d_,d_, rn=.1, dir=1): # dir may be -1 def convert_to_dP(_P,P, derLay, angle, distance, Et): link = CdP(nodet=[_P,P], Et=Et, vertuple=derLay, angle=angle, span=distance, yx=np.add(_P.yx, P.yx)/2) - # bidirectional, regardless of clustering: + # bilateral, regardless of clustering: _P.vertuple += link.vertuple; P.vertuple += link.vertuple _P.lrim += [link]; P.lrim += [link] _P.prim += [P]; P.prim +=[_P] # all Ps are dPs if fd @@ -138,22 +138,21 @@ def form_PP_(root, iP_, fd): # form PPs of dP.valt[fd] + connected Ps val for P in iP_: P.merged = 0 for P in iP_: # dP from link_ if fd if P.merged: continue - _prim_ = P.prim; _lrim_ = P.lrim - _P_ = {P}; link_ = set(); Et = np.zeros(2); n = 0 + _prim_ = P.prim; _lrim_ = P.lrim; I, G, M, Ma, L, _ = P.latuple + _P_ = {P}; link_ = set(); Et = np.array([M,G]); n = L while _prim_: prim_,lrim_ = set(),set() for _P,_L in zip(_prim_,_lrim_): if _L.Et[fd] < aves[fd] or _P.merged: continue - _P_.add(_P); link_.add(_L); Et += _L.Et; n += P.latuple[4] # L + _P_.add(_P); link_.add(_L); I, G, M, Ma, L, _ = _P.latuple + Et += _L.Et + np.array([M,G]); n += L # L is a multiplier to 1 for _L.vertuple[1] prim_.update(set(_P.prim) - _P_) lrim_.update(set(_P.lrim) - link_) _P.merged = 1 _prim_, _lrim_ = prim_, lrim_ - if not link_: - PPt_ += [P]; continue PPt = sum2PP(root, list(_P_), list(link_), Et, n) - PPt_ += [PPt] + PPt_ += [PPt]; root.Et += Et; root.n += n return PPt_ @@ -171,7 +170,7 @@ def sum2PP(root, P_, dP_, Et, n): # sum links in Ps and Ps in PP link_ += [dP] a = dP.angle; A = np.add(A,a); S += np.hypot(*a) # span, links are contiguous but slanted else: # single P PP - S,A = P_[0].latuple[4:] # latuple is I, G, M, Ma, L, (Dy, Dx) + S,A = P_[0].latuple[4:] # [I, G, M, Ma, L, (Dy, Dx)] box = [np.inf,np.inf,0,0] for P in P_: if not fd: # else summed from P_ nodets on top diff --git a/frame_2D_alg/vectorize_edge_blob/slice_edge.py b/frame_2D_alg/vectorize_edge_blob/slice_edge.py index 35cdcfcde..e53514255 100644 --- a/frame_2D_alg/vectorize_edge_blob/slice_edge.py +++ b/frame_2D_alg/vectorize_edge_blob/slice_edge.py @@ -106,41 +106,40 @@ def select_max(edge): def trace_P_adjacency(edge): # fill and trace across slices - P_map_ = [(P, y,x) for P in edge.P_ for y,x in edge.rootd if edge.rootd[y,x] is P] - prelink__ = defaultdict(list) # uplinks - while P_map_: - _P, _y,_x = P_map_.pop(0) # also pop _P__ + margin_rim = [(P, y,x) for P in edge.P_ for y,x in edge.rootd if edge.rootd[y,x] is P] + prelink__ = defaultdict(list) # bilateral + while margin_rim: # breadth-first search for neighbors + _P, _y,_x = margin_rim.pop(0) # also pop _P__ _margin = prelink__[_P] # empty list per _P for y,x in [(_y-1,_x),(_y,_x+1),(_y+1,_x),(_y,_x-1)]: # adjacent pixels - try: # form link if yx has _P - P = edge.rootd[y,x] - margin = prelink__[P] # empty list per P - if _P is not P: - if _P.yx < P.yx and _P not in margin: - margin += [_P] # _P is higher - elif P not in _margin: - _margin += [P] # P is higher - except KeyError: # if yx empty, keep tracing - if (y,x) not in edge.dert_: continue # yx is outside the edge - edge.rootd[y,x] = _P - P_map_ += [(_P, y,x)] + if (y,x) not in edge.dert_: continue # yx is outside the edge + if (y,x) not in edge.rootd: # assign root, keep tracing + edge.rootd[y, x] = _P + margin_rim += [(_P, y, x)] + continue + # form link if yx has _P + P = edge.rootd[y,x] + margin = prelink__[P] # empty list per P + if _P is not P and _P not in margin and P not in _margin: + margin += [_P]; _margin += [P] # remove crossed links - for P in edge.P_: - yx = P.yx - for _P, __P in combinations(prelink__[P], r=2): - _yx, __yx = _P.yx, __P.yx + for _P in edge.P_: + _yx = _P.yx + for P, __P in combinations(prelink__[_P], r=2): + if {__P,P}.intersection(prelink__[_P]) != {__P, P}: continue # already removed + yx, __yx = P.yx, __P.yx # get aligned line segments: - _yx1 = np.subtract(_P.yx_[0], _P.axis) - _yx2 = np.add(_P.yx_[-1], _P.axis) + yx1 = np.subtract(P.yx_[0], P.axis) + yx2 = np.add(P.yx_[-1], P.axis) __yx1 = np.subtract(__P.yx_[0], __P.axis) __yx2 = np.add(__P.yx_[-1], __P.axis) # remove crossed uplinks: if xsegs(yx, _yx, __yx1, __yx2): - prelink__[P].remove(_P) - elif xsegs(yx, __yx, _yx1, _yx2): - prelink__[P].remove(__P) + prelink__[P].remove(_P); prelink__[_P].remove(P) + elif xsegs(_yx, __yx, yx1, yx2): + prelink__[_P].remove(__P); prelink__[__P].remove(_P) # for comp_slice: - edge.pre__ = prelink__ + edge.pre__ = {_P:[P for P in prelink__[_P] if _P.yx > P.yx] for _P in prelink__} # -------------------------------------------------------------------------------------------------------------- # utility functions @@ -232,25 +231,23 @@ def xsegs(yx1, yx2, yx3, yx4): v_, u_ = zip(*vu_) plt.quiver(x_, y_, u_, v_, scale=100) if show_slices: - for P in edge.P_: - y_, x_ = zip(*(P.yx_ - yx0)) - if len(P.yx_) == 1: - v, u = P.axis - y_ = y_[0]-v/2, y_[0]+v/2 - x_ = x_[0]-u/2, x_[0]+u/2 - plt.plot(x_, y_, "k-", linewidth=3) - yp, xp = P.yx - yx0 - pre_set = set() - for _P in edge.pre__[P]: - assert _P.id not in pre_set # verify pre-link uniqueness - pre_set.add(_P.id) + for _P in edge.P_: + _y_, _x_ = zip(*(_P.yx_ - yx0)) + if len(_P.yx_) == 1: + v, u = _P.axis + _y_ = _y_[0]-v/2, _y_[0]+v/2 + _x_ = _x_[0]-u/2, _x_[0]+u/2 + plt.plot(_x_, _y_, "k-", linewidth=3) + _yp, _xp = _P.yx - yx0 + assert len(set(edge.pre__[_P])) == len(edge.pre__[_P]) # verify pre-link uniqueness + for P in edge.pre__[_P]: assert _P.yx > P.yx # verify up-link - _yp, _xp = _P.yx - yx0 + yp, xp = P.yx - yx0 plt.plot([_xp, xp], [_yp, yp], "ko--", alpha=0.5) - yx_ = [yx for yx in edge.rootd if edge.rootd[yx] is P] - if yx_: - y_, x_ = zip(*(yx_ - yx0)) - plt.plot(x_, y_, 'o', alpha=0.5) + _cyx_ = [_yx for _yx in edge.rootd if edge.rootd[_yx] is _P] + if _cyx_: + _cy_, _cx_ = zip(*(_cyx_ - yx0)) + plt.plot(_cx_, _cy_, 'o', alpha=0.5) ax = plt.gca() ax.set_aspect('equal', adjustable='box') diff --git a/frame_2D_alg/vectorize_edge_blob/trace_edge.py b/frame_2D_alg/vectorize_edge_blob/vect_edge.py similarity index 90% rename from frame_2D_alg/vectorize_edge_blob/trace_edge.py rename to frame_2D_alg/vectorize_edge_blob/vect_edge.py index ed43bee20..ca1d720b7 100644 --- a/frame_2D_alg/vectorize_edge_blob/trace_edge.py +++ b/frame_2D_alg/vectorize_edge_blob/vect_edge.py @@ -189,6 +189,7 @@ def __init__(G, n=0, fd=0, rng=1, root_=[], node_=[], link_=[], subG_=[], subL_= G.n = n # last layer? G.fd = fd # 1 if cluster of Ls | lGs? G.Et = np.zeros(3) if Et is None else Et # sum all param Ets + # or np.zeros(4): m,d,r,n: normalizing factors rdn of overlap and n of compared params G.rng = rng G.root_ = root_ # in cluster_N_, same nodes may be in multiple dist layers G.node_ = node_ # convert to GG_ or node_H in agg++ @@ -285,21 +286,22 @@ def cluster_PP_(edge, fd): if fd: edge.subL_ = subG_ else: edge.subG_ = subG_ # higher aggr, mediated access to init edge.subG_ # comp PP_: - N_,L_,(m,d,r) = comp_node_(edge.subG_) + N_,L_,Et = comp_node_(edge.subG_) + m,d, r,n = Et # pack n in Et? edge.subG_ = N_; edge.link_ = L_ # cancel by borrowing d?: - if m > ave * r: + if m > ave * r * n: mlay = CH().add_H([L.derH for L in L_]) # mfork, else no new layer edge.derH = CH(H=[mlay], root=edge, Et=copy(mlay.Et), n=mlay.n) mlay.root = edge.derH # init if len(N_) > ave_L: cluster_PP_(edge,fd=0) # borrow from misprojected m: proj_m -= proj_d, no eval per link: comp instead - if d * (m/ave) > ave_d * r: # likely not from the same links + if d * (m/n/ave) > ave_d * r * n: # likely not from the same links for L in L_: - L.extH = CH(); L.root_= [edge] + L.extH, L.root, L.mL_t, L.rimt, L.aRad, L.visited_, L.Et, L.n = CH(), edge, [[], []], [[], []], 0, [L], copy(L.derH.Et), L.derH.n # comp dPP_: - lN_,lL_,_ = comp_link_(L_) + lN_,lL_,_ = comp_link_(L_, Et) if lL_: # lL_ and lN_ may empty edge.derH.append_(CH().add_H([L.derH for L in lL_])) # dfork if len(lN_) > ave_L: # if vd? @@ -327,7 +329,9 @@ def comp_node_(_N_): # rng+ forms layer of rim and extH per N, appends N_,L_,Et nrim = {L.nodet[1] if L.nodet[0] is G else L.nodet[0] for L,_ in G.rim} if _nrim & nrim: # indirectly connected Gs, continue # no direct match priority? - if dist < max_dist * (radii * icoef**3) * (_G.Et[0] + G.Et[0]) * (_G.extH.Et[0] + G.extH.Et[0]): + if (dist < max_dist * (radii * icoef**3) + * (1 + (_G.Et[0] + G.Et[0]) - ave * (_G.n + G.n)) # induction + * (1 + (_G.extH.Et[0] + G.extH.Et[0]) - ave * (_G.extH.n + G.extH.n))): # n should be in Et[2] or Et[3]? Link = comp_N(_G,G, rn, angle=[dy,dx],dist=dist) L_ += [Link] # include -ve links if Link.derH.Et[0] > ave * Link.derH.Et[2]: @@ -343,20 +347,21 @@ def comp_node_(_N_): # rng+ forms layer of rim and extH per N, appends N_,L_,Et return list(N_), L_, ET # flat N__ and L__ -def comp_link_(iL_): # comp CLs via directional node-mediated link tracing: der+'rng+ in root.link_ rim_t node rims +def comp_link_(iL_, iEt): # comp CLs via directional node-mediated link tracing: der+'rng+ in root.link_ rim_t node rims fd = isinstance(iL_[0].nodet[0], CL) + M,D, r,rn = iEt # normalizing factors rdn: overlap, and n of compared params for L in iL_: - L.mL_t, L.rimt, L.aRad, L.visited_, L.Et, L.n = [[],[]], [[],[]], 0, [L], copy(L.derH.Et), L.derH.n - # init mL_t (mediated Ls) per L: - for rev, n, mL_ in zip((0,1), L.nodet, L.mL_t): - for _L,_rev in n.rimt[0]+n.rimt[1] if fd else n.rim: - if _L is not L and _L.derH.Et[0] > ave * _L.derH.Et[2]: - mL_ += [(_L, rev ^_rev)] # the direction of L relative to _L - _L_, out_L_, LL_, ET = iL_,set(),[],np.zeros(3) # out_L_: positive subset of iL_ + # init mL_t: bilateral mediated Ls per L: + for rev, N, mL_ in zip((0,1), L.nodet, L.mL_t): + for _L,_rev in n.rimt[0]+N.rimt[1] if fd else N.rim: + if _L is not L: + if _L.derH.Et[1] * (M/ (ave*r*rn)) > ave_d * _L.derH.Et[2]: # proj val = compared d * rel root M + mL_ += [(_L, rev ^_rev)] # the direction of L relative to _L + _L_, out_L_, LL_, ET = iL_,set(),[],np.zeros(3) # out_L_: positive subset of iL_, Et = np.zeros(4)? med = 1 while True: # xcomp _L_ - L_, Et = set(),np.zeros(3) + L_, Et, n = set(), np.zeros(3), 0 for L in _L_: for mL_ in L.mL_t: for _L, rev in mL_: # rev is relative to L @@ -366,31 +371,32 @@ def comp_link_(iL_): # comp CLs via directional node-mediated link tracing: der Link = comp_N(_L,L, rn,angle=[dy,dx],dist=np.hypot(dy,dx), dir = -1 if rev else 1) # d = -d if L is reversed relative to _L Link.med = med LL_ += [Link] # include -ves, link order: nodet < L < rimt, mN.rim || L - if Link.derH.Et[1] > ave * Link.derH.Et[2]: # eval d: main comparand - out_L_.update({_L,L}); L_.update({_L,L}); Et += Link.derH.Et + if Link.derH.Et[0] > ave * Link.derH.Et[2]: # induction + out_L_.update({_L,L}); L_.update({_L,L}); Et += Link.derH.Et; n += Link.derH.n if not any(L_): break # extend mL_t per last med_L ET += Et; Med = med + 1 # med increases process costs if Et[0] > ave * Et[2] * Med: # project prior-loop value - new cost - _L_, _Et = set(),np.zeros(3) + _L_, ext_Et = set(), np.zeros(3) # ext_n = 0 for L in L_: - mL_t, lEt = [set(),set()],np.zeros(3) # __Ls per L + mL_t, lEt, ln = [set(),set()], np.zeros(3), 0 # __Ls per L for mL_,_mL_ in zip(mL_t, L.mL_t): for _L, rev in _mL_: - for _rev, n in zip((0,1), _L.nodet): - rim = n.rimt if fd else n.rim + for _rev, N in zip((0,1), _L.nodet): + rim = N.rimt if fd else N.rim if len(rim) == med: # append in comp loop for __L,__rev in rim[0]+rim[1] if fd else rim: if __L in L.visited_ or __L not in iL_: continue L.visited_ += [__L]; __L.visited_ += [L] - et = __L.derH.Et - if et[1] > ave * et[2] * Med: # /__L + et,_n = __L.derH.Et, __L.derH.n + # if compared mag * normalized loop induction?: + if et[1] * (Et[0]/n/ave) > ave_d * et[2] * Med: # /__L mL_.add((__L, rev ^_rev ^__rev)) # combine reversals: 2 * 2 mLs, but 1st 2 are pre-combined - lEt += et + lEt += et # ln += _n if lEt[0] > ave * lEt[2] * Med: # rng+/ L is different from comp/ L above - L.mL_t = mL_t; _L_.add(L); _Et += lEt + L.mL_t = mL_t; _L_.add(L); ext_Et += lEt # ext_n += ln # refine eval: - if _Et[0] > ave * _Et[0] * Med: + if ext_Et[1] * (Et[0]/n/ave) > ave_d * ext_Et[2] * Med: # * ext_n med = Med else: break @@ -451,7 +457,7 @@ def comp_N(_N,N, rn, angle=None, dist=None, dir=1): # dir if fd, Link.derH=dH, derH.root = Link for rev, node in zip((0,1), (N,_N)): # reverse Link direction for _N if fd: node.rimt[1-rev] += [(Link,rev)] # opposite to _N,N dir - else: node.rim += [(Link, rev)] + else: node.rim += [(Link,dir)] node.extH.add_H(Link.derH) node.n += derH.n node.Et += Et @@ -464,7 +470,7 @@ def sum2graph(root, grapht, fd, nest): # sum node and link params into graph, a node_, link_, Et, n = grapht[:4] Et *= icoef # is internal now graph = CG(fd=fd, Et=Et, root_ = [root]+node_[0].root_, node_=node_, link_=link_, rng=nest) - if len(grapht)==6: # called from cluster_N + if len(grapht) == 6: # called from cluster_N minL, subG_ = grapht[4:] if fd: graph.subL_ = subG_ else: graph.subG_ = subG_ @@ -494,9 +500,10 @@ def sum2graph(root, grapht, fd, nest): # sum node and link params into graph, a yx = np.divide(yx,L); graph.yx = yx # ave distance from graph center to node centers: graph.aRad = sum([np.hypot( *np.subtract(yx, N.yx)) for N in node_]) / L - if fd: - # assign alt graphs from d graph, after both linked m and d graphs are formed - for node in node_: # CG or CL + # for CG nodes only: + if isinstance(N,CG) and fd: + # assign alt graphs from d graph, after both m and d graphs are formed + for node in node_: mgraph = node.root_[-1] # altG summation below is still buggy with current add_H if mgraph: