I am a newbie with PyScript.
The following code correctly prints a single plot on the browser.
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<pre>
<py-env>
- numpy
- matplotlib
</py-env>
</pre>
</head>
<body>
<div id="matplotlib-lineplot">
<pre>
<py-script output="matplotlib-lineplot" >
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
year_1 = [2016, 2017, 2018, 2019, 2020, 2021]
population_1 = np.random.randint(20,size=6)
plt.plot(year_1, population_1, marker='o', linestyle='--', color='g', label='Country 1')
plt.xlabel('Year')
plt.ylabel('Population (M)')
plt.title('Year vs Population')
plt.legend(loc='lower right')
fig
</py-script>
</pre>
</div>
</body>
</html>
I would like to extend this to printing 20 plots one after another in a loop and then stop at the final plot. For this I am trying:
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<pre>
<py-env>
- numpy
- matplotlib
</py-env>
</pre>
</head>
<body>
<div id="matplotlib-lineplot">
<pre>
<py-script output="matplotlib-lineplot" >
import matplotlib.pyplot as plt
import numpy as np
for step in range(20):
fig, ax = plt.subplots()
year_1 = [2016, 2017, 2018, 2019, 2020, 2021]
population_1 = np.random.randint(20,size=6)
plt.plot(year_1, population_1, marker='o', linestyle='--', color='g', label='Country 1')
plt.xlabel('Year')
plt.ylabel('Population (M)')
plt.title('Year vs Population')
plt.legend(loc='lower right')
fig
</py-script>
</pre>
</div>
</body>
</html>
Which prints nothing. How would go about this?
I have also tried replacing fig
with plt.show()
, which also shows nothing.
I believe an alternative is to use IPython.display()
but importing IPython throws an error ModuleNotFoundError: No module named 'termios' )
on my mac.
EDIT: After looking into the official docs I realised I was using an outdated way for printing. So I updated to:
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<py-config>
packages = ["matplotlib", "numpy"]
</py-config>
</head>
<body>
<py-script>
import matplotlib.pyplot as plt
import numpy as np
import time
for step in range(20):
fig, ax = plt.subplots()
year_1 = [2016, 2017, 2018, 2019, 2020, 2021]
population_1 = np.random.randint(20,size=6)
plt.plot(year_1, population_1, marker='o', linestyle='--', color='g', label='Country 1')
plt.xlabel('Year')
plt.ylabel('Population (M)')
plt.title('Year vs Population')
plt.legend(loc='lower right')
display(fig, target="graph-area", append=False)
time.sleep(1)
plt.clf()
</py-script>
<div id="graph-area"></div>
</body>
</html>
But this prints a single figure
This issue in your final block of code (following EDIT) is the use of time.sleep()
, which essentially instructs the operating system to leave the current thread alone for the given number of seconds, and resume execution of it at a later point. However, the browser is inherently a single-thread-per-tab environment* - there is no "other thread" to come back and "wake up" the current thread. So your execution is stuck at the first call of time.sleep
.
(*This is true in the current version of PyScript (2023.03.1) - in a future release, PyScript will have the option to run in Web Worker thread, in a way which allows for blocking operations like this.)
To fix your issue, use a coroutine with asyncio.sleep
like so:
import matplotlib.pyplot as plt
import numpy as np
import asyncio
async def showPlots():
for step in range(20):
fig, ax = plt.subplots()
year_1 = [2016, 2017, 2018, 2019, 2020, 2021]
population_1 = np.random.randint(20,size=6)
plt.plot(year_1, population_1, marker='o', linestyle='--', color='g', label='Country 1')
plt.xlabel('Year')
plt.ylabel('Population (M)')
plt.title('Year vs Population')
plt.legend(loc='lower right')
display(fig, target="graph-area", append=False)
await asyncio.sleep(1)
plt.clf()
asyncio.ensure_future(showPlots())