class Peer(visualizer.Peer): def __init__(self, *args): visualizer.Peer.__init__(self, *args) self.departure_position = None self.smoothed_branching_position = Smoother() self.segments = {} hue = random.uniform(0, 1) self.color = Vector3d(*(colorsys.hsv_to_rgb(hue, 0.35, 1))) def add_segment(self, segment): if self.departure_position is None: self.departure_position = segment.departure_position segment.peer = self segment.gathered = False self.segments[segment.id] = segment def update(self): for segment in self.segments.values(): if not segment.gathered and not segment.is_playing(): segment.f.gatherer.add(segment) segment.gathered = True outdated = filter(lambda segment_id: self.segments[segment_id].outdated(), self.segments) for segment_id in outdated: segment = self.segments[segment_id] del self.segments[segment_id] self.update_branching_position() def update_branching_position(self): if len(self.segments) == 0: self.smoothed_branching_position.reset() else: average_target_position = \ sum([segment.target_position() for segment in self.segments.values()]) / \ len(self.segments) new_branching_position = self.departure_position*0.4 + average_target_position*0.6 self.smoothed_branching_position.smooth( new_branching_position, self.visualizer.time_increment) def draw(self): if len(self.segments) > 0: for segment in self.segments.values(): segment.draw_playing() for segment in self.segments.values(): self.set_color(0) segment.draw_curve() def set_color(self, relative_age): if GREYSCALE: glColor3f(1 - CURVE_OPACITY, 1 - CURVE_OPACITY, 1 - CURVE_OPACITY) else: self.visualizer.set_color(self.color)
class Peer(visualizer.Peer): def __init__(self, *args): visualizer.Peer.__init__(self, *args) self.departure_position = None self.smoothed_branching_position = Smoother() self.segments = {} self.rightward = random.choice([True, False]) if self.rightward: x = 0 else: x = self.visualizer.width self.position = Vector2d( x, CURVE_MARGIN_Y * self.visualizer.height + \ random.uniform(0, (1-CURVE_MARGIN_Y*2) * self.visualizer.height)) def add_segment(self, segment): if self.departure_position is None: self.departure_position = segment.departure_position segment.peer = self segment.gathered = False self.segments[segment.id] = segment def update(self): for segment in self.segments.values(): if not segment.gathered and not segment.is_playing(): self.visualizer.gather(segment) segment.gathered = True outdated = filter(lambda segment_id: self.segments[segment_id].outdated(), self.segments) for segment_id in outdated: segment = self.segments[segment_id] del self.segments[segment_id] self.update_branching_position() def update_branching_position(self): if len(self.segments) == 0: self.smoothed_branching_position.reset() else: average_target_position = \ sum([segment.target_position() for segment in self.segments.values()]) / \ len(self.segments) new_branching_position = self.departure_position * RELATIVE_BRANCHING_POSITION \ + average_target_position * (1-RELATIVE_BRANCHING_POSITION) self.smoothed_branching_position.smooth( new_branching_position, self.visualizer.time_increment) def draw(self): if len(self.segments) > 0: for segment in self.segments.values(): segment.draw_playing()
class Segment(waves.Segment, heat_map.Segment): def __init__(self, *args): waves.Segment.__init__(self, *args) heat_map.Segment.__init__(self, *args) self._amp_smoother = Smoother(response_factor=2.5) def relative_size(self): age = self.age() if age > (self.duration - self._fade_time): return 1 - sigmoid(1 - (self.duration - age) / self._fade_time) else: self._amp_smoother.smooth( max([abs(value) for value in self.waveform]), self.visualizer.time_increment) return sigmoid(pow(max(self._amp_smoother.value(), 0), 0.25))
def test_smooth(self): s1 = Smoother([[0, 1], [1, 0]]) s1.smooth() self.assertEqual(s1._bmp, [[0 | SE, 1 | NW | SE], [1 | NW | SE, 0 | NW]]) s2 = Smoother([[1, 0, 0], [1, 0, 0], [1, 1, 1]]) s2.smooth() self.assertEqual(s2._bmp, [[1, 0, 0], [1, 0, 0], [1, 1, 1]]) s3 = Smoother([[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]]) s3.smooth() self.assertEqual(s3._bmp, [[0 | SE, 1 | NW, 1 | NE, 0 | SW], [1 | NW, 0 | NW, 0 | NE, 1 | NE], [1 | SW, 0 | SW, 0 | SE, 1 | SE], [0 | NE, 1 | SW, 1 | SE, 0 | NW]])
class Ancestry(visualizer.Visualizer, AncestryPlotter): def __init__(self, tr_log, pieces, args): visualizer.Visualizer.__init__(self, args) AncestryPlotter.__init__(self, tr_log.total_file_size(), tr_log.lastchunktime(), args) self._unfold_function = getattr(self, "_unfold_%s" % args.unfold) self._pre_render() self._autozoom = (args.geometry == CIRCLE and self.args.autozoom) if self._autozoom: self._max_pxy = 0 self._zoom_smoother = Smoother() @staticmethod def add_parser_arguments(parser): AncestryPlotter.add_parser_arguments(parser) visualizer.Visualizer.add_parser_arguments(parser) parser.add_argument("-z", dest="timefactor", type=float, default=1.0) def _pre_render(self): print "pre-rendering..." self._timeline = [] for piece in pieces: self.add_piece(piece["id"], piece["t"], piece["begin"], piece["end"]) frame = {"t": piece["t"], "tracker": copy.deepcopy(self._tracker), "num_pieces": self._num_pieces} self._timeline.append(frame) print "ok" def InitGL(self): visualizer.Visualizer.InitGL(self) glClearColor(0.0, 0.0, 0.0, 0.0) def ReSizeGLScene(self, width, height): visualizer.Visualizer.ReSizeGLScene(self, width, height) self._size = min(width, height) - 2*MARGIN AncestryPlotter.set_size(self, self._size, self._size) def render(self): glTranslatef(MARGIN + (self.width - self._size)/2, MARGIN, 0) glLineWidth(LINE_WIDTH * self.width) glEnable(GL_LINE_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glColor3f(1,1,1) self._unfold_function(self.current_time() * self.args.timefactor) frame = self._frame_at_cursor() self._activate_frame(frame) if self._autozoom: self._zoom = self._zoom_smoother.value() if self._zoom is None: self._zoom = 0.0 else: self._zoom = 1.0 self.plot() if self._autozoom: if self._max_pxy == 0: zoom = 0.5 else: zoom = 0.5 + self.cursor_t/self._duration * 0.5 / self._max_pxy self._zoom_smoother.smooth(zoom, self.time_increment) def _unfold_backward(self, t): self._cursor_t = self._duration - t % self._duration def _unfold_forward(self, t): self._cursor_t = t % self._duration def _frame_at_cursor(self): for frame in self._timeline: if frame["t"] >= self._cursor_t: return frame return self._timeline[-1] def _activate_frame(self, frame): self._num_pieces = frame["num_pieces"] self._tracker = frame["tracker"] # def _follow_piece(self, piece): # if len(piece.growth) > 0: # path = [(piece.t, # (piece.begin + piece.end) / 2)] # for older_version in reversed(piece.growth): # path.append((older_version.t, # (older_version.begin + older_version.end) / 2)) # self.draw_path(path) # for parent in piece.parents.values(): # if self.min_t < parent.t < self.max_t: # self._connect_child_and_parent( # piece.t, (piece.begin + piece.end) / 2, # parent.t, (parent.begin + parent.end) / 2) # self._follow_piece(parent) # else: # if self.args.unfold == BACKWARD: # t = self.cursor_t - pow(self.cursor_t - parent.t, 0.7) # else: # t = self.cursor_t # self._connect_child_and_parent( # piece.t, (piece.begin + piece.end) / 2, # t, (parent.begin + parent.end) / 2) def _rect_position(self, t, byte_pos): x = float(byte_pos) / self._total_size * self._width y = (1 - t / self._duration) * self._height return x, y def _circle_position(self, t, byte_pos): angle = float(byte_pos) / self._total_size * 2*math.pi rel_t = 1 - t / self._duration px = rel_t * math.cos(angle) py = rel_t * math.sin(angle) x = self._width / 2 + (px * self._zoom) * self._width / 2 y = self._height / 2 + (py * self._zoom) * self._height / 2 if self._autozoom: self._max_pxy = max([self._max_pxy, abs(px), abs(py)]) return x, y def draw_path(self, points): glBegin(GL_LINE_STRIP) for (t, b) in points: x, y = self._position(t, b) glVertex2f(x, y) glEnd() def draw_curve(self, x1, y1, x2, y2): control_points = [ Vector2d(x1, y1), Vector2d(x1 + (x2 - x1) * 0.3, y1), Vector2d(x1 + (x2 - x1) * 0.7, y2), Vector2d(x2, y2) ] bezier = make_bezier([(p.x, p.y) for p in control_points]) points = bezier(CURVE_PRECISION) glBegin(GL_LINE_STRIP) for x, y in points: glVertex2f(x, y) glEnd()
def test_vectorize_origin(self): s = Smoother([[0, 1], [1, 0]]) s.smooth() self.assertEqual(s.vectorize(10, -10), [[(10, 3), (23, -10), (30, -10), (30, -3), (17, 10), (10, 10)]])
def test_vectorize(self): s = Smoother([[0, 1], [1, 0]]) s.smooth() self.assertEqual(s.vectorize(), [[(0, 13), (13, 0), (20, 0), (20, 7), (7, 20), (0, 20)]])
def get_smoothed_sent_dist(address): sent_dist = sent_distributions.find_one({'address': address}) smitty = Smoother(sent_dist['sent_distribution'], 'total') smitty.smooth() smoothed_dist = smitty.to_objects() return smoothed_dist
def vectorize(self, smooth=True): s = Smoother(self._bitmap()) if smooth: s.smooth() return s.vectorize(MARGIN, -self.font.bdf[b'FONT_DESCENT'] * SCALE)
class Ancestry(visualizer.Visualizer, AncestryPlotter): def __init__(self, tr_log, pieces, args): visualizer.Visualizer.__init__(self, args) AncestryPlotter.__init__(self, tr_log.total_file_size(), tr_log.lastchunktime(), args) if args.unfold == BACKWARD: for piece in pieces: self.add_piece(piece["id"], piece["t"], piece["begin"], piece["end"]) elif args.unfold == FORWARD: self._remaining_pieces = copy.copy(pieces) self._autozoom = (args.geometry == CIRCLE and self.args.autozoom) if self._autozoom: self._max_pxy = 0 self._zoom_smoother = Smoother() if args.node_style == CIRCLE: self._node_plot_method = self._draw_node_circle self._nodes = {} else: self._node_plot_method = None if args.node_size_envelope: attack, decay, sustain = args.node_size_envelope.split(",") self._node_size_envelope = AdsrEnvelope( attack, decay, sustain, args.node_size_envelope_slope) else: self._node_size_envelope = None if args.sway_envelope: attack, decay, sustain = args.sway_envelope.split(",") self._sway_envelope = AdsrEnvelope(attack, decay, sustain) else: self._sway_envelope = None @staticmethod def add_parser_arguments(parser): AncestryPlotter.add_parser_arguments(parser) visualizer.Visualizer.add_parser_arguments(parser) parser.add_argument("-z", dest="timefactor", type=float, default=1.0) def InitGL(self): visualizer.Visualizer.InitGL(self) glClearColor(0.0, 0.0, 0.0, 0.0) if self.args.node_style == CIRCLE: self._node_circle_lists = [] for n in range(0, NODE_SIZE_PRECISION): display_list = self.new_display_list_id() self._node_circle_lists.append(display_list) glNewList(display_list, GL_COMPILE) self._render_node_circle(0, 0, n) glEndList() def ReSizeGLScene(self, width, height): visualizer.Visualizer.ReSizeGLScene(self, width, height) self._size = min(width, height) - 2*MARGIN AncestryPlotter.set_size(self, self._size, self._size) def render(self): glTranslatef(MARGIN + (self.width - self._size)/2, MARGIN, 0) glLineWidth(self.args.line_width) glEnable(GL_LINE_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glColor3f(1,1,1) if self.args.unfold == BACKWARD: self._cursor_t = self._duration - self._adjusted_current_time() % self._duration elif self.args.unfold == FORWARD: if self.args.ff: self._add_oldest_remaining_piece() else: while (len(self._remaining_pieces) > 0 and self._remaining_pieces[0]["t"] <= self._adjusted_current_time()): self._add_oldest_remaining_piece() if self._autozoom: self._zoom = self._zoom_smoother.value() if self._zoom is None: self._zoom = 0.0 else: self._zoom = 1.0 self.plot() if self._autozoom: if self._max_pxy == 0: zoom = 0.5 else: zoom = 0.5 + self._cursor_t/self._duration * 0.5 / self._max_pxy self._zoom_smoother.smooth(zoom, self.time_increment) def _add_oldest_remaining_piece(self): piece = self._remaining_pieces.pop(0) self.add_piece(piece["id"], piece["t"], piece["begin"], piece["end"]) def finished(self): return self.current_time() > (self._duration / self.args.timefactor + SUSTAIN_TIME) def _adjusted_current_time(self): return self.current_time() * self.args.timefactor def _follow_piece(self, piece, child=None): self._update_and_draw_node(piece, piece.t, (piece.begin + piece.end) / 2) if len(piece.growth) > 0: path = [(piece.t, (piece.begin + piece.end) / 2)] for older_version in reversed(piece.growth): if self.args.unfold == FORWARD or self._cursor_t < older_version.t: path.append((older_version.t, (older_version.begin + older_version.end) / 2)) self.draw_path(piece, path) self._update_and_draw_node(piece, path[-1][0], path[-1][1]) for parent in piece.parents.values(): if self.args.unfold == FORWARD or self._cursor_t < parent.t: self._connect_generations(parent, piece, child) self._follow_piece(parent, piece) else: if self.args.unfold == BACKWARD: t = self._cursor_t - pow(self._cursor_t - parent.t, 0.7) else: t = self._cursor_t self._connect_generations(parent, piece, child, t) self._update_and_draw_node(parent, t, (parent.begin + parent.end) / 2) def _rect_position(self, t, byte_pos): x = float(byte_pos) / self._total_size * self._width y = (1 - t / self._duration) * self._height return Vector2d(x, y) def _circle_position(self, t, byte_pos): angle = float(byte_pos) / self._total_size * 2*math.pi rel_t = 1 - t / self._duration px = rel_t * math.cos(angle) py = rel_t * math.sin(angle) x = self._width / 2 + (px * self._zoom) * self._width / 2 y = self._height / 2 + (py * self._zoom) * self._height / 2 if self._autozoom: self._max_pxy = max([self._max_pxy, abs(px), abs(py)]) return Vector2d(x, y) def draw_path(self, piece, points): if self.args.sway: piece_sway_magnitude = self._sway_magnitude(piece) glBegin(GL_LINE_STRIP) n = 0 for (t, b) in points: x, y = self._position(t, b) if self.args.sway: magnitude = (1 - float(n) / len(points)) * piece_sway_magnitude x += piece.sway.sway.x * magnitude * self._size y += piece.sway.sway.y * magnitude * self._size n += 1 glVertex2f(x, y) glEnd() def draw_curve(self, x1, y1, x2, y2): control_points = [ Vector2d(x1, y1), Vector2d(x1 + (x2 - x1) * 0.3, y1), Vector2d(x1 + (x2 - x1) * 0.7, y2), Vector2d(x2, y2) ] bezier = make_bezier([(p.x, p.y) for p in control_points]) points = bezier(CURVE_PRECISION) glBegin(GL_LINE_STRIP) for x, y in points: glVertex2f(x, y) glEnd() def draw_line(self, x1, y1, x2, y2): glBegin(GL_LINES) glVertex2f(x1, y1) glVertex2f(x2, y2) glEnd() def _update_and_draw_node(self, piece, t, b): if self.args.sway: self._update_sway(piece) if self._node_plot_method: self._node_plot_method(piece, t, b) def _update_sway(self, piece): if not hasattr(piece, "sway"): piece.sway = Sway(self.args.sway_magnitude) piece.sway.update(self.time_increment) def _draw_node_circle(self, piece, t, b): age = self._age(piece) size = self._node_size(age) cx, cy = self._position(t, b) if self.args.sway: piece_sway_magnitude = self._sway_magnitude(piece) cx += piece.sway.sway.x * piece_sway_magnitude * self._size cy += piece.sway.sway.y * piece_sway_magnitude * self._size glPushMatrix() glTranslatef(cx, cy, 0) glCallList(self._node_circle_lists[size]) glPopMatrix() def _age(self, piece): try: appearance_time = piece.appearance_time except AttributeError: appearance_time = piece.appearance_time = self._adjusted_current_time() return self._adjusted_current_time() - appearance_time def _node_size(self, age): if self._node_size_envelope: return int(self._node_size_envelope.value(age) * (NODE_SIZE_PRECISION-1)) else: return NODE_SIZE_PRECISION-1 def _sway_magnitude(self, piece): age = self._age(piece) if self._sway_envelope: return self._sway_envelope.value(age) else: return 1 def _render_node_circle(self, cx, cy, size): # glColor3f(0,0,0) # self._render_filled_circle(cx, cy, size) # glColor3f(1,1,1) # self._render_circle_outline(cx, cy, size) # glColor3f(1,1,1) # self._render_filled_circle(cx, cy, size) glColor3f(1,1,1) glEnable(GL_POINT_SMOOTH) radius = max(self.args.node_size * self.width * size / (NODE_SIZE_PRECISION-1), 0.1) glPointSize(radius * 2) glBegin(GL_POINTS) glVertex2f(cx, cy) glEnd() def _render_filled_circle(self, cx, cy, size): glBegin(GL_TRIANGLE_FAN) glVertex2f(cx, cy) angle = 0 radius = self.args.node_size * self.width * size / (NODE_SIZE_PRECISION-1) while angle < 2*math.pi: x = cx + math.cos(angle) * radius y = cy + math.sin(angle) * radius glVertex2f(x, y) angle += 0.1 x = cx + math.cos(0) * radius y = cy + math.sin(0) * radius glVertex2f(x, y) glEnd() def _render_circle_outline(self, cx, cy, size): glBegin(GL_LINE_STRIP) angle = 0 radius = self.args.node_size * self.width * size / (NODE_SIZE_PRECISION-1) while angle < 2*math.pi: x = cx + math.cos(angle) * radius y = cy + math.sin(angle) * radius glVertex2f(x, y) angle += 0.1 glEnd()