Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagecell
Path: blob/master/interact_compatibility.py
447 views
1
#########################################################################################
2
# Copyright (C) 2012 Jason Grout, Ira Hanson, Alex Kramer #
3
# #
4
# Distributed under the terms of the GNU General Public License (GPL), version 2+ #
5
# #
6
# http://www.gnu.org/licenses/ #
7
#########################################################################################
8
9
# the only reason this file is distributed under GPLv2+ is because it
10
# imports functions from interact_sagecell.py, which is distributed as
11
# GPLv2+. The actual code in this file is under the modified BSD
12
# license, which means that if those imports are replaced with
13
# BSD-compatible functions, this file can be distributed under the
14
# modified BSD license.
15
16
17
"""
18
This module defines a backwards-compatible API for interact controls from the first interact design.
19
20
"""
21
22
from interact_sagecell import *
23
24
"""
25
text_control: http://www.sagemath.org/doc/reference/sagenb/notebook/interact.html#sagenb.notebook.interact.text_control
26
slider: http://www.sagemath.org/doc/reference/sagenb/notebook/interact.html#sagenb.notebook.interact.slider
27
range_slider: http://www.sagemath.org/doc/reference/sagenb/notebook/interact.html#sagenb.notebook.interact.range_slider
28
selector: http://www.sagemath.org/doc/reference/sagenb/notebook/interact.html#sagenb.notebook.interact.selector
29
input_grid: http://www.sagemath.org/doc/reference/sagenb/notebook/interact.html#sagenb.notebook.interact.input_grid
30
input_box: http://www.sagemath.org/doc/reference/sagenb/notebook/interact.html#sagenb.notebook.interact.input_box
31
color_selector: http://www.sagemath.org/doc/reference/sagenb/notebook/interact.html#sagenb.notebook.interact.color_selector
32
checkbox: http://www.sagemath.org/doc/reference/sagenb/notebook/interact.html#sagenb.notebook.interact.checkbox
33
"""
34
35
from collections.abc import Iterable
36
import math
37
38
39
def __old_make_values_list(vmin, vmax, step_size):
40
"""
41
This code is from slider_generic.__init__.
42
43
This code requires sage mode to be checked.
44
"""
45
from sage.arith.srange import srange
46
if isinstance(vmin, (range, Iterable)):
47
values = list(vmin)
48
else:
49
if vmax is None:
50
vmin, vmax = 0, vmin
51
#Compute step size; vmin and vmax are both defined here
52
#500 is the length of the slider (in px)
53
if step_size is None:
54
step_size = (vmax - vmin) / 499.0
55
elif step_size <= 0:
56
raise ValueError("step_size must be positive")
57
58
#Compute list of values
59
num_steps = int(math.ceil((vmax - vmin) / float(step_size)))
60
if num_steps <= 1:
61
return [vmin, vmax]
62
values = srange(vmin, vmax, step_size, include_endpoint=True)
63
if values[-1] != vmax:
64
try:
65
if values[-1] > vmax:
66
values[-1] = vmax
67
else:
68
values.append(vmax)
69
except (ValueError, TypeError):
70
pass
71
72
#If the list of values is small, use the whole list.
73
#Otherwise, use evenly spaced values in the list.
74
if not values:
75
return [0]
76
if len(values) <= 500:
77
return values
78
vlen = (len(values) - 1) / 499.0
79
return [values[(int)(i * vlen)] for i in range(500)]
80
81
82
def slider(vmin, vmax=None,step_size=None, default=None, label=None,
83
display_value=True):
84
r"""
85
An interactive slider control, which can be used in conjunction
86
with the :func:`interact` command.
87
88
INPUT:
89
90
- ``vmin`` - an object
91
92
- ``vmax`` - an object (default: None); if None then ``vmin``
93
must be a list, and the slider then varies over elements of
94
the list.
95
96
- ``step_size`` - an integer (default: 1)
97
98
- ``default`` - an object (default: None); default value is
99
"closest" in ``vmin`` or range to this default.
100
101
- ``label`` - a string
102
103
- ``display_value`` - a bool, whether to display the current
104
value to the right of the slider
105
106
EXAMPLES:
107
108
We specify both ``vmin`` and ``vmax``. We make the default
109
`3`, but since `3` isn't one of `3/17`-th spaced values
110
between `2` and `5`, `52/17` is instead chosen as the
111
default (it is closest)::
112
113
sage: slider(2, 5, 3/17, 3, 'alpha')
114
Slider: alpha [2--|52/17|---5]
115
116
Here we give a list::
117
118
sage: slider([1..10], None, None, 3, 'alpha')
119
Slider: alpha [1--|3|---10]
120
121
The elements of the list can be anything::
122
123
sage: slider([1, 'x', 'abc', 2/3], None, None, 'x', 'alpha')
124
Slider: alpha [1--|x|---2/3]
125
"""
126
values=__old_make_values_list(vmin, vmax, step_size)
127
return DiscreteSlider(range_slider=False, values=values,
128
default=default, label=label, display_value=display_value)
129
130
131
def range_slider(vmin, vmax=None, step_size=None, default=None, label=None, display_value=True):
132
r"""
133
An interactive range slider control, which can be used in conjunction
134
with the :func:`interact` command.
135
136
INPUT:
137
138
- ``vmin`` - an object
139
140
- ``vmax`` - object or None; if None then ``vmin`` must be a
141
list, and the slider then varies over elements of the list.
142
143
- ``step_size`` - integer (default: 1)
144
145
- ``default`` - a 2-tuple of objects (default: None); default
146
range is "closest" in ``vmin`` or range to this default.
147
148
- ``label`` - a string
149
150
- ``display_value`` - a bool, whether to display the current
151
value below the slider
152
153
EXAMPLES:
154
155
We specify both ``vmin`` and ``vmax``. We make the default
156
`(3,4)` but since neither is one of `3/17`-th spaced
157
values between `2` and `5`, the closest values: `52/17`
158
and `67/17`, are instead chosen as the default::
159
160
sage: range_slider(2, 5, 3/17, (3,4), 'alpha')
161
Range Slider: alpha [2--|52/17==67/17|---5]
162
163
Here we give a list::
164
165
sage: range_slider([1..10], None, None, (3,7), 'alpha')
166
Range Slider: alpha [1--|3==7|---10]
167
"""
168
values=__old_make_values_list(vmin, vmax, step_size)
169
return DiscreteSlider(range_slider=True, values=values,
170
default=default, label=label, display_value=display_value)
171
172
173
def input_box(default=None, label=None, type=None, width=80, height=1, **kwargs):
174
r"""
175
An input box interactive control. Use this in conjunction
176
with the :func:`interact` command.
177
178
INPUT:
179
180
- ``default`` - an string; the default string for the input box
181
and adapter. If this is not a string, then the default string
182
is set to ``repr(object)``.
183
184
- ``label`` - a string; the label rendered to the left of the
185
box.
186
187
- ``type`` - a type; coerce inputs to this; this doesn't
188
have to be an actual type, since anything callable will do.
189
190
- ``height`` - an integer (default: 1); the number of rows.
191
If greater than 1 a value won't be returned until something
192
outside the textarea is clicked.
193
194
- ``width`` - an integer; width of text box in characters
195
196
- ``kwargs`` - a dictionary; additional keyword options
197
198
EXAMPLES::
199
200
sage: input_box("2+2", 'expression')
201
Interact input box labeled 'expression' with default value '2+2'
202
sage: input_box('sage', label="Enter your name", type=str)
203
Interact input box labeled 'Enter your name' with default value 'sage'
204
sage: input_box('Multiline\nInput',label='Click to change value',type=str,height=5)
205
Interact input box labeled 'Click to change value' with default value 'Multiline\nInput'
206
"""
207
from sage.plot.colors import Color
208
209
if type is Color:
210
# kwargs are only used if the type is Color.
211
widget=kwargs.get('widget', None)
212
hide_box=kwargs.get('hide_box', False)
213
return color_selector(default=default, label=label,
214
widget=widget, hide_box=hide_box)
215
if type is str or height>1:
216
return InputBox(default=default, label=label, width=width, height=height, keypress=False)
217
else:
218
return ExpressionBox(default=default, label=label, width=width, height=height,
219
adapter=(lambda x: type(x)) if type is not None else None)
220
221
def color_selector(default=(0,0,1), label=None,
222
widget='colorpicker', hide_box=False):
223
r"""
224
A color selector (also called a color chooser, picker, or
225
tool) interactive control. Use this with the :func:`interact`
226
command.
227
228
INPUT:
229
230
- ``default`` - an instance of or valid constructor argument
231
to :class:`Color` (default: (0,0,1)); the selector's default
232
color; a string argument must be a valid color name (e.g.,
233
'red') or HTML hex color (e.g., '#abcdef')
234
235
- ``label`` - a string (default: None); the label rendered to
236
the left of the selector.
237
238
- ``widget`` - a string (default: 'jpicker'); the color
239
selector widget to use; choices are 'colorpicker', 'jpicker'
240
and 'farbtastic'
241
242
- ``hide_box`` - a boolean (default: False); whether to hide
243
the input box associated with the color selector widget
244
245
EXAMPLES::
246
247
sage: color_selector()
248
Interact color selector labeled None, with default RGB color (0.0, 0.0, 1.0), widget 'jpicker', and visible input box
249
sage: color_selector((0.5, 0.5, 1.0), widget='jpicker')
250
Interact color selector labeled None, with default RGB color (0.5, 0.5, 1.0), widget 'jpicker', and visible input box
251
sage: color_selector(default = Color(0, 0.5, 0.25))
252
Interact color selector labeled None, with default RGB color (0.0, 0.5, 0.25), widget 'jpicker', and visible input box
253
sage: color_selector('purple', widget = 'colorpicker')
254
Interact color selector labeled None, with default RGB color (0.50..., 0.0, 0.50...), widget 'colorpicker', and visible input box
255
sage: color_selector('crayon', widget = 'colorpicker')
256
Traceback (most recent call last):
257
...
258
ValueError: unknown color 'crayon'
259
sage: color_selector('#abcdef', label='height', widget='jpicker')
260
Interact color selector labeled 'height', with default RGB color (0.6..., 0.8..., 0.9...), widget 'jpicker', and visible input box
261
sage: color_selector('abcdef', label='height', widget='jpicker')
262
Traceback (most recent call last):
263
...
264
ValueError: unknown color 'abcdef'
265
"""
266
# TODO: look at various other widgets we used to support
267
#'widget': 'jpicker, 'colorpicker', 'farbtastic'
268
# -- we don't need to support each one right now
269
if widget!='colorpicker':
270
print("ColorSelector: Only widget='colorpicker' is supported; changing color widget")
271
return ColorSelector(default=default, label=label, hide_input=hide_box)
272
273
274
def selector(values, label=None, default=None,
275
nrows=None, ncols=None, width=None, buttons=False):
276
r"""
277
A drop down menu or a button bar that when pressed sets a
278
variable to a given value. Use this in conjunction with the
279
:func:`interact` command.
280
281
We use the same command to create either a drop down menu or
282
selector bar of buttons, since conceptually the two controls
283
do exactly the same thing - they only look different. If
284
either ``nrows`` or ``ncols`` is given, then you get a buttons
285
instead of a drop down menu.
286
287
INPUT:
288
289
- ``values`` - [val0, val1, val2, ...] or [(val0, lbl0),
290
(val1,lbl1), ...] where all labels must be given or given as
291
None.
292
293
- ``label`` - a string (default: None); if given, this label
294
is placed to the left of the entire button group
295
296
- ``default`` - an object (default: 0); default value in values
297
list
298
299
- ``nrows`` - an integer (default: None); if given determines
300
the number of rows of buttons; if given buttons option below
301
is set to True
302
303
- ``ncols`` - an integer (default: None); if given determines
304
the number of columns of buttons; if given buttons option
305
below is set to True
306
307
- ``width`` - an integer (default: None); if given, all
308
buttons are the same width, equal to this in HTML ex
309
units's.
310
311
- ``buttons`` - a bool (default: False); if True, use buttons
312
313
EXAMPLES::
314
315
sage: selector([1..5])
316
Drop down menu with 5 options
317
sage: selector([1,2,7], default=2)
318
Drop down menu with 3 options
319
sage: selector([1,2,7], nrows=2)
320
Button bar with 3 buttons
321
sage: selector([1,2,7], ncols=2)
322
Button bar with 3 buttons
323
sage: selector([1,2,7], width=10)
324
Drop down menu with 3 options
325
sage: selector([1,2,7], buttons=True)
326
Button bar with 3 buttons
327
328
We create an :func:`interact` that involves computing charpolys of
329
matrices over various rings::
330
331
sage: @interact
332
... def _(R=selector([ZZ,QQ,GF(17),RDF,RR]), n=(1..10)):
333
... M = random_matrix(R, n)
334
... show(M)
335
... show(matrix_plot(M,cmap='Oranges'))
336
... f = M.charpoly()
337
... print(f)
338
<html>...
339
340
Here we create a drop-down::
341
342
sage: @interact
343
... def _(a=selector([(2,'second'), (3,'third')])):
344
... print(a)
345
<html>...
346
"""
347
selector_type = 'button' if buttons else 'list'
348
values = list(values)
349
# in the old code, if a selector had a single button, then it was
350
# actually a pushbutton (i.e., it would trigger an update every time
351
# it was pushed)
352
if selector_type == 'button' and len(values) == 1:
353
v0 = values[0]
354
if isinstance(v0, (list, tuple)) and len(v0) == 2:
355
value, text = v0
356
else:
357
value, text= v0, str(v0)
358
return Button(value=value, text=text, default=value, label=label, width=width)
359
360
return Selector(values=values, default=default, label=label, selector_type=selector_type,
361
nrows=nrows, ncols=ncols, width=width)
362
363
def input_grid(nrows, ncols, default=None, label=None, to_value=None, width=4, type=None):
364
r"""
365
An input grid interactive control. Use this in conjunction
366
with the :func:`interact` command.
367
368
INPUT:
369
370
- ``nrows`` - an integer
371
372
- ``ncols`` - an integer
373
374
- ``default`` - an object; the default put in this input box
375
376
- ``label`` - a string; the label rendered to the left of the
377
box.
378
379
- ``to_value`` - a function; the grid output (list of rows) is
380
sent through this function. This may reformat the data or
381
coerce the type.
382
383
- ``type`` - a function; each input box string is sent through
384
this function before sending the list through to_value
385
386
- ``width`` - an integer; size of each input box in characters
387
388
NOTEBOOK EXAMPLE::
389
390
@interact
391
def _(m = input_grid(2,2, default = [[1,7],[3,4]],
392
label='M=', to_value=matrix),
393
v = input_grid(2,1, default=[1,2],
394
label='v=', to_value=matrix)):
395
try:
396
x = m\v
397
html('$$%s %s = %s$$'%(latex(m), latex(x), latex(v)))
398
except:
399
html('There is no solution to $$%s x=%s$$'%(latex(m), latex(v)))
400
401
EXAMPLES::
402
403
sage: input_grid(2,2, default = 0, label='M')
404
Interact 2 x 2 input grid control labeled M with default value 0
405
sage: input_grid(2,2, default = [[1,2],[3,4]], label='M')
406
Interact 2 x 2 input grid control labeled M with default value [[1, 2], [3, 4]]
407
sage: input_grid(2,2, default = [[1,2],[3,4]], label='M', to_value=MatrixSpace(ZZ,2,2))
408
Interact 2 x 2 input grid control labeled M with default value [[1, 2], [3, 4]]
409
sage: input_grid(1, 3, default=[[1,2,3]], to_value=lambda x: vector(flatten(x)))
410
Interact 1 x 3 input grid control labeled None with default value [[1, 2, 3]]
411
412
"""
413
# this mirrors the code in input_box
414
element_adapter = None
415
evaluate = True
416
if type is str:
417
evaluate = False
418
elif type is not None:
419
element_adapter = lambda x: type(x)
420
421
if to_value is None:
422
adapter=None
423
else:
424
adapter=lambda x: to_value(x)
425
426
return InputGrid(nrows=nrows, ncols=ncols, width=width,
427
default=default, label=label, adapter=adapter,
428
element_adapter=element_adapter, evaluate=evaluate)
429
430
def checkbox(default=True, label=None):
431
"""
432
A checkbox interactive control. Use this in conjunction with
433
the :func:`interact` command.
434
435
INPUT:
436
437
- ``default`` - a bool (default: True); whether box should be
438
checked or not
439
440
- ``label`` - a string (default: None) text label rendered to
441
the left of the box
442
443
EXAMPLES::
444
445
sage: checkbox(False, "Points")
446
Interact checkbox labeled 'Points' with default value False
447
sage: checkbox(True, "Points")
448
Interact checkbox labeled 'Points' with default value True
449
sage: checkbox(True)
450
Interact checkbox labeled None with default value True
451
sage: checkbox()
452
Interact checkbox labeled None with default value True
453
"""
454
return Checkbox(default=default, label=label)
455
456
def text_control(value=""):
457
"""
458
Text that can be inserted among other :func:`interact` controls.
459
460
INPUT:
461
462
- ``value`` - HTML for the control
463
464
EXAMPLES::
465
466
sage: text_control('something')
467
Text field: something
468
"""
469
return HtmlBox(value=value)
470
471
imports = {"slider": slider, "range_slider": range_slider,
472
"input_box": input_box, "color_selector": color_selector,
473
"selector": selector, "input_grid": input_grid,
474
"text_control": text_control, "checkbox": checkbox}
475
476
477
478