Pysimplegui: Logscale slider

Created on 19 Jun 2019  路  24Comments  路  Source: PySimpleGUI/PySimpleGUI

Type of Issues (Enhancement, Error, Bug, Question)

Enhancement.

Operating System

Linux.

Python version

3+

PySimpleGUI Port and Version

Tk. 3.39

Code or partial code causing the problem

NA

Currently (AFAIK), Slider only support linear scale (that too in Int, I gues. But see #1039 ). Is there a way to get slider in log scale e.g., [0.1, 1.0, 10.0, 100.0, etc.] values. There might be a simple hack to achieve this e.g., https://stackoverflow.com/questions/7160864/logarithmic-scale-in-tkinter

All 24 comments

This is one you can easily do yourself.

Setup the Slider to go from 1 to 100. Disable the numeric display that the slider does for you. Then simply use the slider value in a function that maps 1 to 100 to 0.1 to ?.

If you want you can create a text field and display your calculated value. This is what I called a compound element in this Demo Program:
https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Spinner_Compound_Element.py
In the demo I'm using a spinner but it could just as easily be a slider.

Finally, if you are going to display your computed value in realtime, then be sure and enable events for the slider.

Here's a short demo:

import PySimpleGUI as sg

layout = [
            [sg.Text('Log Demo')],
            [sg.Slider((1,100),
                       disable_number_display=True, 
                       enable_events=True,
                       orientation='h', 
                       key='_SLIDER_'), 
             sg.Text('', size=(10,1), key='_OUT_')],
            [sg.Button('Do Something'), sg.Button('Exit')]
         ]

window = sg.Window('Window Title', layout)

while True:             # Event Loop
    event, values = window.Read()
    print(event, values)
    if event in (None, 'Exit'):
        break
    window.Element('_OUT_').Update(1/10**int(values['_SLIDER_']))
window.Close()

Thanks.

Just a thought: if this all could be wrapped into the library itself. I am thinking like passing an argument log_scale=2 (default None) would automatically create log-scale ticks and set up the Update function. If this does not break the existing API, it would be super convenient.

PS: I just uploaded a simple Oscilloscope based on your library to PyPI (still a work in progress) https://pypi.org/project/SerialScope/ .

The larger over-arching issue is that when parameters like this are changed, especially to an Element, it must be ported across 4 different ports. Some of these may not support this kind of slider natively.

If not supplied by the GUI, then it becomes a wrapper as you've suggested. Generally speaking, unless something is REALLY difficult to do by the user, I don't add convenience code. I recently posted the criteria I run through for new features. If the user is able to do it on their own, it generally doesn't go in. I'm focused on bringing new features to users that they are unable to do using their own code. There's simply too much to do.

You're fortunate that implementing this so trivial within your code. It's a single line of code, right?

I like the SerialScope idea. Unfortunately I don't have a board capable of running the code. Can I suggest a few things that would help boost your project (in my opinion)?

  • Add images, preferably animated GIFs to your README on PyPI

    • Nothing gets people more excited about a project than seeing pictures

    • Your user is interacting with your program through a visual interface, you're more likely to get someone to install your package if they get a sneak peek

    • The more the better

    • It appears the readme on the GitHub does have an image but PyPI version is out of date. You've got a 0.0.1 Readme in your 0.0.3 Release.

  • Create settings so that you can run it in an simulated environment

    • Add code so that you can run on Windows, Linux, etc, without the need for special hardware

    • Generate data to be displayed rather than reading from serial interface

    • This enables you to debug your GUI and other code on a platform with more capabilities to help debug

Ooops... I spoke too soon about the need to run on Windows. Your code does indeed run on my Windows machine with no problem. I don't see any waveforms, but I can at least play with the GUI Elements

image

I hadn't taken a close look at the stack overflow example until later in the day today, well after I had released this implementation. It appears that the person on Stack Overflow proposed a solution that's very similar to mine :-)

His line of code:
self.number = (10**(int(val)))

My line of code:
1/10**int(values['_SLIDER_']

Mine was 1/10^slider, his was 10^ slider.

Thanks for the pointers. I've tried to implement some of them. This scope is meant for upcoming neuro course (Unix platform). It seems to me that TkInter GUI is slow to respond; and for better performance I may have to port it to C++/Qt5. Currently it seems to be behaving satisfactorly with Arduino Uno.

You can always try Qt through PySimpleGUI by running PySimpleGUIQt instead of PySimpleGUI.

Too slow? How fast does one of your event loop revolutions need to be?

I get ~12k data points per second from Arduino. That's 6k per channel. I draw all of them and update the canvas every 200 points or so. Once the canvas is filled, I clean up.

So I have roughly 0.1ms second resolution. Currently I launch a separate thread to fill a queue and let gui consume this queue as fast as possible.

On 24 June 2019 7:44:35 AM IST, MikeTheWatchGuy notifications@github.com wrote:

Too slow? How fast does one of your event loop revolutions need to be?

--
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub:
https://github.com/PySimpleGUI/PySimpleGUI/issues/1584#issuecomment-504814651

--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

If you want to move to Qt, I can try and make that possible by completing the missing drawing primitives that you may need. They must get completed at some point and I often tie these kinds of features to user requests. I have found Qt can indeed have a significant difference in speed. It depends on the operations. Sometimes tkinter's lightweight arch is faster, sometimes it's 2 or 3 times slower.

I'll stick to tkinter for now. It has been working on OsX and windows. And it's lightweight during installation. It's fast enough for our need.

Though I've been looking at flexx, not sure how does it perform.

On 24 June 2019 10:25:23 PM IST, MikeTheWatchGuy notifications@github.com wrote:

If you want to move to Qt, I can try and make that possible by
completing the missing drawing primitives that you may need. They must
get completed at some point and I often tie these kinds of features to
user requests. I have found Qt can indeed have a significant
difference in speed. It depends on the operations. Sometimes
tkinter's lightweight arch is faster, sometimes it's 2 or 3 times
slower.

--
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub:
https://github.com/PySimpleGUI/PySimpleGUI/issues/1584#issuecomment-505092673

--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

I'm stunned by your event loop timing. Maybe we misunderstood each other. My question is how fast are you making it through one revolution of the event loop. A figure is 0.1 ms, 100us is extraordinary. Normally we're talking 1 ms on a high-end machine with nothing else happening inside the event loop. But, maybe you've got special hardware or aren't doing anything in your loop yet.

True that tkinter is the lightweight choice between the two. WxPython is another choice but doubt I've got the drawing primitives done.

The Web version may work oddly enough. I'll give it a go.

Everything suddenly stopped working for me. Were there any changes to the code? I did a new download from GitHub. Maybe I'm running the wrong file? I can't tell exactly what's what from the list of files. Nothing jumps out at me at the "RUN_ME.py" file.

I'm stunned by your event loop timing. Maybe we misunderstood each other. My question is how fast are you making it through one revolution of the event loop. A figure is 0.1 ms, 100us is extraordinary. Normally we're talking 1 ms on a high-end machine with nothing else happening inside the event loop. But, maybe you've got special hardware or aren't doing anything in your loop yet.

I see. I am sorry; I conflated two processes. Here how it is implemented.
The arduino reader SerialScope/arduino.py is launch in a separate thread. It reads data from arduino if found or generate dummy data and put it into a shared queue. The rate at which this queue is filled is 1 event per 0.1ms. This queue is shared with gui (SerialScope/gui.py file). I am not calling a function at fixed time interval which reads this queue and plot lines; but another threads 'inject' values into main window and every 200 points or so (i.e. ~20 ms); I draw these points and update the canvas.

The entry point for this app is SerialScope/__main__.py which can be invoked by python3 -m SerialScope. The naming scheme of files and functions is bit loose/ I need to refactor quite a lot of code.

Everything suddenly stopped working for me. Were there any changes to the code? I did a new download from GitHub. Maybe I'm running the wrong file? I can't tell exactly what's what from the list of files. Nothing jumps out at me at the "RUN_ME.py" file.

The master branch is working for me. After downloading and unpacking (or after git pull)

 $ make test

Will launch the GUI (this executes the following command)

  $ python3 -m SerialScope

If you want to run a specific file say SerialScope/arduino.py then

  $ python3 -m SerialScope.arduino

This is how I understand how python3 works with absolute imports in scripts (-m). It was easier in python2 with relative imports.

I'm running from an IDE, using the downloaded GitHub contents.

I'm running on Windows, so make test won't do anything. I'm pretty sure previously I was running one of the .py file directly from the IDE. I just don't recall which it was.

I just found __main__.py which seems like the logical thing to run. This time I was able to get a window to stay up! However, I don't get the simulated data as before and it eventually freezes.

I also am having trouble with the from SerialScope import.... statements since I'm running directly within the SerialScope folder.

Do you have a setup that allows the use of an IDE?

I consulted stackoverflow and some other places: looks like after python3.3, import mechanism is full of traps (and https://stackoverflow.com/questions/25583756/using-absolute-import-while-in-developing-python-modules).

The easiest solution I could think of is to set PYTHONPATH in your IDE. For SerialScope

$ git clone https://github.com/dilawar/SerialScope /path/to/SerialScope
$ export PYTHONPATH=/path/to/SerialScope

(__not__ to /path/to/SerialScope/SerialScope)

I guess I'm questioning why I need to do these things when there are no other packages I need to do this. Is there something specific about your imports that are both unique and required?

I just found main.py which seems like the logical thing to run. This time I was able to get a window to stay up! However, I don't get the simulated data as before and it eventually freezes.

It is freezing for me as well on a Windows 7 desktop. Though it is working fine on Unix systems (linux and OSX). I guess threading module is not very performant on Windows. Needs some debugging on Windows machine.

I guess I'm questioning why I need to do these things when there are no other packages I need to do this. Is there something specific about your imports that are both unique and required?

Frankly I don't know a better way to write python3 modules. With python2, things were less complicated. This I learned from a tutorial and now I just use it. Since it is not IDE friendly, I'd be happy to refactor the code. Any pointers?

And I forget to thank you for testing the module :-). I really appreciate it.

The freezing behaviour is because Graph.DrawLine is taking too long. Not sure if this is a TK+Windows problem. There were other minor issues such as time.sleep is not very precise on Win.

It's unlikely that there would be a problem with threading on the Windows Python release.

About DrawLine. Are you using it to draw many lines that come and go? If so, you should call DeleteFigure when you are done with it. Otherwise you'll get a memory leak which certainly could lead to a performance problem. It depends on when you see the "Freezing behavior".

If you want to do some timing, there are a couple of function calls built-in to PySimpleGUI. TimerStart() and TimerStop(). Stop will print out how long the time span was.

If you're using tkinter, it must not be run in a thread.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ihouses picture ihouses  路  6Comments

MikeTheWatchGuy picture MikeTheWatchGuy  路  3Comments

thelou1s picture thelou1s  路  4Comments

DKatarakis picture DKatarakis  路  6Comments

flowerbug picture flowerbug  路  4Comments