def plotWord(self,diagram,word,w,h,col,x,y,flip): self.plots.append((x,y,w,h)) r = rectangle(x,y,w,h,fill="#FFF") diagram.add(r) fs = h*0.8 tl = w*0.8 if flip: fs = w*0.8 tl = h*0.8 t = text(x+w*0.1,y+h*0.1,word) t.addStyle("text-anchor","start") t.addAttr("dominant-baseline","hanging") t.addAttr("font-size",fs) t.addAttr("textLength",tl) t.addAttr("fill",col) t.addAttrs(self.text_attributes) if flip: t.addAttr("writing-mode","tb") diagram.add(t)
def draw(self,d,ox,oy): legend_column_width = self.width / self.legend_columns legend_y = oy legend_x = ox - (self.width/2) col = 0 for (category, colour) in self.palette: g = self.legend_font_height points = [(legend_x, legend_y), (legend_x + g, legend_y), (legend_x + g, legend_y + g), (legend_x, legend_y + g)] d.add(polygon(points, colour, "black", 2)) t = text(legend_x+1.5*g, legend_y+g/2, self.labels[category]) t.addStyle("font-size", self.legend_font_height) t.addStyle("text-anchor", "start") t.addStyle("alignment-baseline", "middle") t.addStyles(self.legend_text_style) d.add(t) col += 1 if col >= self.legend_columns: legend_y += 2 * g legend_x = ox - (self.width/2) col = 0 else: legend_x += legend_column_width
def draw_subtree(self, diagram, data, xc, yc, w, h): if isinstance(data, tuple): r = rectangle(xc, yc, w, h, fill=self.palette_lookup[data[0]], tooltip=self.labels[data[0]]) diagram.add(r) fraction = data[1] / self.sumtotal t = text(xc + w * 0.02, yc + h * 0.02, "%.2f" % (100 * fraction) + "%") t.addStyle("text-anchor", "start") t.addAttr("dominant-baseline", "hanging") t.addAttrs(self.text_attributes) diagram.add(t) else: totals = [] for d in data: totals.append(self.total(d)) sumtotal = sum(totals) if w < h: # divide vertically y = yc for idx in range(len(data)): sh = h * (totals[idx] / sumtotal) self.draw_subtree(diagram, data[idx], xc, y, w, sh) y += sh else: x = xc for idx in range(len(data)): sw = h * (totals[idx] / sumtotal) self.draw_subtree(diagram, data[idx], x, yc, sw, h) x += sw r = rectangle(xc, yc, w, h, stroke="black", stroke_width=4) diagram.add(r)
def draw(self, d, ox, oy): height = self.height / len(self.keys) ay = 0 plot_width = self.width / len(self.axes) if len(self.axis_labels): ay = self.axis_label_height for axis in range(0, len(self.axes) + 1): axis_label_x = (ox - self.width / 2) + axis * plot_width axis_label_y = oy t = text(axis_label_x, axis_label_y, self.axis_labels[axis]) t.addStyle("font-size", self.axis_label_height) if axis == 0: pos = "start" elif axis == len(self.axes): pos = "end" else: pos = "middle" t.addStyle("text-anchor", pos) d.add(t) grp = group() d.add(grp) for axis in range(0, len(self.axes)): axis_x0 = (ox - self.width / 2) + axis * plot_width axis_x1 = (ox - self.width / 2) + (axis + 1) * plot_width points0 = self.axes[axis][0] points1 = self.axes[axis][1] state = None for idx in range(0, len(points0)): key = points0[idx] cat0 = self.data[key][axis] cat1 = self.data[key][axis + 1] oidx = points1.index(key) if state == None: state = (cat0, cat1, (idx, idx), (oidx, oidx)) else: (pcat0, pcat1, (pidx_min, pidx_max), (poidx_min, poidx_max)) = state if cat0 == pcat0 and cat1 == pcat1: state = (cat0, cat1, (pidx_min, idx), (min(oidx, poidx_min), max(oidx, poidx_max))) else: count = 1 + pidx_max - pidx_min self.drawConnection( d, grp, axis_x0, axis_x1, ay + oy, 100, height, state, self.getLabel(pcat0) + "=>" + self.getLabel(pcat1) + "(%d seats)" % (count)) state = (cat0, cat1, (idx, idx), (oidx, oidx)) if state != None: (pcat0, pcat1, (pidx_min, pidx_max), (poidx_min, poidx_max)) = state count = 1 + pidx_max - pidx_min self.drawConnection( d, grp, axis_x0, axis_x1, ay + oy, 100, height, state, pcat0 + "=>" + pcat1 + "(%d seats)" % (count))
def draw(self, diagram, ox, oy): xc = ox - self.width / 2 yc = oy coords = {} nodes = self.data[0] links = self.data[1] node_links = {} distance = lambda x1, y1, x2, y2: sqrt((x1 - x2)**2 + (y1 - y2)**2) def clip(coords): (x, y, r) = coords if x < xc + r: x = xc + r if y < yc + r: y = yc + r if x > xc + self.width - r: x = xc + self.width - r if y > yc + self.height - r: y = yc + self.height - r return (x, y, r) for (nodeid0, nodeid1, weight) in links: if nodeid0 not in node_links: node_links[nodeid0] = [] if nodeid1 not in node_links: node_links[nodeid1] = [] node_links[nodeid0].append(nodeid1) node_links[nodeid1].append(nodeid0) for (nodeid, cat, value) in nodes: frac = value / self.sumtotal area = self.width * self.height * 0.25 * frac r = sqrt(area / pi) cx = xc + r + (self.width - 2 * r) * random.random() cy = yc + r + (self.height - 2 * r) * random.random() coords[nodeid] = (cx, cy, r) c1 = 2 c3 = 1 c4 = 0.1 c5 = 100 iters = 50000 for iter in range(iters): forces = {} for (nodeid, cat, value) in nodes: forces[nodeid] = (0, 0) (nx, ny, nr) = coords[nodeid] if nodeid in node_links: for adjid in node_links[nodeid]: (ax, ay, adjr) = coords[adjid] c2 = (nr + adjr) * 2 d = distance(nx, ny, ax, ay) f = c1 * log(d / c2) fx = ((ax - nx) / d) * f * c4 fy = ((ay - ny) / d) * f * c4 forces[nodeid] = (forces[nodeid][0] + fx, forces[nodeid][1] + fy) for otherid in coords: if otherid != nodeid: (ox, oy, otherr) = coords[otherid] d = distance(nx, ny, ox, oy) f = c3 / (d**2) fx = ((nx - ox) / d) * f * c5 fy = ((ny - oy) / d) * f * c5 forces[nodeid] = (forces[nodeid][0] + fx, forces[nodeid][1] + fy) for nodeid in coords: coords[nodeid] = (coords[nodeid][0] + forces[nodeid][0], coords[nodeid][1] + forces[nodeid][1], coords[nodeid][2]) coords[nodeid] = clip(coords[nodeid]) for (nodeid0, nodeid1, weight) in links: (x1, y1, r1) = coords[nodeid0] (x2, y2, r2) = coords[nodeid1] l = line(x1, y1, x2, y2, self.getLinkColour(weight), 3) diagram.add(l) for (nodeid, cat, value) in nodes: (cx, cy, r) = coords[nodeid] col = self.palette_lookup[cat] circ = circle(cx, cy, r, col) circ.addAttr("stroke", "#EEE") circ.addAttr("stroke-width", 4) diagram.add(circ) if nodeid in self.labels: label = self.labels[nodeid] length = len(label) t = text(cx, cy, label) font_height = 2 * r * 0.8 / length text_length = font_height * length t.addAttr("textLength", text_length) t.addAttr("font-size", font_height) t.addAttrs(self.text_attributes) diagram.add(t)
def renderGrid(self, diagram, ox, oy, dlength, scores): rangle = radians(30) off_sm = dlength * sin(rangle) off_lg = dlength * cos(rangle) hx = ox labels = [] js = javascript_snippet(""" function toggleVisibility(cls) { var found = document.getElementsByClassName(cls); for(var idx=0; idx<found.length; idx++) { if (found[idx].getAttribute("visibility") == "hidden") { found[idx].setAttribute("visibility","visible"); } else { found[idx].setAttribute("visibility","hidden"); } } } """) diagram.add(js) for xc in range(0, self.gx): hy = oy for yc in range(0, self.gy): y = hy x = hx if yc % 2 == 1: x += off_lg poly = self.hexagon((x, y), dlength, "#E0E0E0", (128, 128, 128), str(xc) + "_" + str(yc)) poly.addStyle("stroke", "grey") poly.addStyle("stroke-width", "3") cls = str(xc) + "_" + str(yc) poly.addAttr("onclick", "toggleVisibility(\"" + cls + "\")") diagram.add(poly) centroid = self.plot.getWeights(self.plot.getOutput(xc, yc)) assigned = scores[(xc, yc)] if assigned: centroid_sum = sum(centroid) theta = 0 cx = x cy = y - dlength / 2 r1 = dlength * 0.5 r2 = dlength * 0.7 r3 = r2 + 10 for idx in range(0, len(centroid)): theta0 = theta theta += 2 * pi * centroid[idx] / centroid_sum s = sector(cx, cy, 0, r1, theta0, theta, self.plot.palette[idx][0]) s.addStyle("fill", self.plot.palette[idx][1]) s.addAttr("onclick", "toggleVisibility(\"" + cls + "\")") diagram.add(s) assigned = sorted(assigned, key=lambda x: x[1]) theta = 0 step = pi * 2 / len(assigned) if step > 1.0: step = 1.0 for (label, colour) in assigned: px = cx + r2 * cos(theta) py = cy + r2 * sin(theta) pxl = cx + r3 * cos(theta) pyl = cy + r3 * sin(theta) c = circle(px, py, dlength * 0.1, colour, label) t = text(pxl, pyl, label) t.addAttr("dominant-baseline", "middle") t.addStyle("paint-order", "stroke") t.addStyle("fill", colour) t.addStyle("stroke-width", "10px") t.addStyle("stroke", "white") if theta > pi / 2 and theta < pi * 1.5: t.addStyle("text-anchor", "end") t.setRotation(theta - pi) else: t.addStyle("text-anchor", "start") t.setRotation(theta) t.addAttr("visibility", "hidden") t.addAttr("class", cls) diagram.add(c) labels.append(t) theta += step hy = hy + dlength + off_sm hx = hx + 2 * off_lg for label in labels: diagram.add(label) return (ox + off_lg + self.gx * (2 * off_lg) + 10, oy + off_sm + (self.gy) * (dlength + off_sm) + 10)