Is there a way to detach matplotlib plots so that the computation can continue?
Use matplotlib
's calls that won't block:
Using draw()
:
from matplotlib.pyplot import plot, draw, show
plot([1,2,3])
draw()
print('continue computation')
# at the end call show to ensure window won't close.
show()
Using interactive mode:
from matplotlib.pyplot import plot, ion, show
ion() # enables interactive mode
plot([1,2,3]) # result shows immediatelly (implicit draw())
print('continue computation')
# at the end call show to ensure window won't close.
show()
python: how to keep the script run after plt.show()
I did have a similar problem and found solution here on SO.I think that you need plt.ion().One example
import numpy as np
from matplotlib import pyplot as plt
def main():
plt.axis([-20,20,0,10000])
plt.ion()
plt.show()
x = np.arange(-20, 21)
for pow in range(1,5): # plot x^1, x^2, ..., x^4
y = [Xi**pow for Xi in x]
plt.plot(x, y)
plt.draw()
plt.pause(0.001)
input("Press [enter] to continue.")
if __name__ == '__main__':
main()
Works fine,although it gives this warning
MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented
warnings.warn(str, mplDeprecation)
I am not sure if that is related to 3.6 version or not.
matplotlib.plot.show continues shows plots even the script finished
The plots will close when the script is finished, even if you use block=False
Similar to the answer here, when running from the terminal you have to call plt.show
at the end of the script to keep these plots open after you've finished. I made a similar code to yours which works as intended; the plot simply refreshes at the end of the code. (added a for loop for a 5 second delay just so you can see it's running).
import numpy as np
import matplotlib.pyplot as plt
import time
if __name__ == '__main__':
plt.figure(figsize=(10, 10))
plt.plot(range(5), lw=2, label='Real')
plt.title('Prediction')
plt.legend(loc="best")
plt.show(block=False)
print("---Plot graph finish---")
for i in range(5):
print('waiting...{}'.format(i))
time.sleep(1)
print('code is done')
plt.show()
Plotting in a non-blocking way with Matplotlib
I spent a long time looking for solutions, and found this answer.
It looks like, in order to get what you (and I) want, you need the combination of plt.ion()
, plt.show()
(not with block=False
) and, most importantly, plt.pause(.001)
(or whatever time you want). The pause is needed because the GUI events happen while the main code is sleeping, including drawing. It's possible that this is implemented by picking up time from a sleeping thread, so maybe IDEs mess with that—I don't know.
Here's an implementation that works for me on python 3.5:
import numpy as np
from matplotlib import pyplot as plt
def main():
plt.axis([-50,50,0,10000])
plt.ion()
plt.show()
x = np.arange(-50, 51)
for pow in range(1,5): # plot x^1, x^2, ..., x^4
y = [Xi**pow for Xi in x]
plt.plot(x, y)
plt.draw()
plt.pause(0.001)
input("Press [enter] to continue.")
if __name__ == '__main__':
main()
Matplotlib: Is there a way so that we can see and work with plot result while the routines after the `.show()` is being processed by Python?
You could use a combination of a separate python process (via multiprocessing) and the blocking behaviour of plt.show() to achieve the desired result:
import matplotlib.pyplot as plt
import time
from multiprocessing import Process
def show_plot(data):
fig, ax = plt.subplots()
ax.plot(data)
plt.show()
def do_calculation():
for i in range(100):
print(i)
time.sleep(0.1)
if __name__ == '__main__':
p = Process(target=show_plot, args=([1,2,3],))
p.start() # start parallel plotting process
do_calculation()
p.join() # the process will terminate once the plot has been closed
Plotting matplotlib plots in pyscript when a button is clicked
To make it work you should have a button listener defined to ensure the call back. To do that use create_proxy function and then process the button.
It looks like this:
1. index.html
I moved your python code to main.py file to have html more readable. Added - paths: in py-env node and src="./main.py" in py-script node. There are some stylings for the button and a hidden div that I use if there are more buttons to control all of them with the same button processing function.
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<py-env>
- matplotlib
- paths:
./main.py
</py-env>
<style>
.button:hover {
background: #d9d9d9;
}
.button {
text-decoration: none;
display: inline;
padding: 5px;
width: 120px;
font-size: 1em;
background: #afc7b5;
color: darkgreen;
font-weight: bold;
}
</style>
</head>
<body>
<h1>Matplotlib</h1>
<div hidden id="evtMsg">0</div>
<py-script> print("My Lineplot")</py-script>
<div id="lineplot"></div>
<button id="plot-button" onClick="document.getElementById('evtMsg').innerHTML=100" class="button" style="">Plot</button>
<py-script src="./main.py"></py-script>
</body>
</html>
2. main.py
Your code is here along with imports and listener definition and button processing code. I changed the name of your function to plot_it and declared it asynchronous.
import matplotlib.pyplot as plt
import asyncio
from pyodide import create_proxy
def Setup_Button_Listeners():
btnList = document.querySelectorAll(".button")
for i in range(len(btnList)):
e = document.getElementById(btnList[i].id)
btn_event = create_proxy(Process_Button)
e.addEventListener("click", btn_event)
#
#
async def Process_Button(event):
if document.getElementById("evtMsg").innerHTML == '100': # button plot_it
fig = await plot_it()
pyscript.write('lineplot', fig)
async def plot_it(*args, **kwargs):
fig, ax = plt.subplots()
year_1 = [2016, 2017, 2018, 2019, 2020, 2021]
population_1 = [42, 43, 45, 47, 48, 50]
year_2 = [2016, 2017, 2018, 2019, 2020, 2021]
population_2 = [43, 43, 44, 44, 45, 45]
plt.plot(year_1, population_1, marker='o', linestyle='--', color='g', label='Country 1')
plt.plot(year_2, population_2, marker='d', linestyle='-', color='r', label='Country 2')
plt.xlabel('Year')
plt.ylabel('Population (M)')
plt.title('Year vs Population')
plt.legend(loc='lower right')
fig
return fig
Setup_Button_Listeners()
This way, when page loaded, the button listener will be established waiting for you to click it. When you do - the proxy will call Process_Button function where you can do whatever you want to do with that button clicked. Regards...
Multiple mouse pick event Error on thinker Matplotlib Canvas plots
event
doesn't care what you clicked. It runs both functions when you click object on canvas.
And different objects have different functions and you should check instance
of event.artist
to run correct code for clicked object.
def onpick(event):
print('onpick', event.artist)
if isinstance(event.artist, matplotlib.lines.Line2D):
thisline = event.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = event.ind
print(xdata[ind][0])
self.points = []
self.points.append([xdata[ind][0], ydata[ind][0]])
print('this point click on polygon', self.points)
def onpick2(event):
print('onpick2', event.artist)
if isinstance(event.artist, matplotlib.collections.PathCollection):
index = event.ind
xy = event.artist.get_offsets()
print ('hi scatter', xy[index])
You can even put all in one function.
def onpick(event):
print('onpick', event.artist)
if isinstance(event.artist, matplotlib.lines.Line2D):
thisline = event.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = event.ind
print(xdata[ind][0])
self.points = []
self.points.append([xdata[ind][0], ydata[ind][0]])
print('this point click on polygon', self.points)
if isinstance(event.artist, matplotlib.collections.PathCollection):
index = event.ind
xy = event.artist.get_offsets()
print ('hi scatter', xy[index])
Related Topics
Non-Alphanumeric List Order from Os.Listdir()
Importerror: Dll Load Failed: %1 Is Not a Valid Win32 Application. But the Dll's Are There
Pandas: Drop Consecutive Duplicates
Why Python 3.6.1 Throws Attributeerror: Module 'Enum' Has No Attribute 'Intflag'
Intuition and Idea Behind Reshaping 4D Array to 2D Array in Numpy
What Are the Arguments to Tkinter Variable Trace Method Callbacks
Scrape Multiple Urls Using Qwebpage
Python Socket Not Receiving Without Sending
How to Convert a Utc Datetime to a Local Datetime Using Only Standard Library
How to Delete Items from a Dictionary While Iterating Over It
What Is the Standard Way to Add N Seconds to Datetime.Time in Python
Unicodedecodeerror: 'Utf8' Codec Can't Decode Byte 0Xa5 in Position 0: Invalid Start Byte
How to Save a New Sheet in an Existing Excel File, Using Pandas
Differencebetween a Function, an Unbound Method and a Bound Method