Using Jupyter Notebook (v. 6.0.0) via Anaconda (Navigator v. 1.9.7) on Windows 10. Consider a situation where I have a ipywidgets slider on top, then a whole lotta text in between, then a graph on the botton that responds to the slider. Here is an image of such a webpage in Firefox, zoomed out so that it can be shown in full:
Clearly, this is difficult to use - and what I would prefer in this case, is to "detach" the widget that contains the slider, and drag it down to approx where the graph is, then manipulate the slider; in that case, I also would not have to use the webpage rendering zoomed out. Then when done manipulating, I'd like to click a button, and have the widget reattached to where it was.
However, I am not sure, how could I implement this in Jupyter notebook with ipywidgets? The only thing close to this I've found is [Question] Maintain position of floating widget when browser tab is closed · Issue #2520 · jupyter-widgets/ipywidgets, which seems to imply that intervention in JavaScript is needed.
Here is the code to recreate the screenshot (there is already a "Detach" button in the widget containing the slider, except it does nothing else but change its text):
Cell 1 - Python 3:
import plotly.graph_objs as go
import numpy as np
from ipywidgets import widgets, Layout
from IPython.display import display
from IPython.display import Markdown as md
inSlider = widgets.FloatSlider(
value=1.0,
min=0.0,
max=10.0,
step=0.01,
description='In:',
continuous_update=True
)
output2 = widgets.Output()
def on_detButton_click(b):
if b.description == "Detach": b.description = "Attach"
else: b.description = "Detach"
detButton = widgets.Button(description="Detach")
detButton.on_click(on_detButton_click)
myctlwidget = widgets.VBox([widgets.HBox([inSlider, detButton]), output2])
display(myctlwidget)
Cell 2 is Markdown - pasted at end of this post;
Cell 3 - Python 3:
fig = go.FigureWidget( layout=go.Layout() )
fig.add_trace(go.Scatter(x=[0,10], y=[0,10],
mode='lines',
name='Test plot'))
# set range to prevent autoranging when slider sets a new value
fig.update_yaxes(range=[0, 11])
def update_graph(change):
with fig.batch_update():
curval = inSlider.value
fig.data[0].y=[0, curval]
inSlider.observe(update_graph, names="value")
widgets.VBox([fig])
Cell 2 - Markdown (note two spaces at end of each first line, to introduce a line break)
Test paragraph 0
Some text 0, 0.... some text 0
Test paragraph 1
Some text 1, 1.... some text 1
Test paragraph 2
Some text 2, 2.... some text 2
Test paragraph 3
Some text 3, 3.... some text 3
Test paragraph 4
Some text 4, 4.... some text 4
Test paragraph 5
Some text 5, 5.... some text 5
Test paragraph 6
Some text 6, 6.... some text 6
Test paragraph 7
Some text 7, 7.... some text 7
Test paragraph 8
Some text 8, 8.... some text 8
Test paragraph 9
Some text 9, 9.... some text 9
Test paragraph 10
Some text 10, 10.... some text 10
Test paragraph 11
Some text 11, 11.... some text 11
Test paragraph 12
Some text 12, 12.... some text 12
Test paragraph 13
Some text 13, 13.... some text 13
Test paragraph 14
Some text 14, 14.... some text 14
Test paragraph 15
Some text 15, 15.... some text 15
Test paragraph 16
Some text 16, 16.... some text 16
Test paragraph 17
Some text 17, 17.... some text 17
Test paragraph 18
Some text 18, 18.... some text 18
Test paragraph 19
Some text 19, 19.... some text 19
Test paragraph 20
Some text 20, 20.... some text 20
Test paragraph 21
Some text 21, 21.... some text 21
Test paragraph 22
Some text 22, 22.... some text 22
Test paragraph 23
Some text 23, 23.... some text 23
Test paragraph 24
Some text 24, 24.... some text 24
Test paragraph 25
Some text 25, 25.... some text 25
Test paragraph 26
Some text 26, 26.... some text 26
Test paragraph 27
Some text 27, 27.... some text 27
Test paragraph 28
Some text 28, 28.... some text 28
Test paragraph 29
Some text 29, 29.... some text 29
Test paragraph 30
Some text 30, 30.... some text 30
Ok, I think I got it working - thankfully, this version of Jupyter notebook automatically loads jquery-ui, so I can use .draggable() ...
Note that:
Having the whole background div as draggable, means that the whole element will be dragged even when you just want to move the slider head - so must use a drag handle instead (to allow for proper usage of the slider itself)
The detached/draggable element typically goes over other elements (as desired), except when in a cell which has a plotly diagram - once draggable element is released here (regardless if it happens over the plotly diagram itself, or other ipywidgets that may be present in the same cell output), the element cannot be clicked to be dragged anymore! (however, it can be click/dragged if the handle ends up in the two thin right and left borders)
If anyone comes up with a solution for the (second) problem, I'd love to hear it.
In the meantime, the workaround is to place a plain Markdown cell, below the cell output that contains the plotly diagram, which will then be able to properly "host" the dragged slider element. Here is how the fix looks like in this case (the little "(h)" is the handle):
Here is my fix:
Cell 1 - Python 3:
import plotly.graph_objs as go
import numpy as np
from ipywidgets import widgets, Layout
from IPython.display import display, Javascript
from IPython.display import Markdown as md
inSlider = widgets.FloatSlider(
value=1.0,
min=0.0,
max=10.0,
step=0.01,
description='In:',
continuous_update=True
)
output2 = widgets.Output()
def on_detButton_click(b):
if b.description == "Detach":
b.description = "Attach"
# must wrap in display() - Javascript() call on its own does not effectuate!
# https://stackoverflow.com/questions/15193640/jquery-ui-draggable-reset-to-original-position
# NOTE: in spite of zIndex manipulation: do NOT place dragged widget over textarea (it will lose focus),
# also, it will be under a plot.ly diagram regardless!
display(Javascript("""
var $dragwidget = $("div.myctlwidget").parent();
$dragwidget.data({
'originalLeft': $dragwidget.css('left'),
'originalTop': $dragwidget.css('top'),
'originalZindex': $dragwidget.css('z-index')
});
$dragwidget.css({ 'z-index': 5000});
$dragwidget.draggable({ disabled: false, handle: "div.myctlhandle" });
"""))
else:
b.description = "Detach"
display(Javascript("""
var $dragwidget = $("div.myctlwidget").parent();
$dragwidget.draggable({ disabled: true });
$dragwidget.css({
'left': $dragwidget.data('originalLeft'),
'top': $dragwidget.data('originalTop'),
'z-index': $dragwidget.data('originalZindex'),
});
"""))
detButton = widgets.Button(description="Detach")
detButton.on_click(on_detButton_click)
# NB: Button still is visually clickable, even when disabled :(
handleButton = widgets.Label("(h)", _dom_classes = ['myctlhandle'])
myctlwidget = widgets.VBox([widgets.HBox([inSlider, detButton, handleButton])], _dom_classes = ['myctlwidget'])
display(myctlwidget)
#myctlwidget._dom_classes = ['myctlwidget'] # nowork; only added as argument to VBox _dom_classes works!
#print(myctlwidget._dom_classes)
Cell 3 - Python 3:
fig = go.FigureWidget( layout=go.Layout() )
fig.add_trace(go.Scatter(x=[0,10], y=[0,10],
mode='lines',
name='Test plot'))
# set range to prevent autoranging
fig.update_yaxes(range=[0, 11])
def update_graph(change):
with fig.batch_update():
curval = inSlider.value
fig.data[0].y=[0, curval]
inSlider.observe(update_graph, names="value")
#spacer = widgets.VBox([widgets.Text(": :"), widgets.Label(": :")]) # nope
display(md("Markdown here does NOT work as spacer!\n\n... does NOT work as spacer!"))
display(widgets.VBox([fig]))
Related
I have a small problem
assign a value to 2 sliders, works
assign 2 values to strings, works see the values changes when moving the sliders
assign these strings to plt.imshow, get a error.
string qq works on the image, string zz gives the error.
here is a piece off code where the problem occur:
from ipywidgets import interact
#interact(q=(.1, 10))
def f(q=5):
qq=(str(q)+'E3')
#interact(z=(.1, 10))
def f(z=2):
zz=(str(z)+'E3')
plt.figure()
plt.imshow(image_data, cmap='gray', vmin=zz, vmax=qq)
Input In [52], in <cell line: 16>()
11 zz=(str(z)+'E3')
15 plt.figure()
---> 16 plt.imshow(image_data, cmap='gray', vmin=zz, vmax=qq)
NameError: name 'zz' is not defined
thanks.
Willie.
I have a text file like this:
red 5
orange 2
red 7
How would I put it into a dictionary so it says
{red: 12, orange: 2}
I want to get text from a dialog box. I am getting the title from the dialog box using winGetTitle() function.
My code in autoit is as follows:
$pId = Run("C:/foldername/Dialogbox.exe")
Local $hWnd = WinWait("[CLASS:#32770]", "", 10)
Local $sTitle = WinGetTitle("[ACTIVE]")
; Display the window title.
ConsoleWrite($sTitle & #CRLF)
; changing control from the class containg title to the class containing the text.
Local $hSysTray_Handle = ControlGetHandle('[Class:#32770]', '', '[Class:SysListView32;Instance:1]')
Local $sText = WinGetText("[ACTIVE]")
Local $sTextnew = ControlGetText($hSysTray_Handle, "", $sText)
ConsoleWrite($sTextnew & #CRLF)
This returns only the title and not the text in the dialog box. #32770 is the main class of dialog box and title, text are in the different classes in basic control info in autoit.
I am new to autoit and don't know how to fetch the text from dialog box. Or should I use sikuli for this?
; Start Mp3tag if not running.
If Not ProcessExists('Mp3tag.exe') Then
Run('"C:\Program Files (x86)\Mp3tag\Mp3tag.exe"')
If #error Then Exit 1
EndIf
; Scans working directory for Mp3 files.
WinWaitClose('Reading directory', '', 5)
; Main window.
$hWnd = WinWait('Mp3tag')
; Get item count of 1st column from the listview.
For $i1 = 1 To 5
$iCount = ControlListView($hWnd, '', 'SysListView321', 'GetItemCount')
If $iCount Then
ConsoleWrite('Found ' & $iCount & ' items.' & #CRLF)
ExitLoop
EndIf
Sleep(1000)
Next
If Not $iCount Then
MsgBox(0x40000, #ScriptName, 'Count is 0')
Exit 1
EndIf
; Get text of each listview item in the 1st column.
For $i1 = 0 To $iCount -1
$sText = ControlListView($hWnd, '', 'SysListView321', 'GetText', $i1)
ConsoleWrite(StringFormat('%3d Text: %s', $i1, $sText) & #CRLF)
Next
I do not have "C:/foldername/Dialogbox.exe" to test with.
I do have Mp3tag which has a SysListView32 control.
ControlListView() can get text etc. from a ListView control.
The parameter GetItemCount will get the count of list items
and GetText will get text from each list item.
This is test output:
Found 15 items.
0 Text: 01 - Lively Up Yourself.mp3
1 Text: 02 - Soul Rebel.mp3
2 Text: 03 - Treat Yourself Right.mp3
3 Text: 04 - Rebels Hop.mp3
4 Text: 05 - Soul Almighty.mp3
5 Text: 06 - Kaya.mp3
6 Text: 07 - Trenchtown Rock.mp3
7 Text: 08 - Soul Shakedown Party.mp3
8 Text: 09 - Natural Mystic.mp3
9 Text: 10 - Fussing And Fighting.mp3
10 Text: 11 - African Herbsman.mp3
11 Text: 12 - Keep On Moving.mp3
12 Text: 13 - Go Tell It On The Mountain.mp3
13 Text: 14 - How Many Times.mp3
14 Text: 15 - Bonus Track.mp3
The list item number is on the left
and the list item text is on the right,
following Text:.
At a guess, the code to test your Dialogbox.exe with:
Run("C:\foldername\Dialogbox.exe")
$hWnd = WinWait("[CLASS:#32770]", "", 10)
; Allow time for SysListView321 to fully load.
Sleep(1000)
; Get the window title.
$sTitle = WinGetTitle("[ACTIVE]")
ConsoleWrite($sTitle & #CRLF)
; Changing control from the class containing title to the class containing the text.
$hLView = ControlGetHandle($hWnd, '', 'SysListView321')
; Get item count of 1st column from the listview.
$iCount = ControlListView($hWnd, '', $hLView, 'GetItemCount')
; Get text of each listview item in the 1st column.
For $i1 = 0 To $iCount -1
$sText = ControlListView($hWnd, '', $hLView, 'GetText', $i1)
ConsoleWrite(StringFormat('%3d Text: %s', $i1, $sText) & #CRLF)
Next
It could use some improvement even if it works.
When using autoIt to get Window's Text and the WinGetText matches multiple controls (e.g. with the same Class SciCalc in this case), the WinGetText will concatenate the text of all the controls. How can I get the Text of the n-th (say 3rd 'MR') control?
e.g.
Local $output = WinGetText("[CLASS:SciCalc]", "")
print
output:666666.
MC
MR
MS
M+
7
4
1
0
8
5
2
+/-
9
6
3
.
/
*
-
+
=
Backspace
CE
C
1/x
sqt
%
Something like this
ControlGetText("[CLASS:SciCalc]","","[CLASS:Button; INSTANCE:3]")
Use AutoIt Window Info to find the Advanced mode details on the wanted control.
I need to show a find dialog after pressing Ctrl+F in QWidget, which contains a QTableView. The find dialog will search in the first column of the table to find the matches.
I can show the QMessageBox after pressing Ctrl+F with the following code:
class Widget(QWidget):
def __init__(self,md,parent=None):
QWidget.__init__(self,parent)
layout=QVBoxLayout(self)
# initially construct the visible table
tv = QTableView()
# uncomment this if the last column shall cover the rest
tv.horizontalHeader().setStretchLastSection(True)
tv.show()
# set black grid lines
self.setStyleSheet("gridline-color: rgb(39, 42, 49)")
# construct the Qt model belonging to the visible table
model = NvmQtModel(md)
tv.setModel(model)
tv.resizeRowsToContents()
tv.resizeColumnsToContents()
# set the shortcut ctrl+F for find in menu
shortcut = QShortcut(QKeySequence('Ctrl+f'), self)
shortcut.activated.connect(self.handleFind)
# delegate for decimal
delegate = NvmDelegate()
tv.setItemDelegate(delegate)
self.setGeometry(200,200,600,600) # adjust this later
layout.addWidget(tv)
# set window title
self.setWindowTitle("TITLE")
# find function: search in the first column of the table
def handleFind(self):
reply = QMessageBox.question(
self, 'Find', 'Find Dialog',
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
print('Yes')
else:
print('No')
Then I changed the QMessageBox to a QDialog, but now it does not work. I would appreciate if you could tell me where I am not doing it correctly:
class Widget(QWidget):
def __init__(self,md,parent=None):
QWidget.__init__(self,parent)
layout=QVBoxLayout(self)
# initially construct the visible table
tv = QTableView()
# uncomment this if the last column shall cover the rest
tv.horizontalHeader().setStretchLastSection(True)
tv.show()
# set black grid lines
self.setStyleSheet("gridline-color: rgb(39, 42, 49)")
# construct the Qt model belonging to the visible table
model = NvmQtModel(md)
tv.setModel(model)
tv.resizeRowsToContents()
tv.resizeColumnsToContents()
# set the shortcut ctrl+F for find in menu
shortcut = QShortcut(QKeySequence('Ctrl+f'), self)
shortcut.activated.connect(self.handleFind)
# delegate for decimal
delegate = NvmDelegate()
tv.setItemDelegate(delegate)
self.setGeometry(200,200,600,600) # adjust this later
layout.addWidget(tv)
# set window title
self.setWindowTitle("TITLE")
# find function: search in the first column of the table
def handleFind(self):
findDialog = QDialog()
findLabel = QLabel("Find what", findDialog)
findField = QLineEdit(findDialog)
findButton = QPushButton("Find", findDialog)
closeButton = QPushButton("Close", findDialog)
findDialog.show()
If you want the Dialog be a modal Dialog, call findDialog.exec_():
from PyQt4.QtGui import *
def handleFind():
findDialog = QDialog()
#findDialog.setModal(True)
findLabel = QLabel("Find what", findDialog)
findField = QLineEdit(findDialog)
findButton = QPushButton("Find", findDialog)
closeButton = QPushButton("Close", findDialog)
#findDialog.show()
findDialog.exec_()
app = QApplication([])
b = QPushButton("click me")
b.clicked.connect(handleFind)
b.show()
app.exec_()