1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
from __future__ import with_statement
from numpy import empty
from enthought.traits.api import Property, Enum
# Local imports
from lineplot import LinePlot
from polygon_plot import PolygonPlot
def Alias(name):
return Property(lambda obj: getattr(obj, name),
lambda obj, val: setattr(obj, name, val))
class FilledLinePlot(PolygonPlot):
""" Draws a line plot filled to the axis """
fill_color = Alias("face_color")
# Direction to fill. Down is towards the origin, up is towards the max
fill_direction = Enum("down", "up")
# The rendering style of the line plot.
#
# connectedpoints
# "normal" style (default); each point is connected to subsequent and
# prior points by line segments
# hold
# each point is represented by a line segment parallel to the abscissa
# (index axis) and spanning the length between the point and its
# subsequent point.
# connectedhold
# like "hold" style, but line segments are drawn at each point of the
# plot to connect the hold lines of the prior point and the current
# point. Also called a "right angle plot".
render_style = Enum("connectedpoints", "hold", "connectedhold")
def _render(self, gc, points):
if len(points) == 0:
return
render_method_dict = {
"hold": LinePlot._render_hold,
"connectedhold": LinePlot._render_connected_hold,
"connectedpoints": LinePlot._render_normal
}
render_lines = render_method_dict.get(self.render_style, LinePlot._render_normal)
if self.fill_direction == 'down':
ox, oy = self.map_screen([[0,0]])[0]
else:
ox, oy = self.map_screen([[self.x_mapper.range.high,
self.y_mapper.range.high]])[0]
with gc:
gc.clip_to_rect(self.x, self.y, self.width, self.height)
# If the fill color is not transparent, then draw the fill polygon first
face_col = self.face_color_
if not (len(face_col) == 4 and face_col[-1] == 0):
if self.render_style in ("hold","connectedhold"):
# Modify the points array before passing it in to render_polys:
# Between every two points, create an intermediate point with
# the first point's Y and the second point's X. (For vertical
# plots, use the first point's X and the second point's Y.)
new_points = empty((points.shape[0]*2-1, 2))
new_points[::2] = points
if self.orientation == "h":
new_points[1::2,0] = points[1:,0]
new_points[1::2,1] = points[:-1,1]
else:
new_points[1::2,0] = points[:-1,0]
new_points[1::2,1] = points[1:,1]
points = new_points
self._render_polys(gc, points, ox, oy)
# If the line color is not transparent, or tha same color
# as the filled area:
edge_col = self.edge_color_
if (not (len(edge_col) == 4 and edge_col[-1] == 0)) and edge_col != face_col:
gc.set_stroke_color(edge_col)
gc.set_line_width(self.edge_width)
gc.set_line_dash(self.edge_style_)
# Create a list around points because the LinePlot supports
# Nans, and its rendering methods expect lists of disjoint arrays.
render_lines(gc, [points], self.orientation)
def _render_polys(self, gc, points, ox, oy):
face_col = self.face_color_
gc.set_fill_color(face_col)
gc.begin_path()
startx, starty = points[0]
if self.orientation == "h":
gc.move_to(startx, oy)
gc.line_to(startx, starty)
else:
gc.move_to(ox, starty)
gc.line_to(startx, starty)
gc.lines(points)
endx, endy = points[-1]
if self.orientation == "h":
gc.line_to(endx, oy)
gc.line_to(startx, oy)
else:
gc.line_to(ox, endy)
gc.line_to(ox, starty)
gc.close_path()
gc.fill_path()
|