From 852ba3761f0bcd93ade3ad4be4bda1f325eb76f2 Mon Sep 17 00:00:00 2001 From: Oliver Lindemann Date: Sat, 15 Nov 2014 14:36:15 +0100 Subject: [PATCH 1/5] BUG: observed overrides all foreground colours --- daft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daft.py b/daft.py index dd27d07..100e0e0 100644 --- a/daft.py +++ b/daft.py @@ -280,7 +280,7 @@ def render(self, ctx): p["fc"] = fc # Draw the foreground ellipse. - if ctx.observed_style == "inner" and not self.fixed: + if ctx.observed_style == "inner" and not self.fixed and self.observed: p["fc"] = "none" el = Ellipse(xy=ctx.convert(self.x, self.y), width=diameter * aspect, height=diameter, **p) From 80f831ea61712f806daf31a39d0c32eb30cbf62b Mon Sep 17 00:00:00 2001 From: Oliver Lindemann Date: Sat, 15 Nov 2014 17:11:49 +0100 Subject: [PATCH 2/5] "update" --- .gitignore | 1 + daft.py | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 3311046..1cc3bdb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dist *.egg-info *~ *.png +*.swp diff --git a/daft.py b/daft.py index 100e0e0..482aae0 100644 --- a/daft.py +++ b/daft.py @@ -174,13 +174,14 @@ class Node(object): """ def __init__(self, name, content, x, y, scale=1, aspect=None, - observed=False, fixed=False, + observed=False, fixed=False, rectangle=False, offset=[0, 0], plot_params={}, label_params=None): # Node style. assert not (observed and fixed), \ "A node cannot be both 'observed' and 'fixed'." self.observed = observed self.fixed = fixed + self.rectangle = rectangle # Metadata. self.name = name @@ -272,7 +273,12 @@ def render(self, ctx): p["fc"] = fc # Draw the background ellipse. - bg = Ellipse(xy=ctx.convert(self.x, self.y), + if self.rectangle: + bg = Rectangle(xy=ctx.convert(self.x-w/2, self.y-h/2), + width=w, height=h, **p) + print "hi" + else: + bg = Ellipse(xy=ctx.convert(self.x, self.y), width=w, height=h, **p) ax.add_artist(bg) @@ -282,7 +288,13 @@ def render(self, ctx): # Draw the foreground ellipse. if ctx.observed_style == "inner" and not self.fixed and self.observed: p["fc"] = "none" - el = Ellipse(xy=ctx.convert(self.x, self.y), + if self.rectangle: + xy = ctx.convert(self.x, self.y) + xy = (xy[0]-diameter/2.0, xy[1]-diameter/2.0) + el = Rectangle(xy=xy, + width=diameter * aspect, height=diameter, **p) + else: + el = Ellipse(xy=ctx.convert(self.x, self.y), width=diameter * aspect, height=diameter, **p) ax.add_artist(el) @@ -351,9 +363,12 @@ def _get_coords(self, ctx): dist1 = np.sqrt(dy * dy + dx * dx / float(a1 ** 2)) dist2 = np.sqrt(dy * dy + dx * dx / float(a2 ** 2)) + radius1 = 0.5 * ctx.node_unit * self.node1.scale + radius2 = 0.5 * ctx.node_unit * self.node2.scale + # Compute the fractional effect of the radii of the nodes. - alpha1 = 0.5 * ctx.node_unit * self.node1.scale / dist1 - alpha2 = 0.5 * ctx.node_unit * self.node2.scale / dist2 + alpha1 = radius1 / dist1 + alpha2 = radius2 / dist2 # Get the coordinates of the starting position. x0, y0 = x1 + alpha1 * dx, y1 + alpha1 * dy @@ -362,6 +377,18 @@ def _get_coords(self, ctx): dx0 = dx * (1. - alpha1 - alpha2) dy0 = dy * (1. - alpha1 - alpha2) + if self.node1.rectangle: + print self.node1.name + # replace start coordinates (polar) + _, angle = cart2polar(dx0, dy0) + angle = angle + np.pi/2.0 + displacment_dist = radius1/abs(np.cos(angle)) - radius1 + displacement = polar2cart(displacment_dist, angle) + print vec2deg(angle), np.cos(angle), displacment_dist + + x0 += displacement[1] + y0 -= displacement[0] + return x0, y0, dx0, dy0 def render(self, ctx): @@ -621,3 +648,18 @@ def _pop_multiple(d, default, *args): return default return results[0][1] + +def polar2cart(r, theta): + """polar coordinates to cartesian coordinates""" + x = r * np.cos(theta) + y = r * np.sin(theta) + return x, y + +def cart2polar(x,y): + """ cartesian coordinates to polar coordinates""" + r = np.sqrt(x**2 + y**2) + theta = np.arctan2(y, x) + return r, theta + +def vec2deg(vec): + return 180*vec/np.pi From 99e422c1b1f4977aa439d2b42a189b4cf0889a46 Mon Sep 17 00:00:00 2001 From: Oliver Lindemann Date: Sat, 15 Nov 2014 18:34:22 +0100 Subject: [PATCH 3/5] add rectangle --- daft.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/daft.py b/daft.py index 482aae0..68dfb2b 100644 --- a/daft.py +++ b/daft.py @@ -378,16 +378,22 @@ def _get_coords(self, ctx): dy0 = dy * (1. - alpha1 - alpha2) if self.node1.rectangle: - print self.node1.name # replace start coordinates (polar) - _, angle = cart2polar(dx0, dy0) - angle = angle + np.pi/2.0 - displacment_dist = radius1/abs(np.cos(angle)) - radius1 + length, angle = cart2polar(dx0, dy0) + if abs(angle)>np.pi*0.25 and abs(angle) Date: Sat, 15 Nov 2014 18:42:52 +0100 Subject: [PATCH 4/5] bug fix --- daft.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/daft.py b/daft.py index 68dfb2b..ad860ea 100644 --- a/daft.py +++ b/daft.py @@ -377,7 +377,7 @@ def _get_coords(self, ctx): dx0 = dx * (1. - alpha1 - alpha2) dy0 = dy * (1. - alpha1 - alpha2) - if self.node1.rectangle: + if self.node1.rectangle or self.node2.rectangle: # replace start coordinates (polar) length, angle = cart2polar(dx0, dy0) if abs(angle)>np.pi*0.25 and abs(angle) Date: Sun, 16 Nov 2014 14:10:14 +0100 Subject: [PATCH 5/5] bigfixes & add property double --- daft.py | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/daft.py b/daft.py index ad860ea..942ed3c 100644 --- a/daft.py +++ b/daft.py @@ -155,8 +155,13 @@ class Node(object): :param aspect: (optional) The aspect ratio width/height for elliptical nodes; default 1. - :param observed: (optional) - Should this be a conditioned variable? + :param rectangle: (optional) + If `True` node has a rectangular shape. + + :param double: (optional) + Double lines. This must be ``"inner"`` or ``"outer"``. + Node is shown as double shapes with the second shape plotted inside + or outside of the standard one, respectively. :param fixed: (optional) Should this be a fixed (not permitted to vary) variable? @@ -175,6 +180,7 @@ class Node(object): """ def __init__(self, name, content, x, y, scale=1, aspect=None, observed=False, fixed=False, rectangle=False, + double = "", offset=[0, 0], plot_params={}, label_params=None): # Node style. assert not (observed and fixed), \ @@ -182,6 +188,7 @@ def __init__(self, name, content, x, y, scale=1, aspect=None, self.observed = observed self.fixed = fixed self.rectangle = rectangle + self.double = double # Metadata. self.name = name @@ -257,26 +264,26 @@ def render(self, ctx): aspect = ctx.aspect # Set up an observed node. Note the fc INSANITY. - if self.observed: + if self.observed or self.double =="inner" or self.double=="outer": # Update the plotting parameters depending on the style of # observed node. h = float(diameter) w = aspect * float(diameter) - if ctx.observed_style == "shaded": + if ctx.observed_style == "shaded" and self.observed: p["fc"] = "0.7" - elif ctx.observed_style == "outer": + elif ctx.observed_style == "outer" or self.double == "outer": h = diameter + 0.1 * diameter w = aspect * diameter + 0.1 * diameter - elif ctx.observed_style == "inner": + elif ctx.observed_style == "inner" or self.double == "inner": h = diameter - 0.1 * diameter w = aspect * diameter - 0.1 * diameter p["fc"] = fc # Draw the background ellipse. if self.rectangle: - bg = Rectangle(xy=ctx.convert(self.x-w/2, self.y-h/2), - width=w, height=h, **p) - print "hi" + xy = np.array(ctx.convert(self.x, self.y)) - diameter/2.0 + xy = xy + (diameter-w)/float(2) + bg = Rectangle(xy=xy, width=w, height=h, **p) else: bg = Ellipse(xy=ctx.convert(self.x, self.y), width=w, height=h, **p) @@ -286,13 +293,13 @@ def render(self, ctx): p["fc"] = fc # Draw the foreground ellipse. - if ctx.observed_style == "inner" and not self.fixed and self.observed: + if ctx.observed_style == "inner" and not self.fixed and \ + (self.observed or self.double == "inner"): p["fc"] = "none" if self.rectangle: - xy = ctx.convert(self.x, self.y) - xy = (xy[0]-diameter/2.0, xy[1]-diameter/2.0) - el = Rectangle(xy=xy, - width=diameter * aspect, height=diameter, **p) + xy = np.array(ctx.convert(self.x, self.y)) - diameter/2.0 + el = Rectangle(xy=xy, width=diameter * aspect, + height=diameter, **p) else: el = Ellipse(xy=ctx.convert(self.x, self.y), width=diameter * aspect, height=diameter, **p) @@ -378,23 +385,22 @@ def _get_coords(self, ctx): dy0 = dy * (1. - alpha1 - alpha2) if self.node1.rectangle or self.node2.rectangle: - # replace start coordinates (polar) + # calc displacement of the edge (in direction of the edge) length, angle = cart2polar(dx0, dy0) if abs(angle)>np.pi*0.25 and abs(angle)