0

writing a program which supplies user with the roots and vertex of a quadratic curve, and then requires the user to input the correct calculated equation, then producing the the graph which satisfies provided roots and vertex.

I have simplified the problem. Basically, I want to produce a graph (or point plot in this case), then run some code, then add the graph to the existing plot. Im not very fluent with matplotlib so excuse any wrong terminology and try keep your answer noobie-friendly.

import matplotlib.pyplot as plt
import numpy as np

plt.plot(5, 0, marker='o', markersize=3, color="red")
plt.show(block=False)
if input(">") == "a":
    x = np.arange(-6, 6, 0.01)
    y = -10/25*(x)**2 + 10
    plt.plot(x,y)
    plt.show()

My results: blank window produced will only show both graphs once the condition is met. Desired results: window show first point plot, then same window will show graph.

James
  • 1
  • 2
  • So when the plot starts you want it to just show the single point you've plotted? And that's the only issue you are having, right? – Reedinationer Mar 26 '19 at 21:06

1 Answers1

0

It looks like to do this you need to implement plt.pause() and plt.draw() and the window will update. My code that does what you want (I think) is:

import matplotlib.pyplot as plt
import numpy as np

plt.ion()
plt.show()
plt.plot(5, 0, marker='o', markersize=3, color="red")
plt.draw()
plt.pause(0.001)
if input(">") == "a":
    x = np.arange(-6, 6, 0.01)
    y = -10/25*(x)**2 + 10
    plt.plot(x, y)
    plt.draw()
    plt.pause(0.001)
    input('press enter to continue')

Where I used the techniques as described in the accepted answer at Plotting in a non-blocking way with Matplotlib I'm not sure if my code can be simplified more of not, but it seems to do what you are aiming for! Let me know if this was what you were asking, or if I was unclear/off topic.

From the documentation of plt.ion() at https://matplotlib.org/api/_as_gen/matplotlib.pyplot.ion.html?highlight=ion#matplotlib.pyplot.ion

Turn the interactive mode on.

From the documentation for plt.pause() at https://matplotlib.org/api/_as_gen/matplotlib.pyplot.pause.html?highlight=pause#matplotlib.pyplot.pause

Pause for interval seconds.

If there is an active figure, it will be updated and displayed before the pause, and the GUI event loop (if any) will run during the pause.

This can be used for crude animation. For more complex animation, see matplotlib.animation.

Notes

This function is experimental; its behavior may be changed or extended in a future release.

Finally the plt.draw() documentation (https://matplotlib.org/api/_as_gen/matplotlib.pyplot.draw.html?highlight=pyplot%20draw#matplotlib.pyplot.draw) states

Redraw the current figure.

This is used to update a figure that has been altered, but not automatically re-drawn. If interactive mode is on (ion()), this should be only rarely needed, but there may be ways to modify the state of a figure without marking it as stale. Please report these cases as bugs.

A more object-oriented alternative, given any Figure instance, fig, that was created using a pyplot function, is:

fig.canvas.draw_idle()

So my understanding of these functions is that the plt.ion() puts it into interactive mode and is preferred to plt.show(block=False) as the block=False is deprecated (according to the linked answer above). Once you've generated your plot you draw to it, and then you need to run the GUI loop to actually show it has changed so you run plt.pause(). From the description of plt.draw() though I think you can omit this and go straight to plt.pause() to update the image (I did not test to confirm this though)

UPDATE

It seems you are begging XD for a code that will continually plot to the same axis. Here is how you can do that with threading (you should thread events that have to do computations so your GUI doesn't freeze)

from matplotlib.figure import  Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import threading
import random
import time

root = tk.Tk()
root.withdraw()

def _destroyWindow():
    root.quit()
    root.destroy()

root.protocol('WM_DELETE_WINDOW', _destroyWindow)
fig = Figure(figsize=(12, 8), facecolor='white')
axis = fig.add_subplot(111)
xValues = [1, 2, 3, 4]
yValues = [5, 7, 6, 8]
axis.plot(xValues, yValues)
axis.set_xlabel('Horizontal Label')
axis.set_ylabel('Vertical Label')
axis.grid(linestyle='-')
canvas = FigureCanvasTkAgg(fig, master=root)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)

def get_new_data():
    while True:
        print('plotting new values')
        xValues = [random.randint(1, 5) for _ in range(4)]
        yValues = [random.randint(1, 5) for _ in range(4)]
        axis.plot(xValues, yValues)
        fig.canvas.draw_idle()
        time.sleep(1)

def thread_maker():
    t = threading.Thread(target=get_new_data)
    t.start()

thread_maker()

root.update()
root.deiconify()
root.mainloop()
Community
  • 1
  • 1
Reedinationer
  • 5,661
  • 1
  • 12
  • 33
  • Thanks a lot, this works for me so far. Could you explain what plt.ion(), plt.show() and plt.pause() do? Update: Slight problem, before the condition is met, when just the point is showing, if I drag my mouse across the window the loading circle appears. If I click on the window is then goes into "not responding" mode. How can I deal with this? – James Mar 27 '19 at 14:43
  • You need it to be clickable? It might be better to draw it on a `tkinter` canvas object then... – Reedinationer Mar 27 '19 at 16:29
  • Ok, thanks for all the information. Only had a little look at tkinter. Seeing as I want the matplotlib window, input/output window and possibly a calculator, all in one. Could you guide me in the right direction, as to what aspects of tkinter I will need to use. – James Mar 30 '19 at 11:47
  • @James The matplotlib plot would have to be a Canvas object. As for the input/output there are many widgets that would be suitable. I use the site http://effbot.org/tkinterbook/ when creating GUIs and you can look through all the widgets to find what you deem most appropriate. There is also a “ttk” module within tkinter that is more advanced but gives more fine tuned control of your GUI. There are many approaches for how to solve your problem such as putting each widget in its own tab, or all in one tab, whether you use .pack() .grid() or .place() on your widgets (don’t mix them), etc... – Reedinationer Mar 31 '19 at 17:31
  • Don't mean to be a beg but if you could knock up the basic code for drawing the matplotlib graph to a tkinter window. The tkinter window should conserve the single figure and not create a new figure for each update. Had a look at multiple different tutorials but can't apply my logic to it. Thanks for your support. – James Apr 02 '19 at 13:36