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/__init__.py +31 -0
- plotext_plus/__main__.py +2 -0
- plotext_plus/_api.py +828 -0
- plotext_plus/_build.py +270 -0
- plotext_plus/_core.py +581 -0
- plotext_plus/_date.py +60 -0
- plotext_plus/_default.py +83 -0
- plotext_plus/_dict.py +210 -0
- plotext_plus/_doc.py +707 -0
- plotext_plus/_doc_utils.py +291 -0
- plotext_plus/_figure.py +488 -0
- plotext_plus/_global.py +370 -0
- plotext_plus/_matrix.py +171 -0
- plotext_plus/_monitor.py +848 -0
- plotext_plus/_output.py +136 -0
- plotext_plus/_shtab.py +9 -0
- plotext_plus/_themes.py +343 -0
- plotext_plus/_utility.py +853 -0
- plotext_plus/api.py +828 -0
- plotext_plus/charts.py +42 -0
- plotext_plus/core.py +581 -0
- plotext_plus/mcp_cli.py +79 -0
- plotext_plus/mcp_server.py +505 -0
- plotext_plus/plotext_cli.py +375 -0
- plotext_plus/plotting.py +92 -0
- plotext_plus/themes.py +29 -0
- plotext_plus/utilities.py +52 -0
- plotext_plus/utils.py +370 -0
- plotext_plus-1.0.1.dist-info/METADATA +303 -0
- plotext_plus-1.0.1.dist-info/RECORD +33 -0
- plotext_plus-1.0.1.dist-info/WHEEL +4 -0
- plotext_plus-1.0.1.dist-info/entry_points.txt +3 -0
- plotext_plus-1.0.1.dist-info/licenses/LICENSE +23 -0
plotext_plus/_global.py
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# This file contains some plotext functions which are only available to the top main level and not to sub figures (which are written in _figure.py and _monitor.py). These are functions which requires some coding and would be too long to be added directly in _core.py
|
|
2
|
+
|
|
3
|
+
from plotext_plus._utility import marker_codes, hd_symbols, sin
|
|
4
|
+
from plotext_plus._figure import _figure_class
|
|
5
|
+
from plotext_plus._utility import themes as _themes
|
|
6
|
+
import plotext_plus._utility as ut
|
|
7
|
+
from time import time, sleep
|
|
8
|
+
from math import sqrt, ceil
|
|
9
|
+
import datetime as dt
|
|
10
|
+
|
|
11
|
+
figure = _figure_class() # the main figure at top level
|
|
12
|
+
|
|
13
|
+
##############################################
|
|
14
|
+
####### Simple Bar Functions ########
|
|
15
|
+
##############################################
|
|
16
|
+
|
|
17
|
+
def simple_bar(*args, width = None, marker = None, color = None, title = None):
|
|
18
|
+
x, y = ut.set_data(*args)
|
|
19
|
+
marker = ut.correct_marker(marker)
|
|
20
|
+
|
|
21
|
+
color_ok = ut.is_color(color) or (isinstance(color, list) and len(color) == len(x))
|
|
22
|
+
color = [color] if color_ok else None
|
|
23
|
+
|
|
24
|
+
simple_stacked_bar(x, [y], width = width, marker = marker, colors = color, title = title)
|
|
25
|
+
|
|
26
|
+
def simple_stacked_bar(*args, width = None, marker = None, colors = None, title = None, labels = None):
|
|
27
|
+
x, y, Y, width = ut.bar_data(*args, width = width)
|
|
28
|
+
marker = ut.correct_marker(marker)
|
|
29
|
+
|
|
30
|
+
bars = len(Y); stacked_bars = len(Y[0])
|
|
31
|
+
|
|
32
|
+
colors_ok1 = isinstance(colors, list) and isinstance(colors[0], list) and ut.matrix_size(colors) == [bars, stacked_bars]
|
|
33
|
+
colors_ok2 = isinstance(colors, list) and len(colors) == stacked_bars
|
|
34
|
+
colors = ut.transpose(colors) if colors_ok1 else [colors] * bars if colors_ok2 else [ut.color_sequence[:stacked_bars]] * bars
|
|
35
|
+
|
|
36
|
+
title = ut.get_title(title, width)
|
|
37
|
+
bars = [ut.single_bar(x[i], Y[i], y[i], marker, colors[i]) for i in range(bars)]
|
|
38
|
+
labels = ut.get_simple_labels(marker, labels, colors[0], width)
|
|
39
|
+
figure.monitor.matrix.canvas = title + '\n'.join(bars) + labels
|
|
40
|
+
figure.monitor.fast_plot = True
|
|
41
|
+
|
|
42
|
+
def simple_multiple_bar(*args, width = None, marker = None, colors = None, title = None, labels = None):
|
|
43
|
+
x, y, Y, width = ut.bar_data(*args, width = width, mode='multiple')
|
|
44
|
+
bars = len(Y); multiple_bars = len(Y[0]); lx = len(x[0])
|
|
45
|
+
marker = ut.correct_marker(marker)
|
|
46
|
+
|
|
47
|
+
colors_ok = isinstance(colors, list) and len(colors) == multiple_bars
|
|
48
|
+
colors = colors if colors_ok else ut.color_sequence[:multiple_bars]
|
|
49
|
+
|
|
50
|
+
out = ut.get_title(title, width)
|
|
51
|
+
for i in range(bars):
|
|
52
|
+
xn = [x[i] if j == (multiple_bars - 1) // 2 else ut.space * lx for j in range(multiple_bars)]
|
|
53
|
+
new = [ut.single_bar(xn[j], [Y[i][j]], y[j][i], marker, [colors[j]]) for j in range(multiple_bars)]
|
|
54
|
+
out += '\n'.join(new)
|
|
55
|
+
out += '\n\n' if i != bars - 1 else ''
|
|
56
|
+
labels = ut.get_simple_labels(marker, labels, colors, width)
|
|
57
|
+
figure.monitor.matrix.canvas = out + labels
|
|
58
|
+
figure.monitor.fast_plot = True
|
|
59
|
+
|
|
60
|
+
##############################################
|
|
61
|
+
############# Play GIF ################
|
|
62
|
+
##############################################
|
|
63
|
+
|
|
64
|
+
def play_gif(path):
|
|
65
|
+
from PIL import Image, ImageSequence
|
|
66
|
+
path = ut.correct_path(path)
|
|
67
|
+
if not ut.is_file(path):
|
|
68
|
+
return
|
|
69
|
+
im = Image.open(path)
|
|
70
|
+
index = 1
|
|
71
|
+
for image in ImageSequence.Iterator(im):
|
|
72
|
+
load_time = time()
|
|
73
|
+
figure.clt()
|
|
74
|
+
image = image.convert('RGB')
|
|
75
|
+
figure.monitor._draw_image(image, fast = True)
|
|
76
|
+
figure.show()
|
|
77
|
+
load_time = time() - load_time
|
|
78
|
+
frame_time = image.info['duration'] / 10 ** 3
|
|
79
|
+
if load_time < frame_time:
|
|
80
|
+
sleep(frame_time - load_time)
|
|
81
|
+
|
|
82
|
+
##############################################
|
|
83
|
+
########## Video Functions ############
|
|
84
|
+
##############################################
|
|
85
|
+
|
|
86
|
+
def play_video(path, from_youtube = False):
|
|
87
|
+
path = ut.correct_path(path)
|
|
88
|
+
if not ut.is_file(path):
|
|
89
|
+
return
|
|
90
|
+
_play_video(path, from_youtube)
|
|
91
|
+
|
|
92
|
+
def play_youtube(url):
|
|
93
|
+
import pafy
|
|
94
|
+
video = pafy.new(url)
|
|
95
|
+
best = video.getbest()
|
|
96
|
+
_play_video(best.url, from_youtube = True)
|
|
97
|
+
|
|
98
|
+
def get_youtube(url, path, log):
|
|
99
|
+
import pafy
|
|
100
|
+
video = pafy.new(url)
|
|
101
|
+
best = video.getbest(preftype = "mp4")
|
|
102
|
+
path = "youtube-video.mp4" if path is None else path
|
|
103
|
+
path = ut.correct_path(path)
|
|
104
|
+
best.download(filepath = path, quiet = not log)
|
|
105
|
+
print(ut.format_strings('YouTube video downloaded as', path)) if log else None
|
|
106
|
+
|
|
107
|
+
def _play_video(path, from_youtube = False):
|
|
108
|
+
import cv2
|
|
109
|
+
from ffpyplayer.player import MediaPlayer
|
|
110
|
+
from PIL import Image
|
|
111
|
+
cap = cv2.VideoCapture(path)
|
|
112
|
+
player = MediaPlayer(path)#, paused = True, loglevel = 'quiet');
|
|
113
|
+
fr = 0;
|
|
114
|
+
while fr == 0:
|
|
115
|
+
fr = cap.get(cv2.CAP_PROP_FPS)
|
|
116
|
+
frame_time = 1 / fr
|
|
117
|
+
#to_list = lambda frame: [[tuple(int(el) for el in tup) for tup in row] for row in frame]
|
|
118
|
+
pt = lambda time: '{time:05.1f} '.format(time=round(10 ** 3 * time, 1))
|
|
119
|
+
real_time = video_time = 0
|
|
120
|
+
while True:
|
|
121
|
+
load_time = time()
|
|
122
|
+
check_video, frame = cap.read();
|
|
123
|
+
audio, check_audio = player.get_frame(show = False)
|
|
124
|
+
load_time = time() - load_time
|
|
125
|
+
if not check_video:
|
|
126
|
+
break
|
|
127
|
+
if load_time >= frame_time:
|
|
128
|
+
continue
|
|
129
|
+
real_time += load_time
|
|
130
|
+
video_time += frame_time
|
|
131
|
+
show_time = 0
|
|
132
|
+
shown = False
|
|
133
|
+
if video_time >= real_time:
|
|
134
|
+
shown = True
|
|
135
|
+
show_time = time()
|
|
136
|
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) if from_youtube else frame
|
|
137
|
+
#frame = to_list(frame)
|
|
138
|
+
image = Image.fromarray(frame)
|
|
139
|
+
|
|
140
|
+
# Synchronized frame rendering - ensure each step completes before next
|
|
141
|
+
figure.clt()
|
|
142
|
+
# Small delay to ensure clear operation completes
|
|
143
|
+
sleep(0.001) # 1ms delay
|
|
144
|
+
figure.monitor._draw_image(image, fast = True)
|
|
145
|
+
# Small delay to ensure image drawing completes before display
|
|
146
|
+
sleep(0.001) # 1ms delay
|
|
147
|
+
figure.show()
|
|
148
|
+
# Brief delay after display to prevent frame overlap
|
|
149
|
+
sleep(0.002) # 2ms delay for terminal rendering
|
|
150
|
+
|
|
151
|
+
show_time = time() - show_time
|
|
152
|
+
sleep_time = 0
|
|
153
|
+
if real_time < video_time:
|
|
154
|
+
sleep_time = time()
|
|
155
|
+
sleep(video_time - real_time)
|
|
156
|
+
sleep_time = time() - sleep_time
|
|
157
|
+
total_time = load_time + show_time + sleep_time
|
|
158
|
+
real_time += show_time + sleep_time
|
|
159
|
+
#print('load: ' + pt(load_time), 'show: ' + pt(show_time), 'sleep: ' + pt(sleep_time), 'total: ' + pt(total_time), 'frame: ' + pt(frame_time), 'real: ' + pt(real_time), 'video: ' + pt(video_time), 'r/v:', round(real_time / video_time, 3)) if shown else None
|
|
160
|
+
player.close_player()
|
|
161
|
+
cap.release()
|
|
162
|
+
cv2.destroyAllWindows()
|
|
163
|
+
figure.clf()
|
|
164
|
+
|
|
165
|
+
##############################################
|
|
166
|
+
############ Utilities ###############
|
|
167
|
+
##############################################
|
|
168
|
+
|
|
169
|
+
test_data_url = "https://raw.githubusercontent.com/piccolomo/plotext/master/data/data.txt"
|
|
170
|
+
test_bar_data_url = "https://raw.githubusercontent.com/piccolomo/plotext/master/data/bar_data.txt"
|
|
171
|
+
test_image_url = "https://raw.githubusercontent.com/piccolomo/plotext/master/data/cat.jpg"
|
|
172
|
+
test_gif_url = "https://raw.githubusercontent.com/piccolomo/plotext/master/data/homer.gif"
|
|
173
|
+
test_video_url = "https://raw.githubusercontent.com/piccolomo/plotext/master/data/moonwalk.mp4"
|
|
174
|
+
test_youtube_url = 'https://www.youtube.com/watch?v=ZNAvVVc4b3E&t=75s'
|
|
175
|
+
|
|
176
|
+
##############################################
|
|
177
|
+
######### Matplotlib Backend ##########
|
|
178
|
+
##############################################
|
|
179
|
+
|
|
180
|
+
def from_matplotlib(fig, marker = None):
|
|
181
|
+
fig.canvas.draw()
|
|
182
|
+
slots = (rows, cols) = fig.axes[0].get_subplotspec().get_gridspec().get_geometry()
|
|
183
|
+
figure.clf(); #clt()
|
|
184
|
+
figure.subplots(*slots)
|
|
185
|
+
round10 = lambda data: [round(el, 10) for el in data]
|
|
186
|
+
to_rgb = lambda rgb_norm: tuple([round(255 * el) for el in rgb_norm[:3]])
|
|
187
|
+
figure.axes_color(to_rgb(fig.patch.get_facecolor()))
|
|
188
|
+
for sub in fig.axes[:]:
|
|
189
|
+
p = sub.get_subplotspec().get_geometry()[2]
|
|
190
|
+
row = int((p - 0) / cols + 1)
|
|
191
|
+
col = p + 1 - (row - 1) * cols
|
|
192
|
+
monitor = figure.subplot(row, col)
|
|
193
|
+
monitor.xlabel(sub.get_xlabel())
|
|
194
|
+
monitor.ylabel(sub.get_ylabel())
|
|
195
|
+
monitor.title(sub.get_title())
|
|
196
|
+
monitor.xscale(sub.get_xscale())
|
|
197
|
+
monitor.yscale(sub.get_yscale())
|
|
198
|
+
monitor.xticks(round10(sub.get_xticks()))
|
|
199
|
+
monitor.yticks(round10(sub.get_yticks()))
|
|
200
|
+
monitor.canvas_color(to_rgb(sub.get_facecolor()))
|
|
201
|
+
for point in sub.collections:
|
|
202
|
+
label = point.get_label()
|
|
203
|
+
label = label if label[0] != '_' else ''
|
|
204
|
+
#point.set_offset_position('data')
|
|
205
|
+
x, y = ut.transpose(point.get_offsets())
|
|
206
|
+
color = [ut.to_rgb(point.to_rgba(el)) for el in point.get_facecolors()[0]]
|
|
207
|
+
# can't find the right point colors
|
|
208
|
+
monitor.scatter(x, y, label = label, marker = marker)
|
|
209
|
+
for line in sub.get_lines():
|
|
210
|
+
label = line.get_label()
|
|
211
|
+
label = label if label[0] != '_' else ''
|
|
212
|
+
x, y = line.get_data()
|
|
213
|
+
monitor.plot(x, y, marker = marker, color = line.get_c(), label = label)
|
|
214
|
+
for b in sub.patches:
|
|
215
|
+
label = b.get_label()
|
|
216
|
+
label = label if label[0] != '_' else ''
|
|
217
|
+
color = b.get_facecolor()
|
|
218
|
+
color = ut.to_rgb(color)
|
|
219
|
+
box = b.get_bbox()
|
|
220
|
+
x0, y0, x1, y1 = box.x0, box.y0, box.x1, box.y1
|
|
221
|
+
x = [x0, x0, x1, x1, x0]
|
|
222
|
+
y = [y0, y1, y1, y0, y0]
|
|
223
|
+
fill = b.get_fill()
|
|
224
|
+
fillx = fill if y0 == 0 else False
|
|
225
|
+
filly = fill if x0 == 0 else False
|
|
226
|
+
monitor.plot(x, y, fillx = fillx, filly = filly, marker = marker, color = color, label = label)
|
|
227
|
+
monitor.xlim(*sub.get_xlim())
|
|
228
|
+
monitor.ylim(*sub.get_ylim())
|
|
229
|
+
|
|
230
|
+
##############################################
|
|
231
|
+
####### Presentation Functions ########
|
|
232
|
+
##############################################
|
|
233
|
+
|
|
234
|
+
def markers():
|
|
235
|
+
markers = list(hd_symbols.keys())[::-1] + list(marker_codes.keys())
|
|
236
|
+
l = len(markers)
|
|
237
|
+
rows = int(sqrt(l))
|
|
238
|
+
cols = ceil(l / rows)
|
|
239
|
+
y = ut.sin(1)
|
|
240
|
+
figure.clf(); figure.theme('pro'); figure.xfrequency(0); figure.yfrequency(0); figure.frame(1)
|
|
241
|
+
figure.subplots(rows, cols)
|
|
242
|
+
figure.frame(0)
|
|
243
|
+
for row in range(1, rows + 1):
|
|
244
|
+
for col in range(1, cols + 1):
|
|
245
|
+
i = (row - 1) * cols + col - 1
|
|
246
|
+
if i < l:
|
|
247
|
+
subplot = figure.subplot(row, col)
|
|
248
|
+
figure.frame(1)
|
|
249
|
+
default = ' [default]' if markers[i] == 'hd' else ''
|
|
250
|
+
subplot.title(markers[i] + default)
|
|
251
|
+
subplot.scatter(y, marker = markers[i])
|
|
252
|
+
subplot.ticks_style('bold')
|
|
253
|
+
#figure.ticks_color(figure._utility.title_color)
|
|
254
|
+
figure.show()
|
|
255
|
+
figure.clf()
|
|
256
|
+
|
|
257
|
+
def colors():
|
|
258
|
+
print(ut.colorize("String Color Codes", style = 'bold'))
|
|
259
|
+
bg = "default"
|
|
260
|
+
c = ut.no_duplicates([el.replace('+', '') for el in ut.colors if el not in ['default', 'black', 'white']])
|
|
261
|
+
cp = [ut.colorize(ut.pad_string(el + '+', 10), el + '+', background = bg) for el in c]
|
|
262
|
+
c = [ut.colorize(ut.pad_string(el, 10), el, background = bg) for el in c]
|
|
263
|
+
c = [' ' + c[i] + cp[i] for i in range(len(c))]
|
|
264
|
+
c = '\n'.join(c)
|
|
265
|
+
print(' ' + ut.colorize(ut.pad_string('default', 20), background = bg))
|
|
266
|
+
print(' ' + ut.colorize(ut.pad_string('black', 10), 'black', background = 'gray') + ut.colorize(ut.pad_string('white', 10), 'white', background = bg))
|
|
267
|
+
print(c)
|
|
268
|
+
print()
|
|
269
|
+
#print(colorize("\n\nInteger Color Codes:", style = ''))
|
|
270
|
+
c = ut.colorize("Integer Color Codes", style = 'bold', show = False) + '\n'
|
|
271
|
+
for row in range(16):
|
|
272
|
+
cr = ' '
|
|
273
|
+
for col in range(16):
|
|
274
|
+
i = row * 16 + col
|
|
275
|
+
cr += ut.colorize(ut.pad_string(i, 5), i)
|
|
276
|
+
c += cr + '\n'
|
|
277
|
+
print(c)
|
|
278
|
+
c = '\n'
|
|
279
|
+
rgb = (100, 200, 85)
|
|
280
|
+
rgb_string = '(' + ', '.join([str(el) for el in rgb]) + ')'
|
|
281
|
+
print(ut.colorize("RGB Tuples like:", style = "bold"), ut.colorize(rgb_string, rgb, "bold"))
|
|
282
|
+
|
|
283
|
+
def styles():
|
|
284
|
+
from plotext_plus._utility import styles, colorize, title_color
|
|
285
|
+
c = [colorize(el, style = el) for el in styles]
|
|
286
|
+
c = '\n'.join(c)
|
|
287
|
+
print(c)
|
|
288
|
+
mul = 'bold italic dim'
|
|
289
|
+
print('\n' + colorize('multiple styles are accepted, ', title_color) + 'eg: ' + colorize(mul, style = mul))
|
|
290
|
+
|
|
291
|
+
def themes():
|
|
292
|
+
themes = list(_themes.keys())[::]
|
|
293
|
+
l = len(themes)
|
|
294
|
+
rows = int(sqrt(l))
|
|
295
|
+
cols = ceil(l / rows)
|
|
296
|
+
y1 = ut.sin(periods = 1)
|
|
297
|
+
y2 = ut.sin(periods = 1, phase = -1)
|
|
298
|
+
figure.clf()
|
|
299
|
+
figure.subplots(rows, cols)
|
|
300
|
+
for row in range(1, rows + 1):
|
|
301
|
+
for col in range(1, cols + 1):
|
|
302
|
+
i = (row - 1) * cols + col - 1
|
|
303
|
+
if i < l:
|
|
304
|
+
subplot = figure.subplot(row, col)
|
|
305
|
+
subplot.theme(themes[i])
|
|
306
|
+
subplot.title(themes[i])
|
|
307
|
+
subplot.scatter(y1); subplot.plot(y2)
|
|
308
|
+
figure.show()
|
|
309
|
+
figure.clf()
|
|
310
|
+
|
|
311
|
+
##############################################
|
|
312
|
+
########### Test Function #############
|
|
313
|
+
##############################################
|
|
314
|
+
|
|
315
|
+
def test():
|
|
316
|
+
import random
|
|
317
|
+
figure.clf(); figure.clt()
|
|
318
|
+
figure.date_form("d/m/Y");
|
|
319
|
+
figure.take_min()
|
|
320
|
+
figure.plot_size(None, ut.terminal_height())
|
|
321
|
+
#figure.plot_size(108, 70)
|
|
322
|
+
|
|
323
|
+
figure.plotsize(ut.tw(), ut.th() - 5)
|
|
324
|
+
figure.subplots(2, 2)
|
|
325
|
+
|
|
326
|
+
subplot = figure.subplot(1, 1)
|
|
327
|
+
subplot.title("Multiple Axes Plot")
|
|
328
|
+
subplot.canvas_color(66); subplot.axes_color(4); subplot.ticks_color(216); subplot.ticks_style('bold italic')
|
|
329
|
+
y = ut.sin(periods = 1); l = len(y)
|
|
330
|
+
subplot.scatter(y, label = "lower left")
|
|
331
|
+
x = [figure.today_datetime() + dt.timedelta(days = i) for i in range(l)]; x = figure.datetimes_to_strings(x)
|
|
332
|
+
subplot.plot(x, x, label = 'upper right - all dates', xside = 2, yside = 2)
|
|
333
|
+
subplot.vline(l / 2, 'red')
|
|
334
|
+
subplot.hline(0, 200)
|
|
335
|
+
subplot.text("origin", l // 2, 0, color = 'red', alignment = 'center')
|
|
336
|
+
subplot.xlabel('x lower'); subplot.xlabel('x upper', 2)
|
|
337
|
+
subplot.ylabel('y left', 'left'); subplot.ylabel('y right', 'right')
|
|
338
|
+
subplot.xfrequency(8); subplot.xfrequency(5, 2);
|
|
339
|
+
subplot.yfrequency(3); subplot.yfrequency(5, 2);
|
|
340
|
+
subplot.grid(1,1)
|
|
341
|
+
|
|
342
|
+
subplot = figure.subplot(1, 2)
|
|
343
|
+
subplot.theme('innocent')
|
|
344
|
+
xb = ["Sausage", "Pepperoni", "Mushrooms", "Cheese", "Chicken", "Beef"]
|
|
345
|
+
y1 = [36, 14, 11, 8, 7, 4]
|
|
346
|
+
y2 = [20, 12, 35, 15, 4, 5]
|
|
347
|
+
subplot.stacked_bar(xb, [y1, y2], labels = ["men", "women"])
|
|
348
|
+
|
|
349
|
+
subplot = figure.subplot(2, 1)
|
|
350
|
+
subplot.theme('dreamland')
|
|
351
|
+
ld = 7 * 10 ** 4
|
|
352
|
+
data = [random.gauss(0, 1) for el in range(10 * ld)]
|
|
353
|
+
subplot.hist(data, bins = 60, label="mean 0")
|
|
354
|
+
subplot.frame(1); #subplot.xaxes(1, 0); subplot.yaxes(1, 0)
|
|
355
|
+
|
|
356
|
+
subplot = figure.subplot(2, 2)
|
|
357
|
+
subplot.canvas_color('gray+'); subplot.axes_color('gray+')
|
|
358
|
+
ut.download(test_image_url, 'cat.jpg')
|
|
359
|
+
subplot.image_plot('cat.jpg', grayscale = False)
|
|
360
|
+
ut.delete_file('cat.jpg')
|
|
361
|
+
subplot.title('A very Cute Cat')
|
|
362
|
+
subplot.frame(0)
|
|
363
|
+
|
|
364
|
+
#figure.plotsize(0, 0)
|
|
365
|
+
figure.show()
|
|
366
|
+
figure._get_time()
|
|
367
|
+
figure.save_fig('test.txt')
|
|
368
|
+
figure.save_fig('test.html')
|
|
369
|
+
#figure.clf()
|
|
370
|
+
|
plotext_plus/_matrix.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import plotext_plus._utility as ut
|
|
2
|
+
|
|
3
|
+
class matrix_class():
|
|
4
|
+
def __init__(self):
|
|
5
|
+
self.set_size(0, 0)
|
|
6
|
+
self.set_axes_color()
|
|
7
|
+
self.set_canvas_area(0, 0, 0, 0)
|
|
8
|
+
self.set_canvas_color()
|
|
9
|
+
self.set_matrices()
|
|
10
|
+
self.set_canvas()
|
|
11
|
+
|
|
12
|
+
def set_size(self, cols, rows):
|
|
13
|
+
self.rows = rows; self.Rows = range(self.rows)
|
|
14
|
+
self.cols = cols; self.Cols = range(self.cols)
|
|
15
|
+
self.size = [self.rows, self.cols]
|
|
16
|
+
|
|
17
|
+
def update_size(self):
|
|
18
|
+
self.cols, self.rows = ut.matrix_size(self.marker)
|
|
19
|
+
self.Rows = range(self.rows); self.Cols = range(self.cols)
|
|
20
|
+
self.size = [self.rows, self.cols]
|
|
21
|
+
|
|
22
|
+
def set_axes_color(self, color = ut.no_color):
|
|
23
|
+
self.axes_color = color
|
|
24
|
+
|
|
25
|
+
def set_canvas_area(self, col1, col2, row1, row2):
|
|
26
|
+
self.Cols_canvas = range(col1, col2)
|
|
27
|
+
self.Rows_canvas = range(row1, row2)
|
|
28
|
+
|
|
29
|
+
def set_canvas_color(self, color = ut.no_color):
|
|
30
|
+
self.canvas_color = color
|
|
31
|
+
|
|
32
|
+
def in_canvas(self, col, row):
|
|
33
|
+
return col in self.Cols_canvas and row in self.Rows_canvas
|
|
34
|
+
|
|
35
|
+
def set_matrices(self):
|
|
36
|
+
self.marker = [[ut.space] * self.cols for row in self.Rows]
|
|
37
|
+
self.fullground = [[ut.no_color] * self.cols for row in self.Rows]
|
|
38
|
+
get_background = lambda col, row: self.canvas_color if self.in_canvas(col, row) else self.axes_color
|
|
39
|
+
self.background = [[get_background(col, row) for col in self.Cols] for row in self.Rows]
|
|
40
|
+
self.style = [[ut.no_color] * self.cols for row in self.Rows]
|
|
41
|
+
|
|
42
|
+
def legal(self, col, row):
|
|
43
|
+
return col in self.Cols and row in self.Rows
|
|
44
|
+
|
|
45
|
+
def get_marker(self, col, row):
|
|
46
|
+
return self.marker[row][col] #if self.legal(col, row) else "OUT"
|
|
47
|
+
|
|
48
|
+
def get_marker_row(self, row):
|
|
49
|
+
return self.marker[row] #if self.legal(0, row) else "OUT"
|
|
50
|
+
|
|
51
|
+
def get_marker_col(self, col):
|
|
52
|
+
return [self.marker[r][col] for r in self.Rows]#if self.legal(0, row) else "OUT"
|
|
53
|
+
|
|
54
|
+
def set_marker(self, col, row, marker):
|
|
55
|
+
self.marker[row][col] = marker
|
|
56
|
+
|
|
57
|
+
def set_fullground(self, col, row, fullground = None):
|
|
58
|
+
self.fullground[row][col] = fullground
|
|
59
|
+
|
|
60
|
+
def set_background(self, col, row, background = None):
|
|
61
|
+
self.background[row][col] = background
|
|
62
|
+
|
|
63
|
+
def set_style(self, col, row, style = None):
|
|
64
|
+
self.style[row][col] = style
|
|
65
|
+
|
|
66
|
+
def insert_element(self, col, row, marker, fullground = None, style = None, background = None, check_canvas = False):
|
|
67
|
+
test_canvas = True if check_canvas is False else col in self.Cols_canvas and row in self.Rows_canvas
|
|
68
|
+
if self.legal(col, row) and test_canvas:
|
|
69
|
+
self.set_marker(col, row, marker)
|
|
70
|
+
self.set_fullground(col, row, fullground) if fullground is not None else None
|
|
71
|
+
self.set_background(col, row, background) if background is not None else None
|
|
72
|
+
self.set_style(col, row, style) if style is not None else None
|
|
73
|
+
|
|
74
|
+
def add_horizontal_string(self, col, row, string, fullground = None, style = None, background = None, alignment = "left", check_space = False, check_canvas = False):
|
|
75
|
+
l = len(string); L = range(l)
|
|
76
|
+
col = col if alignment == "left" else col - l // 2 if alignment == "center" else col - l + 1 if alignment == "right" else ut.correct_coord(self.get_marker_row(row), string, col) # if dynamic
|
|
77
|
+
b, e = max(col - 1, 0), min(col + l + 1, self.cols)
|
|
78
|
+
test_space = all([self.get_marker(c, row) == ut.space for c in range(b, e)]) and col >= 0 and col + l <= self.cols if check_space else True
|
|
79
|
+
[self.insert_element(col + i, row, string[i], fullground, style, background, check_canvas) for i in L] if test_space else None
|
|
80
|
+
return test_space
|
|
81
|
+
|
|
82
|
+
def add_vertical_string(self, col, row, string, fullground = None, style = None, background = None, alignment = "bottom", check_canvas = False):
|
|
83
|
+
l = len(string); L = range(l)
|
|
84
|
+
row = row if alignment == "bottom" else row - l // 2 if alignment == "center" else row - l + 1 #if alignment == "top"
|
|
85
|
+
[self.insert_element(col, row + i, string[i], fullground, style, background, check_canvas) for i in L]
|
|
86
|
+
|
|
87
|
+
def add_multiple_horizontal_strings(self, col, row, string, fullground = None, style = None, background = None, alignment = "left", check_space = False, check_canvas = False):
|
|
88
|
+
strings = ''.join(string).split('\n'); S = len(strings)
|
|
89
|
+
[self.add_horizontal_string(col, row - s, strings[s], fullground, style, background, alignment, check_space, check_canvas) for s in range(S)]
|
|
90
|
+
|
|
91
|
+
def add_multiple_vertical_strings(self, col, row, string, fullground = None, style = None, background = None, alignment = "left", check_canvas = False):
|
|
92
|
+
strings = ''.join(string).split('\n'); S = len(strings)
|
|
93
|
+
[self.add_vertical_string(col + s, row, strings[s], fullground, style, background, alignment, check_canvas) for s in range(S)]
|
|
94
|
+
|
|
95
|
+
def get_colors(self, col, row):
|
|
96
|
+
return [self.fullground[row][col], self.style[row][col], self.background[row][col]] #if self.legal(col, row) else ["OUT"] * 3
|
|
97
|
+
|
|
98
|
+
def set_canvas(self):
|
|
99
|
+
canvas = ''
|
|
100
|
+
for row in self.Rows[::-1]:
|
|
101
|
+
for col in self.Cols:
|
|
102
|
+
marker = self.marker[row][col]
|
|
103
|
+
colors = self.get_colors(col, row)
|
|
104
|
+
if col == 0 or colors != self.get_colors(col - 1, row):
|
|
105
|
+
ansi = ut.colors_to_ansi(*colors)
|
|
106
|
+
canvas += ansi
|
|
107
|
+
canvas += marker
|
|
108
|
+
if col == self.cols - 1 or colors != self.get_colors(col + 1, row):
|
|
109
|
+
#ansi_next = colors_to_ansi(*colors_next)
|
|
110
|
+
canvas += ut.ansi_end #+ ansi_next
|
|
111
|
+
canvas += '\n'
|
|
112
|
+
|
|
113
|
+
self.canvas = canvas
|
|
114
|
+
#print(repr(canvas))
|
|
115
|
+
#self.canvas = '\n'.join([''.join(self.marker[row]) for row in self.Rows])
|
|
116
|
+
return self.canvas
|
|
117
|
+
|
|
118
|
+
def get_canvas(self):
|
|
119
|
+
return self.canvas
|
|
120
|
+
|
|
121
|
+
def hstack(self, extra):
|
|
122
|
+
self.marker = ut.hstack(self.marker, extra.marker)
|
|
123
|
+
self.fullground = ut.hstack(self.fullground, extra.fullground)
|
|
124
|
+
self.background = ut.hstack(self.background, extra.background)
|
|
125
|
+
self.style = ut.hstack(self.style, extra.style)
|
|
126
|
+
self.update_size()
|
|
127
|
+
self.canvas = '';
|
|
128
|
+
|
|
129
|
+
def vstack(self, extra):
|
|
130
|
+
self.marker = ut.vstack(self.marker, extra.marker)
|
|
131
|
+
self.fullground = ut.vstack(self.fullground, extra.fullground)
|
|
132
|
+
self.background = ut.vstack(self.background, extra.background)
|
|
133
|
+
self.style = ut.vstack(self.style, extra.style)
|
|
134
|
+
self.update_size()
|
|
135
|
+
self.canvas = ''
|
|
136
|
+
|
|
137
|
+
def to_html(self): # turns a matrix of character in html form
|
|
138
|
+
code = lambda color: "rgb" + str(color).replace(" ", "")
|
|
139
|
+
#html = "<body>\n<p style=\"font-family:courier; font-size:11pt;\">\n\n"
|
|
140
|
+
html = "<body> \n <code style = style=\"font-family:courier; \"font-size : 10pt;\"> \n\n"
|
|
141
|
+
for r in range(self.rows - 1, -1, -1):
|
|
142
|
+
for c in range(self.cols):
|
|
143
|
+
marker = self.get_marker(c, r)
|
|
144
|
+
color, style, background = self.get_colors(c, r)
|
|
145
|
+
marker = " " if marker == ut.space else marker
|
|
146
|
+
marker = '<b>' + marker + '</b>' if style == 'bold' else marker
|
|
147
|
+
marker = '<i>' + marker + '</i>' if style == 'italic' else marker
|
|
148
|
+
color = 'black' if color == ut.no_color else color
|
|
149
|
+
background = 'white' if background == ut.no_color else background
|
|
150
|
+
color = ut.to_rgb(color)
|
|
151
|
+
background = ut.to_rgb(background)
|
|
152
|
+
color = code(color)
|
|
153
|
+
background = code(background)
|
|
154
|
+
html += "<span style = \"color:" + color + "; background-color: " + background + "\">" + marker + "</span>"
|
|
155
|
+
html += " <br>\n\n"
|
|
156
|
+
html += "<code> \n </body>"
|
|
157
|
+
return html
|
|
158
|
+
|
|
159
|
+
def join_matrices(matrices): # from a matrix of matrix_class() objects to a single matrix
|
|
160
|
+
cols, rows = ut.matrix_size(matrices)
|
|
161
|
+
M = matrix_class()
|
|
162
|
+
for r in range(rows):
|
|
163
|
+
m_rows = matrices[r][0].rows
|
|
164
|
+
m = matrix_class()
|
|
165
|
+
m.set_size(0, m_rows)
|
|
166
|
+
m.set_matrices()
|
|
167
|
+
for c in range(cols):
|
|
168
|
+
m.hstack(matrices[r][c])
|
|
169
|
+
M.vstack(m)
|
|
170
|
+
return M
|
|
171
|
+
|