9.5. Python-Module matplotlib¶
The module matplotlib can be used in order to create two or three dimensional plots like in these examples:
Since the internal plotting methods of itom mainly provide display widgets for plotting matrix contents and images, matplotlib can be used for plotting other types of graphics like graphs, line plots, bars... A huge list of examples can be found under http://matplotlib.org/gallery.html.
9.5.1. Set Matplotlib backend to itom¶
Matplotlib 1.4.x or lower
In order to render the output of matplotlib into an itom window or a user interface generated by itom (see Creating advanced dialogs and windows), you need to write the following command before importing any module of the package matplotlib:
import matplotlib matplotlib.use('module://mpl_itom.backend_itomagg',False)
Alternatively, you can always configure matplotlib to render its output in itom windows. Therefore, itom internally has an environment variable MPLCONFIGDIR that points to the directory:
of your itom installation (or build-folder if self-compiled). Place a copy of the matplotlib config file matplotlibrc into this directory and modify the variable backend to module://mpl_itom.backend_itomagg.
A template for the configuration file can be either found in the Python subfolder [PythonDir]/Lib/site-packages/matplotlib/mpl-data or under http://matplotlib.org/_static/matplotlibrc.
This is the part you need to change:
# the default backend; one of GTK GTKAgg GTKCairo GTK3Agg GTK3Cairo # CocoaAgg MacOSX Qt4Agg TkAgg WX WXAgg Agg Cairo GDK PS PDF SVG # Template # You can also deploy your own backend outside of matplotlib by # referring to the module name (which must be in the PYTHONPATH) as # 'module://my_backend' backend : module://mpl_itom.backend_itomagg
Once you placed the config file, you don’t need to use the use command in any of your scripts.
If you are not sure, whether your user defined config file is loaded, you can obtain the path to the loaded config file with:
>>> import matplotlib >>> matplotlib.matplotlib_fname()
For more information about this, see http://matplotlib.org/users/customizing.html
Matplotlib 1.5 or higher
itom automatically sets the environment variable MPLBACKEND to module://mpl_itom.backend_itomagg. Then, matplotlib outputs are directly rendered in the itom backend without further modifications of the code. The matplotlib.use command is not necessary any more, however it can be used to set another backend.
9.5.2. Simple Matplotlib example¶
This example shows you that is possible to use any arbitrary matplotlib python script and execute it in itom. Therefore, the example hist2d_log_demo.py from the pylab examples on http://matplotlib.org is taken.
Its source code is:
import matplotlib matplotlib.use('module://mpl_itom.backend_itomagg',False) import matplotlib.pyplot as plt import numpy as np from matplotlib.collections import EllipseCollection x = np.arange(10) y = np.arange(15) X, Y = np.meshgrid(x, y) XY = np.hstack((X.ravel()[:,np.newaxis], Y.ravel()[:,np.newaxis])) ww = X/10.0 hh = Y/15.0 aa = X*9 ax = plt.subplot(1,1,1) ec = EllipseCollection( ww, hh, aa, units='x', offsets=XY, transOffset=ax.transData) ec.set_array((X+Y).ravel()) ax.add_collection(ec) ax.autoscale_view() ax.set_xlabel('X') ax.set_ylabel('y') cbar = plt.colorbar(ec) cbar.set_label('X+Y') title("ellipse collection") plt.show()
Please consider that the original source code has been changed such that the first two lines are prepended. After executing this script, the following figure is displayed in itom:
If the figure does not appear, the matplotlib designer widget for itom is not available. This means, the library matplotlibPlot in the designer folder of itom is missing.
Further examples from the official matplotlib gallery are contained in the itom subfolder demo/matplotlib.
9.5.3. Embedding a matplotlib figure in your own user interface¶
itom not only provides stand-alone windows for showing the result of the matplotlib, but it is also possible to integrate a matplotlib canvas into own user interfaces created by the QtDesigner and scripted with Python. For more information how to do this, see Creating advanced dialogs and windows.
In the widget library of QtDesigner there is the widget MatplotlibPlot in the section itom Plugins (under the consumption that the corresponding designer plugin library is contained in the folder designer of the root directory of itom). Drag&Drop an instance of this widget onto your user interface.
In the following example, a new main window is created where a MatplotlibPlot widget (name: plot) is placed on the left side while two buttons (name: btnDroppedSpines and btnSine) are placed on the right side:
When any of the both buttons are pressed, the following example should be displayed in the figure plot on the left side.
import matplotlib matplotlib.use('module://mpl_itom.backend_itomagg',False) import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D def plotDroppedSpines(): ''' plot taken from matplotlib example 'spines_demo_dropped.py' ''' canvas = gui.plot #reference to matplotlibPlot widget fig = plt.figure(num = 3, canvas=canvas) ax = fig.add_subplot(111) ax.clear() image = np.random.uniform(size=(10, 10)) ax.imshow(image, cmap=plt.cm.gray, interpolation='nearest') ax.set_title('dropped spines') # Move left and bottom spines outward by 10 points ax.spines['left'].set_position(('outward', 10)) ax.spines['bottom'].set_position(('outward', 10)) # Hide the right and top spines ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) # Only show ticks on the left and bottom spines ax.yaxis.set_ticks_position('left') ax.xaxis.set_ticks_position('bottom') plt.show() def plotSine(): ''' plots sine, taken from matplotlib gallery examples ''' t = np.arange(0.0, 1.0, 0.01) s = np.sin(2*np.pi*t) canvas = gui.plot #reference to matplotlibPlot widget fig = plt.figure(num = 3, canvas=canvas) ax = fig.add_subplot(111) ax.clear() ax.plot(t,s) plt.show() gui = ui("matplotlibGui.ui", type = ui.TYPEWINDOW) gui.btnSine.connect("clicked()", plotSine) gui.btnDroppedSpines.connect("clicked()", plotDroppedSpines) gui.show() # if you call this script for the second time, the given figure-num (3) # is already in used for the lastly closed figure. Therefore also tell # matplotlib to close this figure handle. plt.close(3)
The result is:
What happens here?
- At the end of the script, the user interface matplotlibGui.ui is loaded and referenced by the variable gui.
- The click-events of both buttons is connected to the methods plotSine and plotDroppedSpines respectively.
- The gui is shown
For both button clicks the following things have to be done:
Once you added the itom-backend command as first, mandatory line to your script, the figure-class of matplotlib has got one further keyword-based parameter canvas. This needs to be used in order to tell the figure where the widget is to plot the content to. If you omit this parameter, a new window is opened with the corresponding output. If you set this parameter to the reference of the widget of type MatplotlibPlot (here: called canvas), the output is print there.
The you have the reference to the figure-instance of matplotlib and can go one like usual.
Once you created one figure that maps to a given widget using the canvas-keyword, this figure is not deleted when a new figure is created using the same keyword. Therefore it will happen that lots of invisible figures need to be handled. Therefore, the num keyword argument is used in the methods in the example in order to always tell matplotlib that a defined figure with the handle 3 should be instantiated. If this handle already exists, this existing figure is used. Therefore it is also necessary to clear the axes using ax.clear().
Furthermore, if you created a figure with a given num and canvas, deletes the user interface and creates a new one, a new figure with the handle of the old one is not able to plot in the new user interface since it still is connected with the old, deleted widget. Therefore, the command:
is used to firstly delete the matplotlib-figure with handle 3 once the script is re-executed.
Usually, matplotlib is allowed changing the size of the output window. The window is then forced to have a new size that can afterwards be manually resized. If your output widget is embedded in an user interface, this behaviour might be undesired. Then disable it by setting the property forceWindowResize to False. In the example above this can be done by:
gui.plot["forceWindowResize"] = False
or by directlly setting the corresponding property when designing the user interface in QtDesigner.
This example is contained in the demo/ui/embeddedMatplotlib folder.