plotext-plus 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
plotext_plus/_build.py ADDED
@@ -0,0 +1,270 @@
1
+ import plotext_plus._utility as ut
2
+ import math
3
+
4
+ # this file builds a class inherited by the monitor_class() in _monitor.py just because its only method - build_plot() - is very long and it is the core of plot building and it is written separately for clarity
5
+
6
+ class build_class():
7
+
8
+ def build_plot(self): # it builds the plot given the external settings and internal settings collected in draw()
9
+
10
+ # Initial Tools
11
+ r2 = [0, 1]
12
+ signals = len(self.x); Signals = list(range(signals))
13
+ texts = len(self.text); Texts = list(range(texts))
14
+ width, height = self.size
15
+ ticks_colors = self.ticks_color, self.ticks_style
16
+
17
+ # Find if Axes are used
18
+ xside = [(self.default.xside[i] in self.xside + self.txside) or self.vcoord[i] != [] for i in r2]
19
+ yside = [(self.default.yside[i] in self.yside + self.tyside) or self.hcoord[i] != [] for i in r2]
20
+
21
+ # Remove Useless X and Y Ticks and Labels if axes are not used
22
+ self.xticks = [self.xticks[i] if xside[i] else None for i in r2]
23
+ self.xlabels = [self.xlabels[i] if xside[i] else None for i in r2]
24
+
25
+ self.yticks = [self.yticks[i] if yside[i] else None for i in r2]
26
+ self.ylabels = [self.ylabels[i] if yside[i] else None for i in r2]
27
+
28
+ # Remove Useless h and v user defined Lines if axes are not used
29
+ self.hcoord = [self.hcoord[i] if yside[i] else [] for i in r2]
30
+ self.vcoord = [self.vcoord[i] if xside[i] else [] for i in r2]
31
+ self.hcolors = [self.hcolors[i] if yside[i] else [] for i in r2]
32
+ self.vcolors = [self.vcolors[i] if xside[i] else [] for i in r2]
33
+
34
+ # Apply Scale (linear or log) to the data
35
+ xscale = [ut.get_first(self.xscale, self.xside[s] is self.default.xside[0]) for s in Signals] # the x scale for each signal
36
+ yscale = [ut.get_first(self.yscale, self.yside[s] is self.default.yside[0]) for s in Signals] # the y scale for each signal
37
+ self.x = [ut.apply_scale(self.x[s], xscale[s] is self.default.xscale[1]) for s in Signals] # apply optional log scale
38
+ self.y = [ut.apply_scale(self.y[s], yscale[s] is self.default.yscale[1]) for s in Signals]
39
+
40
+ # Apply Scale (linear or log) to the Axes Ticks
41
+ self.xticks = [ut.apply_scale(self.xticks[i], self.xscale[i] is self.default.xscale[1]) if self.xticks[i] is not None else None for i in r2] # apply optional log scale
42
+ self.yticks = [ut.apply_scale(self.yticks[i], self.yscale[i] is self.default.yscale[1]) if self.yticks[i] is not None else None for i in r2] # apply optional log scale
43
+
44
+ # Apply Scale (linear or log) to the user defined Lines
45
+ self.hcoord = [ut.apply_scale(self.hcoord[i], self.yscale[i] is self.default.yscale[1]) for i in r2] # apply optional log scale
46
+ self.vcoord = [ut.apply_scale(self.vcoord[i], self.xscale[i] is self.default.xscale[1]) for i in r2] # apply optional log scale
47
+
48
+ # Apply Scale (linear or log) to the user defined Text
49
+ txscale = [ut.get_first(self.xscale, self.txside[s] is self.default.xside[0]) for s in Texts] # the x scale for each text
50
+ tyscale = [ut.get_first(self.yscale, self.tyside[s] is self.default.yside[0]) for s in Texts] # the y scale for each text
51
+ self.tx = [ut.apply_scale([self.tx[s]], txscale[s] is self.default.xscale[1])[0] for s in Texts] #if width_canvas * height_canvas > 0 else [] # apply optional log scale
52
+ self.ty = [ut.apply_scale([self.ty[s]], tyscale[s] is self.default.yscale[1])[0] for s in Texts] #if width_canvas * height_canvas > 0 else [] # apply optional log scale
53
+ tx = [[self.tx[s] for s in Texts if self.txside[s] is self.default.xside[i]] for i in r2] # text x coord for each axis
54
+ ty = [[self.ty[s] for s in Texts if self.tyside[s] is self.default.yside[i]] for i in r2] # text x coofor each axis
55
+
56
+ # Get X Axes Limits
57
+ x = [ut.join([self.x[s] for s in Signals if self.xside[s] is side]) for side in self.default.xside] # total x data for each axis
58
+ x = [x[i] + self.vcoord[i] + tx[i] for i in r2] # add v lines and text coords to calculate xlim
59
+ xlim = [ut.get_lim(el) if len(el) > 0 else [None, None] for el in x]
60
+ self.xlim = [ut.replace_none(self.xlim[i], xlim[i]) for i in r2]
61
+ self.xlim = [self.xlim[i][:: self.xdirection[i]] for i in r2] # optionally reverse axes
62
+ xlim = [self.xlim[0] if self.xside[s] == self.default.xside[0] else self.xlim[1] for s in Signals] # xlim for each signal
63
+
64
+ # Get Y Axes Limits
65
+ y = [ut.join([self.y[s] for s in Signals if self.yside[s] is side]) for side in self.default.yside]
66
+ y = [y[i] + self.hcoord[i] + ty[i] for i in r2] # add h lines and text coords to calculate ylim
67
+ ylim = list(map(ut.get_lim, y))
68
+ self.ylim = [ut.replace_none(self.ylim[i], ylim[i]) for i in r2]
69
+ self.ylim = [self.ylim[i][:: self.ydirection[i]] for i in r2] # optionally reverse axes
70
+ ylim = [self.ylim[0] if self.yside[s] == self.default.yside[0] else self.ylim[1] for s in Signals] # ylim for each signal
71
+
72
+ # Get Y Ticks and Labels
73
+ yticks_to_set = [self.yticks[i] is None and yside[i] and len(y[i]) > 0 for i in r2]
74
+ yticks = [ut.linspace(*self.ylim[i], self.yfrequency[i]) if yticks_to_set[i] else self.yticks[i] for i in r2] # the actual Y ticks
75
+ yticks_rescaled = [ut.reverse_scale(yticks[i], self.yscale[i] is self.default.yscale[1]) for i in r2]
76
+
77
+ ylabels = [self.date.times_to_string(yticks_rescaled[i]) if self.y_date[i] else ut.get_labels(yticks_rescaled[i]) if yticks_to_set[i] else self.ylabels[i] for i in r2]
78
+ ylabels = [ut.add_extra_spaces(ylabels[i], self.default.yside[i]) if ylabels[i] is not None else None for i in r2]
79
+ width_ylabels = [ut.max_length(el) if el is not None else 0 for el in ylabels]
80
+
81
+ # Get X Ticks and Labels
82
+ xticks_to_set = [self.xticks[i] is None and xside[i] and len(x[i]) > 0 for i in r2]
83
+ xticks = [ut.linspace(*self.xlim[i], self.xfrequency[i]) if xticks_to_set[i] else self.xticks[i] for i in r2] # the actual X ticks
84
+ xticks_rescaled = [ut.reverse_scale(xticks[i], self.xscale[i] is self.default.xscale[1]) for i in r2]
85
+ xlabels = [self.date.times_to_string(xticks_rescaled[i]) if self.x_date[i] else ut.get_labels(xticks_rescaled[i]) if xticks_to_set[i] else self.xlabels[i] for i in r2]
86
+ xlabels = [ut.add_extra_spaces(xlabels[i], self.default.xside[i]) if xticks_to_set[i] else self.xlabels[i] for i in r2]
87
+ height_xlabels = [len(el) > 0 if el is not None else 0 for el in xlabels]
88
+
89
+ # Canvas Dimensions (the area of data points)
90
+ width_canvas = width - sum(self.yaxes) - sum(width_ylabels)
91
+ height_highbar = any([el is not None for el in [self.title, self.xlabel[1]]])
92
+ height_lowbar = any([el is not None for el in self.ylabel + [self.xlabel[0]]])
93
+ height_canvas = height - sum(self.xaxes) - sum(height_xlabels) - height_highbar - height_lowbar
94
+
95
+ # Canvas Offset
96
+ col_start = width_ylabels[0] + self.yaxes[0]
97
+ col_end = col_start + width_canvas
98
+ row_start = height_lowbar + height_xlabels[0] + self.xaxes[0]
99
+ row_end = row_start + height_canvas
100
+
101
+ # Get Absolute X and Y Ticks
102
+ cticks = [ut.get_matrix_data(xticks[i], self.xlim[i], width_canvas) if xticks[i] != None else [] for i in r2]
103
+ rticks = [ut.get_matrix_data(yticks[i], self.ylim[i], height_canvas) if yticks[i] != None else [] for i in r2]
104
+
105
+ # Get Absolute Coordinates for user defined Lines
106
+ hticks = [ut.get_matrix_data(self.hcoord[i], self.ylim[i], height_canvas) if None not in self.ylim[i] else [] for i in r2]
107
+ vticks = [ut.get_matrix_data(self.vcoord[i], self.xlim[i], width_canvas) if None not in self.xlim[i] else [] for i in r2]
108
+
109
+ # Get Absolute Coordinates for user defined Text
110
+ txlim = [ut.get_first(self.xlim, self.txside[s] == self.default.xside[0]) for s in Texts] # xlim for each text
111
+ tylim = [ut.get_first(self.ylim, self.tyside[s] == self.default.yside[0]) for s in Texts] # xlim for each text
112
+ tcticks = [ut.get_matrix_data([self.tx[s]], txlim[s], width_canvas)[0] if width_canvas > 0 else 0 for s in Texts] #if width_canvas > 0 else [] #
113
+ trticks = [ut.get_matrix_data([self.ty[s]], tylim[s], height_canvas)[0] if height_canvas > 0 else 0 for s in Texts] #if height_canvas > 0 else [] #
114
+
115
+ # Get effective number of User Lines
116
+ hlines = [len(el) for el in hticks]; Hlines = [list(range(el)) for el in hlines] # number of user defined horizontal lines for each y axis (as list)
117
+ vlines = [len(el) for el in vticks]; Vlines = [list(range(el)) for el in vlines] # number of user defined vertical lines for each x axis (as list)
118
+
119
+ # Create Matrix of Markers
120
+ self.matrix.set_size(width, height)
121
+ self.matrix.set_axes_color(self.axes_color)
122
+ self.matrix.set_canvas_area(col_start, col_end, row_start, row_end)
123
+ self.matrix.set_canvas_color(self.canvas_color)
124
+ self.matrix.set_matrices()
125
+
126
+ # Add Title
127
+ col_center = col_start + width_canvas // 2 # centered on the canvas not the entire plot
128
+ col_title = col_center if self.xlabel[1] is None else 0
129
+ row_title = row_end + self.xaxes[1] + height_xlabels[1]
130
+ alignment_title = "center" if self.xlabel[1] is None else "left"
131
+ self.matrix.add_horizontal_string(col_title, row_title, self.title, *ticks_colors, alignment = alignment_title, check_space = True) if self.title and height > 0 else None
132
+
133
+ # Add Upper X Label
134
+ self.matrix.add_horizontal_string(col_center, row_title, self.xlabel[1], *ticks_colors, alignment = "center", check_space = True) if self.xlabel[1] and height > 0 else None
135
+
136
+ # Add Lower X Ticks
137
+ row_xticks = min(row_start - self.xaxes[0] - 1, height - 1)
138
+ cticks_inserted = [height > 0 and self.matrix.add_horizontal_string(col_start + cticks[0][i], row_xticks, xlabels[0][i], *ticks_colors, alignment = "dynamic", check_space = True) for i in range(len(cticks[0]))]
139
+ cticks[0] = [cticks[0][i] for i in range(len(cticks[0])) if cticks_inserted[i]] # it updates the x ticks coordinates whatever x labels were inserted
140
+
141
+ # Add Upper X Ticks: the reason to do it here prematurely, is that the cticks[1] need to be re-evaluated for next step
142
+ row_xticks = row_end + self.xaxes[1]
143
+ cticks_inserted = [height > 0 and self.matrix.add_horizontal_string(col_start + cticks[1][i], row_xticks, xlabels[1][i], *ticks_colors, alignment = "dynamic", check_space = True) for i in range(len(cticks[1]))]
144
+ cticks[1] = [cticks[1][i] for i in range(len(cticks[1])) if cticks_inserted[i]] # it updates the x ticks coordinates whatever x labels were inserted
145
+
146
+ # Add Upper X Axes (from previous step)
147
+ tick = lambda i: '┼' if (self.grid[1] and i in cticks[1]) else '┬' if (self.grid[1] and i in cticks[0] or i in ut.join(vticks)) else '┴' if i in cticks[1] else '─'
148
+ xaxis = [tick(i) for i in range(width_canvas)]
149
+ self.matrix.add_horizontal_string(col_start, row_end, xaxis, self.ticks_color) if self.xaxes[0] and height_canvas >= -1 else None
150
+
151
+ # Add Left Y Ticks
152
+ [self.matrix.add_horizontal_string(0, rticks[0][i] + row_start, ylabels[0][i], *ticks_colors) for i in range(len(rticks[0]))] if width >= width_ylabels[0] else None
153
+
154
+ # Add Left Y Axis
155
+ tick = lambda i: '┼' if (self.grid[0] and i in rticks[0]) else '├' if (self.grid[0] and i in rticks[1] or i in ut.join(hticks)) else '┤' if i in rticks[0] else '│'
156
+ yaxis = [tick(i) for i in range(height_canvas)]
157
+ col_yaxis = width_ylabels[0]
158
+ self.matrix.add_vertical_string(col_yaxis, row_start, yaxis, self.ticks_color) if self.yaxes[0] and width >= sum(width_ylabels) + 1 else None
159
+
160
+ # Add Right Y Axis
161
+ tick = lambda i: '┼' if (self.grid[0] and i in rticks[1]) else '┤' if (self.grid[0] and i in rticks[0] or i in ut.join(hticks)) else '├' if i in rticks[1] else '│'
162
+ yaxis = [tick(i) for i in range(height_canvas)]
163
+ self.matrix.add_vertical_string(col_end, row_start, yaxis, self.ticks_color) if self.yaxes[1] and width >= sum(width_ylabels) + self.yaxes[0] + 1 else None
164
+
165
+ # Add Right Y Ticks
166
+ [self.matrix.add_horizontal_string(col_end + 1, rticks[1][i] + row_start, ylabels[1][i], *ticks_colors) for i in range(len(rticks[1]))] if width >= sum(width_ylabels) + 1 else None
167
+
168
+ # Add Frame 4 Corners if necessary
169
+ canvas_test = height_canvas >= 0 and width_canvas >= 0
170
+ self.matrix.insert_element(col_start - 1, row_start - 1, '└', self.ticks_color) if self.xaxes[0] and self.yaxes[0] and canvas_test else None
171
+ self.matrix.insert_element(col_end, row_start - 1, '┘', self.ticks_color) if self.xaxes[0] and self.yaxes[1] and canvas_test else None
172
+ self.matrix.insert_element(col_start - 1, row_end, '┌', self.ticks_color) if self.xaxes[1] and self.yaxes[0] and canvas_test else None
173
+ self.matrix.insert_element(col_end, row_end, '┐', self.ticks_color) if self.xaxes[1] and self.yaxes[1] and canvas_test else None
174
+
175
+ # Add Lower X Axes (from previous step)
176
+ tick = lambda i: '┼' if (self.grid[1] and i in cticks[0]) else '┴' if (self.grid[1] and i in cticks[1] or i in ut.join(vticks)) else '┬' if i in cticks[0] else '─'
177
+ xaxis = [tick(i) for i in range(width_canvas)]
178
+ self.matrix.add_horizontal_string(col_start, row_start - 1, xaxis, self.ticks_color) if self.xaxes[0] and height_canvas >= -1 else None
179
+
180
+ # Add Left Y Label
181
+ self.matrix.add_horizontal_string(0, 0, self.ylabel[0], *ticks_colors, check_space = True) if self.ylabel[0] and height > 0 else None
182
+
183
+ # Add Right Y Label
184
+ self.matrix.add_horizontal_string(width - 1, 0, self.ylabel[1], *ticks_colors, check_space = True, alignment = "right") if self.ylabel[1] and height > 0 else None
185
+
186
+ # Add Lower X Label
187
+ self.matrix.add_horizontal_string(col_center, 0, self.xlabel[0], *ticks_colors, alignment = "center", check_space = True) if self.xlabel[0] and height > 0 else None
188
+
189
+ # Add Grid Lines
190
+ hline = '─' * width_canvas
191
+ [self.matrix.add_horizontal_string(0 + col_start, row + row_start, hline, self.ticks_color) for row in ut.join(rticks) if self.grid[0]]
192
+ vline = '│' * height_canvas
193
+ [self.matrix.add_vertical_string(col + col_start, 0 + row_start, vline, self.ticks_color) for col in ut.join(cticks) if self.grid[1]]
194
+ [self.matrix.insert_element(col + col_start, row + row_start, '┼') for row in ut.join(rticks) for col in ut.join(cticks) if all(self.grid)] # deals with the crossing between grids
195
+
196
+ # Add user defined Lines
197
+ [[self.matrix.add_horizontal_string(col_start, hticks[i][l] + row_start, hline, self.hcolors[i][l]) for l in Hlines[i]] for i in r2]
198
+ [[self.matrix.add_vertical_string(vticks[i][l] + col_start, 0 + row_start, vline, self.vcolors[i][l]) for l in Vlines[i]] for i in r2]
199
+ [[[self.matrix.insert_element(col + col_start, hticks[i][l] + row_start, '┼', self.hcolors[i][l]) for l in Hlines[i]] for i in r2] for col in ut.join(cticks) if self.grid[1]] # deals with the crossing between h lines and v grids
200
+ [[[self.matrix.insert_element(vticks[i][l] + col_start, row + row_start, '┼', self.vcolors[i][l]) for l in Vlines[i]] for i in r2] for row in ut.join(rticks) if self.grid[0]] # deals with the crossing between v lines and h grids
201
+ [[[[self.matrix.insert_element(col_start + vticks[iv][lv], hticks[i][l] + row_start, '┼', self.hcolors[i][l]) for l in Hlines[i]] for i in r2] for lv in Vlines[iv]] for iv in r2] # deals with the crossing between h and v lines
202
+
203
+ # Expand Canvas to accommodate HD markers
204
+ xf = [max([ut.marker_factor(el, 2, 2, 2) for el in self.marker[s]], default = 1) for s in Signals]
205
+ yf = [max([ut.marker_factor(el, 2, 3, 4) for el in self.marker[s]], default = 1) for s in Signals]
206
+ width_expanded = [width_canvas * el for el in xf]
207
+ height_expanded = [height_canvas * el for el in yf]
208
+
209
+ # Get Relative Data to Be Plotted on Matrix
210
+ test_canvas = [width_expanded[s] * width_expanded[s] for s in Signals]
211
+ x = [ut.get_matrix_data(self.x[s], xlim[s], width_expanded[s]) if test_canvas[s] else [] for s in Signals]
212
+ y = [ut.get_matrix_data(self.y[s], ylim[s], height_expanded[s]) if test_canvas[s] else [] for s in Signals]
213
+ m, c, st = self.marker, self.color, self.style
214
+
215
+
216
+ # Add Lines between Data Points
217
+ x, y, m, c, st = ut.transpose([ut.get_lines(x[s], y[s], m[s], c[s], st[s]) if self.lines[s] else (x[s], y[s], m[s], c[s], st[s]) for s in Signals], 5)
218
+
219
+ # Fillx
220
+ #x, y, m, c, st = ut.transpose([ut.brush(x[s], y[s], m[s], c[s], st[s]) for s in Signals], 5)
221
+ level = [ut.get_fill_level(self.fillx[s], ylim[s], height_expanded[s]) for s in Signals]
222
+ x, y, m, c, st = ut.transpose([ut.fill_data(x[s], y[s], level[s], m[s], c[s], st[s]) if self.fillx[s] is not False else (x[s], y[s], m[s], c[s], st[s]) for s in Signals], 5)
223
+
224
+ # Filly
225
+ #x, y, m, c, st = ut.transpose([ut.brush(x[s], y[s], m[s], c[s], st[s]) for s in Signals], 5)
226
+ level = [ut.get_fill_level(self.filly[s], xlim[s], width_expanded[s]) for s in Signals]
227
+ y, x, m, c, st = ut.transpose([ut.fill_data(y[s], x[s], level[s], m[s], c[s], st[s]) if self.filly[s] is not False else (y[s], x[s], m[s], c[s], st[s]) for s in Signals], 5)
228
+
229
+ # Get Actual HD Markers
230
+ x, y, m, c, st = ut.transpose([ut.brush(x[s], y[s], m[s], c[s], st[s]) for s in Signals], 5)
231
+ xf = [[ut.marker_factor(el, 2, 2, 2) for el in m[s]] for s in Signals]
232
+ yf = [[ut.marker_factor(el, 2, 3, 4) for el in m[s]] for s in Signals]
233
+ test = [max(xf[s], default = 1) * max(yf[s], default = 1) != 1 for s in Signals]
234
+ x, y, mxy = ut.transpose([ut.hd_group(x[s], y[s], xf[s], yf[s]) if test[s] else (x[s], y[s], []) for s in Signals], 3)
235
+ m = [[ut.get_hd_marker(mxy[s][i]) if m[s][i] in ut.hd_symbols else m[s][i] for i in range(len(x[s]))] for s in Signals]
236
+
237
+ # Add Data to Canvas
238
+ x, y, m, c, st = ut.transpose([ut.remove_outsiders(x[s], y[s], width_canvas, height_canvas, m[s], c[s], st[s]) for s in Signals], 5)
239
+
240
+ x, y, m, c, st = ut.transpose([ut.brush(x[s], y[s], m[s], c[s], st[s]) for s in Signals], 5)
241
+ [[self.matrix.insert_element(x[s][i] + col_start, y[s][i] + row_start, m[s][i], c[s][i], st[s][i]) for i in range(len(x[s]))] for s in Signals]
242
+
243
+ # Legend Utilities
244
+ labelled = lambda s: self.label[s] is not None
245
+ labels = [ut.space + self.label[s] + ut.space for s in Signals if labelled(s)]; l = len(labels); L = ut.max_length(labels)
246
+ labels = [el + ut.space * (L - len(el)) for el in labels]
247
+
248
+ # Add Legend Side Symbols
249
+ side = [ut.space + ut.side_symbols[(self.xside[s], self.yside[s])] for s in Signals if labelled(s)]
250
+ side_test = not (ut.no_duplicates(side) == [' L']) and not l == 1; S = 2 if side_test else 0;
251
+ legend_test = width_canvas >= S + 3 + L and height_canvas >= len(labels)
252
+ [self.matrix.add_horizontal_string(col_start, row_end - 1 - s, side[s], self.ticks_color, self.ticks_style) for s in range(l)] if legend_test and side_test else None
253
+
254
+ # Add Legend Markers
255
+ take_3 = lambda data: (data[ : 3] * 3)[ : 3]
256
+ marker = [take_3(self.marker[s]) for s in Signals if labelled(s)]
257
+ replace_hd_marker = lambda marker: ut.hd_symbols[marker] if marker in ut.hd_symbols else marker
258
+ marker = [[ut.space] + list(map(replace_hd_marker, el)) for el in marker]
259
+ color = [[ut.no_color] + take_3(c[s]) for s in Signals if labelled(s)]
260
+ style = [[ut.no_color] + take_3(st[s]) for s in Signals if labelled(s)]
261
+ [[self.matrix.insert_element(col_start + S + i, row_end - 1 - s, marker[s][i], color[s][i], style[s][i]) for i in range(3)] for s in range(l)] if legend_test else None
262
+ [self.matrix.add_horizontal_string(col_start + S + 3, row_end - 1 - s, labels[s], self.ticks_color, self.ticks_style) for s in range(l)] if legend_test else None
263
+
264
+ # Add Text to Canvas
265
+ [self.matrix.add_multiple_horizontal_strings(col_start + tcticks[s], row_start + trticks[s], self.text[s], self.tfull[s], self.tstyle[s], self.tback[s], self.talign[s], False, True) for s in Texts if self.torien[s] is self.default.orientation[0]]
266
+ [self.matrix.add_multiple_vertical_strings(col_start + tcticks[s], row_start + trticks[s], self.text[s], self.tfull[s], self.tstyle[s], self.tback[s], self.talign[s], True) for s in Texts if self.torien[s] is self.default.orientation[1]]
267
+
268
+
269
+
270
+