"""
**Interface to the plot window manager**
The plotting happens in a separate thread (process) so the plot windows remain
responsive even if the main thread does some computation. No additional user
intervention is needed (like calling some refresh function from time-to time).
An example will explain more than ten paragraphs of text::
from pyopus.plotter import interface as pyopl
from numpy import arange, sin, cos, exp, pi, e
# Plot data - sin(x), cos(x), exp(x/pi) .. for x in [0, 2pi] with 0.2 step.
x = arange(0.0, 2*pi, 0.2)
y1 = sin(x)
y2 = cos(x)
y3 = exp(x/pi)
# Create first figure (plot window). This is now the active figure.
# Tag is assigned automatically by the system.
fig=pyopl.figure(windowTitle="Figure - single axes", figpx=(600,400), dpi=100)
# Lock the main GUI event loop. This implicitly disables repainting.
pyopl.lock(True)
# If the window is closed accessing any attribute results in an exception.
# To check if the window is still there, simply use an 'if' statement.
if pyopl.alive(fig):
ax=fig.add_axes((0.12,0.12,0.76,0.76))
#ax=fig.gca()
ax.plot(x, y1, '-o', label='sin(x)', color=(1,0,0))
ax.plot(x, y2, 'rx', label='cos(x)')
ax.plot(x, y3, '--k|', label='exp(x/pi)')
ax.legend()
ax.set_xlabel("x-axis")
ax.set_ylabel("y-axis")
ax.set_title("Axes title")
ax.grid(True)
fig.suptitle("Figure title")
# Paint the changes on the screen.
pyopl.draw(fig)
# Now unlock the main GUI event loop
pyopl.lock(False)
# Handle keyboard interrupts properly.
pyopl.join()
1. You obtain the Matplotlib :class:`Figure` object as the return value of
:func:`figure`.
2. Next you have to lock the GUI event loop (call :func:`lock` with ``True``).
Now the GUI stops and the window is not refreshed anymore thus preventing
any interference from the GUI while API calls are being made.
3. Before making API calls you have to verify that the window is not closed.
This can be done by calling :func:`alive` and passing it the :class:`Figure`
object.
4. Do your Matplotlib API stuff on the :class:`Figure` object.
5. Request a manual redraw of the plot window by calling :func:`draw` and
passing it the :class:`Figure` object.
6. Unlock the GUI event loop by calling :func:`lock` with ``False``.
7. At the end of your program call :func:`join`. The program exits
when you close the Control Window.
"""
from .manager import QPController
import os
__all__ = [ 'init', 'shutdown',
'lock', 'join',
'updateRCParams',
'figure', 'alive', 'draw',
'close', 'title',
'showFigure', 'raiseFigure', 'saveFigure'
]
GUIctl=None
"The :class:`GUIControl` object for communicationg with the graphical thread."
[docs]def init():
"""
This is an obsolete function present only for compatibility reasons.
"""
print("init() function is no longer needed. GUI thread starts automatically at import.")
[docs]def shutdown():
"""
Exits the graphical thread. Equivalent to closing the Control window.
The GUI must not be locked when this function is called. See :func:`lock`.
"""
global GUIctl
if GUIctl is not None:
GUIctl.stopGUI()
[docs]def lock(state=True):
"""
Calling convention: lock(*state*)
Locks the main event loop so Matplotlib API calls can be made using the
matplotlib :class:`Figure` objects without interfering with the repainting
of the plot window.
If *state* is ``False`` the main event loop is unlocked and can proceed
with handling GUI events.
Multiple calls with *state* set to ``True`` (or ``False``) are equivalent
to a single call.
"""
if state is True:
GUIctl.lockGUI()
else:
GUIctl.unlockGUI()
[docs]def join():
"""
Calling convention: join()
Joins the GUI thread. Usually called at the end of the main thread so the
windows don't close immediately after the main thread is finished.
The waiting can be interrupted by a keyboard interrupt.
The GUI must not be locked when this function is called. See :func:`lock`.
"""
GUIctl.join()
[docs]def updateRCParams(*args, **kwargs):
"""
Calling convention: updateRCParams(*dict*)
Updates the rcParams structure of Matplotlib with the dictionary given by
*dict*. Returns ``True`` on success.
The GUI must not be locked when this function is called. See :func:`lock`.
"""
return GUIctl.postMessage({
'cmd':['plot', 'updatercparams'],
'args': args,
'kwargs': kwargs
}
)
[docs]def alive(fig):
"""
Returns ``True`` if the figure *fig* is alive (window is not closed).
The GUI must be locked when this function is called. See :func:`lock`.
"""
return GUIctl.figureAlive(fig)
[docs]def draw(fig):
"""
Redraws figure *fig*. Does nothing if figure is not alive.
The GUI must be locked when this function is called. See :func:`lock`.
"""
return GUIctl.figureDraw(fig)
[docs]def close(fig=None):
"""
Closes a plot window corresponding to figure *fig*.
If no *fig* is given, closes all plot windows.
Returns ``True`` on success.
The GUI must not be locked when this function is called. See :func:`lock`.
"""
if fig is None:
return GUIctl.postMessage({
'cmd':['plot', 'closeall'],
'args': (),
'kwargs': {}
}
)
else:
return GUIctl.postMessage({
'cmd':['plot', 'close'],
'args': ( fig, ),
'kwargs': {}
}
)
[docs]def title(fig, title):
"""
Sets the window title of figure *fig* to *title*.
This title appears in the title bar of the plot window.
The GUI must not be locked when this function is called. See :func:`lock`.
"""
return GUIctl.postMessage({
'cmd':['plot', 'setwindowtitle'],
'args': (fig, title),
'kwargs': {}
}
)
# At import execute the code that initializes the GUI thread
GUIctl=QPController()
GUIctl.startGUI()
updateRCParams({
'font.size': 10,
'axes.titlesize': 10,
'axes.labelsize': 9,
'xtick.labelsize': 9,
'ytick.labelsize': 9,
'legend.fontsize': 9
})
# When join is invoked, show the control window and wait until all plots are closed
if __name__=='__main__':
import numpy as np
x = np.arange(0.0, 2*np.pi, 0.2)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.exp(x/np.pi)
fig=figure(windowTitle="Figure - single axes", figpx=(600,400), dpi=100)
lock(True)
if alive(fig):
ax=fig.add_axes((0.12,0.12,0.76,0.76))
#ax=fig.gca()
ax.plot(x, y1, '-o', label='sin(x)', color=(1,0,0))
ax.plot(x, y2, 'rx', label='cos(x)')
ax.plot(x, y3, '--k|', label='exp(x/pi)')
ax.legend()
ax.set_xlabel("x-axis")
ax.set_ylabel("y-axis")
ax.set_title("Axes title")
ax.grid(True)
fig.suptitle("Figure title")
# Paint the changes on the screen.
draw(fig)
else:
print("Window is closed")
lock(False)
join()