Matplotlib interactive widget from python script - python-3.x

I am adapting this example to interact with a plot using matplotlib's widgets.
The way I normally work is interactive, from within spyder I just call a function that does the plotting.
My goal is to make an executable available to users who do not have Python installed, so as an intermediate step I am wrapping the functions into a script.
I have minimal experience with standalone scripts, so in a nutshell mine looks like this:
import various_modules
def plotting()
...
plot_some_initial_stuff
sl = Slider()
plt.show() <-------
def update()
...
ax.set_ydata()
fig.canvas.draw_idle()
sl.on_change(update)
return()
plotting()
So I just define the plotting function and then call it.
I had to add the plt.show() command, which I do not need to have when I'm working from the IPython shell, otherwise doing:
python my_plot.py
would not produce anything. By adding plt.show(), the window shows up with the graphs I define in the initialization part. However, no interaction happens.
What is the correct way of achieving interaction when running a script like I'm doing?

Although I do not know all the details, I learnt that:
the default mode for script is non-interactive
this means that
no plot is generated until show() is called
the execution of the script does not proceed after the statement
Therefore, my call to show() was too early and actually blocked the definition of the update function and its connection to the slider.on_change() event.
It has been enough to move show() to the last line of the function definition to obtain the desired behaviour.

Related

python3 tkinter entry widget flash green for ~1 sec without blocking ongoing animation?

everything is working for now but I need to signify good input by flashing the entry box green for ~0.5 sec without blocking the ongoing animation.
I create an entry box using the following code
```python
p = tkinter.Entry(master=root, placeholder_text=P_TGT, width=100)
p.bind("<Return>", update_p)
p.bind("<FocusOut>", update_p)
```
where update_p() executes the following -
```python
p.configure({"foreground": "green"})) #signifies good input
time.sleep(5)
p.configure({"foreground": "white"}) #reset color
```
but this code blocks the execution of the whole app, how do i execute such a startegy without blocking the ongoing animation in tkinter?
Thanks
Tkinter widgets have a method named after which can be used to schedule code to run in the future. after takes as arguments a timeout in milliseconds, a callable, and zero or more positional arguments. The callable will be called with the given arguments as soon as possible after the timeout has been reached.
In your case you can use it to change the color back to white after one second like in the following example.
def update_p():
p.configure({"foreground": "green"}) #signifies good input
p.after(1000, p.configure, {"foreground": "white"})

Can one see the whole definition of user defined function?

I've loaded a couple of functions (f and g) from another script in my jupyter notebook. if I pass the parameters, I am able to get the proper output. My question is, is it possible for me to see the whole definition of the function (f or g)?
I tried to see the function but it shows the memory location that was assigned to it.
You can do this with the built in inspect library.
The below snippet should get you acquainted with how to see the source code of a function.
def hello_world():
print("hello_world")
import inspect
source = inspect.getsource(hello_world)
print(source)
You need to comment your function inside (check docstring, https://www.python.org/dev/peps/pep-0257/) like
def func(a,b):
"""
Wonderful
"""
return a+b
Then in your jupyter notebook you can use Shift + Tab on your function.
I can not comment, but this comes from another thread How can I see function arguments in IPython Notebook Server 3?

Maximize figures before saving

The question about how to do maximize a window before saving has been asked several times and has several questions (still no one is portable, though), How to maximize a plt.show() window using Python
and How do you change the size of figures drawn with matplotlib?
I created a small function to maximize a figure window before saving the plots. It works with QT5Agg backend.
import matplotlib.pyplot as plt
def maximize_figure_window(figures=None, tight=True):
"""
Maximize all the open figure windows or the ones indicated in figures
Parameters
----------
figures: (list) figure numbers
tight : (bool) if True, applies the tight_layout option
:return:
"""
if figures is None:
figures = plt.get_fignums()
for fig in figures:
plt.figure(fig)
manager = plt.get_current_fig_manager()
manager.window.showMaximized()
if tight is True:
plt.tight_layout()
Problems:
I have to wait for the windows to be actually maximized before using the plt.savefig() command, otherwise it is saved with as not maximized. This is a problem if I simply want to use the above function in a script
(minor problems:)
2. I have to use the above function twice in order to get the tight_layout option working, i.e. the first time tight=True has no effect.
The solution is not portable. Of course I can add all the possible backend I might use, but that's kind of ugly.
Questions:
how to make the script wait for the windows to be maximized? I don't want to use time.sleep(tot_seconds) because tot_seconds would be kind of arbitrary and makes the function even less portable
how to solve problem 2 ? I guess it is related to problem 1.
is there a portable solution to "maximize all the open windows" problem?
-- Edit --
For problem 3. #DavidG suggestion sounds good. I use tkinter to automatically get width and height, convert them to inches, and use them in fig.set_size_inches or directly during the figure creation via fig = plt.figure(figsize=(width, height)).
So a more portable solution is, for example.
import tkinter as tk
import matplotlib.pyplot as plt
def maximize_figure(figure=None):
root = tk.Tk()
width = root.winfo_screenmmwidth() / 25.4
height = root.winfo_screenmmheight() / 25.4
if figure is not None:
plt.figure(figure).set_size_inches(width, height)
return width, height
where I allow the figure to be None so that I can use the function to just retrieve width and height and use them later.
Problem 1 is still there, though.
I use maximize_figure() in a plot function that I created (let's say my_plot_func()) but still the saved figure doesn't have the right dimensions when saved on file.
I also tried with time.sleep(5) in my_plot_func() right after the figure creation. Not working.
It works only if a manually run in the console maximize_figure() and then run my_plot_func(figure=maximized_figure) with the figure already maximized. Which means that dimension calculation and saving parameters are correct.
It does not work if I run in the console maximize_figure() and my_plot_func(figure=maximized_figure) altogether, i.e. with one call the the console! I really don't get why.
I also tried with a non-interactive backend like 'Agg', so that the figure doesn't get actually created on screen. Not working (wrong dimensions) no matter if I call the functions altogether or one after the other.
To summarize and clarify (problem 1):
by running these two pieces of code in console, figure gets saved correctly.
plt.close('all')
plt.switch_backend('Qt5Agg')
fig = plt.figure()
w, h = maximize_figure(fig.number)
followed by:
my_plot_func(out_file='filename.eps', figure=fig.number)
by running them together (like it would be in a script) figure is not saved correctly.
plt.close('all')
plt.switch_backend('Qt5Agg')
fig = plt.figure()
w, h = maximize_figure(fig.number)
my_plot_func(out_file='filename.eps', figure=fig.number)
Using
plt.switch_backend('Agg')
instead of
plt.switch_backend('Qt5Agg')
it does not work in both cases.

pyldavis Unable to view the graph

I am trying to visually depict my topics in python using pyldavis. However i am unable to view the graph. Is it that we have to view the graph in the browser or will it get popped upon execution. Below is my code
import pyLDAvis
import pyLDAvis.gensim as gensimvis
print('Pyldavis ....')
vis_data = gensimvis.prepare(ldamodel, doc_term_matrix, dictionary)
pyLDAvis.display(vis_data)
The program is continuously in execution mode on executing the above commands. Where should I view my graph? Or where it will be stored? Is it integrated only with the Ipython notebook?Kindly guide me through this.
P.S My python version is 3.5.
This not work:
pyLDAvis.display(vis_data)
This will work for you:
pyLDAvis.show(vis_data)
I'm facing the same problem now.
EDIT:
My script looks as follows:
first part:
import pyLDAvis
import pyLDAvis.sklearn
print('start script')
tf_vectorizer = CountVectorizer(strip_accents = 'unicode',stop_words = 'english',lowercase = True,token_pattern = r'\b[a-zA-Z]{3,}\b',max_df = 0.5,min_df = 10)
dtm_tf = tf_vectorizer.fit_transform(docs_raw)
lda_tf = LatentDirichletAllocation(n_topics=20, learning_method='online')
print('fit')
lda_tf.fit(dtm_tf)
second part:
print('prepare')
vis_data = pyLDAvis.sklearn.prepare(lda_tf, dtm_tf, tf_vectorizer)
print('display')
pyLDAvis.display(vis_data)
The problem is in the line "vis_data = (...)".if I run the script, it will print 'prepare' and keep on running after that without printing anything else (so it never reaches the line "print('display')).
Funny thing is, when I just run the whole script it gets stuck on that line, but when I run the first part, got to my console and execute purely the single line "vis_data = pyLDAvis.sklearn.prepare(lda_tf, dtm_tf, tf_vectorizer)" this is executed in a couple of seconds.
As for the graph, I saved it as html ("simple") and use the html file to view the graph.
I ran into the same problem (I use PyCharm as IDE) The problem is that pyLDAvize is developed for Ipython (see the docs, https://media.readthedocs.org/pdf/pyldavis/latest/pyldavis.pdf, page 3).
My fix/workaround:
make a dict of lda_tf, dtm_tf, tf_vectorizer (eg., pyLDAviz_dict)dump the dict to a file (eg mydata_pyLDAviz.pkl)
read the pkl file into notebook (I did get some depreciation info from pyLDAviz, but that had no effect on the end result)
play around with pyLDAviz in notebook
if you're happy with the view, dump it into html
The cause is (most likely) that pyLDAviz expects continuous user interaction (including user-initiated "exit"). However, I rather dump data from a smart IDE and read that into jupyter, than develop/code in jupyter notebook. That's pretty much like going back to before-emacs times.
From experience this approach works quite nicely for other plotting rountines
If you received the module error pyLDA.gensim, then try this one instead:
import pyLdAvis.gensim_models
You get the error because of a new version update.

Preventing jedi to complete everything after space

I am trying to use jedi to complete python code inside a PyQt application, using QCompleter and QStringListModel to store the possible completion.
Here's a simple working demo:
#!/usr/bin/env python3
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import jedi
import sys
class JediEdit(QLineEdit):
def __init__(self, parent=None):
super().__init__(parent)
self._model = QStringListModel()
self._compl = QCompleter()
self._compl.setModel(self._model)
self.setCompleter(self._compl)
self.textEdited.connect(self.update_model)
def update_model(self, cur_text):
script = jedi.Script(cur_text)
compl = script.completions()
strings = list(cur_text + c.complete for c in compl)
self._model.setStringList(strings)
if __name__ == '__main__':
app = QApplication(sys.argv)
line = JediEdit()
line.show()
sys.exit(app.exec_())
If you run the application and write a code which is not completing anything (e.g. or foo =), the completion will actually show all the possible tokens that can go in that position.
So, if I run and write a space in the field, lots of things pops up, from abs to __version__.
I would like to prevent this: is it possible to query jedi.Script to understand if the token is being completed or if a completely new token is starting?
EDIT: another little question: say that I am running an interpreter which is detached from jedi current state. How can I provide local and global variables to jedi.Script so that it will take into account those, instead of its own completions?
Autocompletion
Jedi's autocompletion will always show all possible tokens in a place. That's the whole point in autocompletion.
If you don't want that behavior just scan the last few characters for whitespace and certain other characters like = or :, it would be a very simple regex command. (You could also try to look up Jedi's internals and use the way how Jedi knows about this context. However I'm not going to tell you, because it's not a public API and IMHO regex calls suffice.)
In the future something like that might be possible. (See https://github.com/davidhalter/jedi/issues/253).
Now that I think about it, there might be another way that you could experiment with this: You can try to play with Completion.name and Completion.complete. The latter only gives you what could come after the current token, while the name would be the full thing. So you can compare and if they are equal than you might not want to display anything.
Have fun playing with the API :-)
Interpreter
If you're running an interpreter, you can use jedi.Interpreter to combine code with actual Python objects. It's pretty flexible. But please note that the current Interpreter (0.8.1) is very buggy. Please use the master branch from Github (0.9.0).

Resources