Source code for PyMca5.PyMcaCore.PyMcaMatplotlibSave

#!/usr/bin/env python
#/*##########################################################################
#
# The PyMca X-Ray Fluorescence Toolkit
#
# Copyright (c) 2004-2014 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#############################################################################*/
__author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import numpy
from matplotlib import cm
from matplotlib import __version__ as matplotlib_version
from matplotlib.font_manager import FontProperties
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.colors import LinearSegmentedColormap, LogNorm, Normalize
from matplotlib.ticker import MaxNLocator, AutoLocator

DEBUG = 0

colordict = {}
colordict['blue']   = '#0000ff'
colordict['red']    = '#ff0000'
colordict['green']  = '#00ff00'
colordict['black']  = '#000000'
colordict['white']  = '#ffffff'
colordict['pink']   = '#ff66ff'
colordict['brown']  = '#a52a2a'
colordict['orange'] = '#ff9900'
colordict['violet'] = '#6600ff'
colordict['grey']   = '#808080'
colordict['yellow'] = '#ffff00'
colordict['darkgreen'] = 'g'
colordict['darkbrown'] = '#660000'
colordict['magenta']   = 'm'
colordict['cyan']      = 'c'
colordict['bluegreen'] = '#33ffff'
colorlist  = [colordict['black'],
              colordict['red'],
              colordict['blue'],
              colordict['green'],
              colordict['pink'],
              colordict['brown'],
              colordict['cyan'],
              colordict['orange'],
              colordict['violet'],
              colordict['bluegreen'],
              colordict['grey'],
              colordict['magenta'],
              colordict['darkgreen'],
              colordict['darkbrown'],
              colordict['yellow']]

[docs]class PyMcaMatplotlibSave(FigureCanvas): def __init__(self, size = (7,3.5), logx = False, logy = False, legends = True, bw = False): self.fig = Figure(figsize=size) #in inches FigureCanvas.__init__(self, self.fig) self._logX = logx self._logY = logy self._bw = bw self._legend = legends self._legendList = [] self._dataCounter = 0 if not legends: if self._logY: ax = self.fig.add_axes([.15, .15, .75, .8]) else: ax = self.fig.add_axes([.15, .15, .75, .75]) else: if self._logY: ax = self.fig.add_axes([.15, .15, .7, .8]) else: ax = self.fig.add_axes([.15, .15, .7, .8]) ax.set_axisbelow(True) self.ax = ax if self._logY: self._axFunction = ax.semilogy else: self._axFunction = ax.plot if self._bw: self.colorList = ['k'] #only black self.styleList = ['-', ':', '-.', '--'] self.nColors = 1 else: self.colorList = colorlist self.styleList = ['-', '-.', ':'] self.nColors = len(colorlist) self.nStyles = len(self.styleList) self.colorIndex = 0 self.styleIndex = 0 self.xmin = None self.xmax = None self.ymin = None self.ymax = None self.limitsSet = False
[docs] def setLimits(self, xmin, xmax, ymin, ymax): self.xmin = xmin self.xmax = xmax self.ymin = ymin self.ymax = ymax self.limitsSet = True
def _filterData(self, x, y): index = numpy.flatnonzero((self.xmin <= x) & (x <= self.xmax)) x = numpy.take(x, index) y = numpy.take(y, index) index = len(index) if index: index = numpy.flatnonzero((self.ymin <= y) & (y <= self.ymax)) index = len(index) return index def _getColorAndStyle(self): color = self.colorList[self.colorIndex] style = self.styleList[self.styleIndex] self.colorIndex += 1 if self.colorIndex >= self.nColors: self.colorIndex = 0 self.styleIndex += 1 if self.styleIndex >= self.nStyles: self.styleIndex = 0 return color, style
[docs] def addDataToPlot(self, x, y, legend = None, color = None, linewidth = None, linestyle = None, **kw): n = max(x.shape) if self.limitsSet is not None: n = self._filterData(x, y) if n == 0: #nothing to plot if DEBUG: print("nothing to plot") return style = None if color is None: color, style = self._getColorAndStyle() if linestyle is None: if style is None: style = '-' else: style = linestyle if linewidth is None:linewidth = 1.0 self._axFunction( x, y, linestyle = style, color=color, linewidth = linewidth, **kw) self._dataCounter += 1 if legend is None: #legend = "%02d" % self._dataCounter #01, 02, 03, ... legend = "%c" % (96+self._dataCounter) #a, b, c, .. self._legendList.append(legend)
[docs] def setXLabel(self, label): self.ax.set_xlabel(label)
[docs] def setYLabel(self, label): self.ax.set_ylabel(label)
[docs] def setTitle(self, title): self.ax.set_title(title)
[docs] def plotLegends(self): if not self._legend:return if not len(self._legendList):return loc = (1.01, 0.0) labelsep = 0.015 drawframe = True fontproperties = FontProperties(size=10) if len(self._legendList) > 14: drawframe = False if matplotlib_version < '0.99.0': fontproperties = FontProperties(size=8) loc = (1.05, -0.2) else: if len(self._legendList) < 18: #drawframe = True loc = (1.01, 0.0) elif len(self._legendList) < 25: loc = (1.05, 0.0) fontproperties = FontProperties(size=8) elif len(self._legendList) < 28: loc = (1.05, 0.0) fontproperties = FontProperties(size=6) else: loc = (1.05, -0.1) fontproperties = FontProperties(size=6) if matplotlib_version < '0.99.0': legend = self.ax.legend(self._legendList, loc = loc, prop = fontproperties, labelsep = labelsep, pad = 0.15) else: legend = self.ax.legend(self._legendList, loc = loc, prop = fontproperties, labelspacing = labelsep, borderpad = 0.15) legend.draw_frame(drawframe)
[docs] def saveFile(self, filename, format=None): if format is None: format = filename[-3:] if format.upper() not in ['EPS', 'PNG', 'SVG']: raise ValueError("Unknown format %s" % format) if os.path.exists(filename): os.remove(filename) if self.limitsSet: self.ax.set_ylim(self.ymin, self.ymax) self.ax.set_xlim(self.xmin, self.xmax) #self.plotLegends() self.print_figure(filename) return
[docs]class PyMcaMatplotlibSaveImage: def __init__(self, imageData=None, fileName=None, dpi=300, size=(5, 5), xaxis='off', yaxis='off', xlabel='', ylabel='', nxlabels=0, nylabels=0, colorbar=None, title='', interpolation='nearest', colormap=None, linlogcolormap='linear', origin='lower', contour='off', contourlabels='on', contourlabelformat='%.3f', contourlevels=10, contourlinewidth=10, xorigin=0.0, yorigin=0.0, xpixelsize=1.0, ypixelsize=1.0, xlimits=None, ylimits=None, vlimits=None, extent=None): self.figure = Figure(figsize=size) #in inches self.canvas = FigureCanvas(self.figure) self.imageData = imageData self.pixmapImage = None self.config={'xaxis':xaxis, 'yaxis':yaxis, 'title':title, 'xlabel':xlabel, 'ylabel':ylabel, 'nxlabels':nxlabels, 'nylabels':nylabels, 'colorbar':colorbar, 'colormap':colormap, 'linlogcolormap':linlogcolormap, 'interpolation':interpolation, 'origin':origin, 'contour':contour, 'contourlabels':contourlabels, 'contourlabelformat':contourlabelformat, 'contourlevels':contourlevels, 'contourlinewidth':contourlinewidth, 'xpixelsize':xpixelsize, 'ypixelsize':ypixelsize, 'xorigin':xorigin, 'yorigin':yorigin, 'zoomxmin':None, 'zoomxmax':None, 'zoomymin':None, 'zoomymax':None, 'valuemin':None, 'valuemax':None, 'xlimits':xlimits, 'ylimits':ylimits, 'vlimits':vlimits, 'extent':extent} #generate own colormaps cdict = {'red': ((0.0, 0.0, 0.0), (1.0, 1.0, 1.0)), 'green': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0)), 'blue': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0))} self.__redCmap = LinearSegmentedColormap('red',cdict,256) cdict = {'red': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0)), 'green': ((0.0, 0.0, 0.0), (1.0, 1.0, 1.0)), 'blue': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0))} self.__greenCmap = LinearSegmentedColormap('green',cdict,256) cdict = {'red': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0)), 'green': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0)), 'blue': ((0.0, 0.0, 0.0), (1.0, 1.0, 1.0))} self.__blueCmap = LinearSegmentedColormap('blue',cdict,256) # Temperature as defined in spslut cdict = {'red': ((0.0, 0.0, 0.0), (0.5, 0.0, 0.0), (0.75, 1.0, 1.0), (1.0, 1.0, 1.0)), 'green': ((0.0, 0.0, 0.0), (0.25, 1.0, 1.0), (0.75, 1.0, 1.0), (1.0, 0.0, 0.0)), 'blue': ((0.0, 1.0, 1.0), (0.25, 1.0, 1.0), (0.5, 0.0, 0.0), (1.0, 0.0, 0.0))} #Do I really need as many colors? self.__temperatureCmap = LinearSegmentedColormap('temperature', cdict, 65536) #reversed gray cdict = {'red': ((0.0, 1.0, 1.0), (1.0, 0.0, 0.0)), 'green': ((0.0, 1.0, 1.0), (1.0, 0.0, 0.0)), 'blue': ((0.0, 1.0, 1.0), (1.0, 0.0, 0.0))} self.__reversedGrayCmap = LinearSegmentedColormap('yerg', cdict, 256) if fileName is not None: self.saveImage(fileName)
[docs] def setImage(self, image=None): self.imageData = image
[docs] def setParameters(self, ddict): self.config.update(ddict)
[docs] def saveImage(self, filename): self.figure.clear() if (self.imageData is None) and\ (self.pixmapImage is None): return # The axes self.axes = self.figure.add_axes([.15, .15, .75, .8]) if self.config['xaxis'] == 'off': self.axes.xaxis.set_visible(False) else: self.axes.xaxis.set_visible(True) nLabels = self.config['nxlabels'] if nLabels not in ['Auto', 'auto', '0', 0]: self.axes.xaxis.set_major_locator(MaxNLocator(nLabels)) else: self.axes.xaxis.set_major_locator(AutoLocator()) if self.config['yaxis'] == 'off': self.axes.yaxis.set_visible(False) else: self.axes.yaxis.set_visible(True) if nLabels not in ['Auto', 'auto', '0', 0]: self.axes.yaxis.set_major_locator(MaxNLocator(nLabels)) else: self.axes.yaxis.set_major_locator(AutoLocator()) if self.pixmapImage is not None: self._savePixmapFigure(filename) return interpolation = self.config['interpolation'] origin = self.config['origin'] cmap = self.__temperatureCmap ccmap = cm.gray if self.config['colormap'] in ['grey','gray']: cmap = cm.gray ccmap = self.__temperatureCmap elif self.config['colormap'] in ['yarg','yerg']: cmap = self.__reversedGrayCmap ccmap = self.__temperatureCmap elif self.config['colormap']=='jet': cmap = cm.jet elif self.config['colormap']=='hot': cmap = cm.hot elif self.config['colormap']=='cool': cmap = cm.cool elif self.config['colormap']=='copper': cmap = cm.copper elif self.config['colormap']=='spectral': cmap = cm.spectral elif self.config['colormap']=='hsv': cmap = cm.hsv elif self.config['colormap']=='rainbow': cmap = cm.gist_rainbow elif self.config['colormap']=='red': cmap = self.__redCmap elif self.config['colormap']=='green': cmap = self.__greenCmap elif self.config['colormap']=='blue': cmap = self.__blueCmap elif self.config['colormap']=='temperature': cmap = self.__temperatureCmap elif self.config['colormap'] == 'paired': cmap = cm.Paired elif self.config['colormap'] == 'paired_r': cmap = cm.Paired_r elif self.config['colormap'] == 'pubu': cmap = cm.PuBu elif self.config['colormap'] == 'pubu_r': cmap = cm.PuBu_r elif self.config['colormap'] == 'rdbu': cmap = cm.RdBu elif self.config['colormap'] == 'rdbu_r': cmap = cm.RdBu_r elif self.config['colormap'] == 'gist_earth': cmap = cm.gist_earth elif self.config['colormap'] == 'gist_earth_r': cmap = cm.gist_earth_r elif self.config['colormap'] == 'blues': cmap = cm.Blues elif self.config['colormap'] == 'blues_r': cmap = cm.Blues_r elif self.config['colormap'] == 'ylgnbu': cmap = cm.YlGnBu elif self.config['colormap'] == 'ylgnbu_r': cmap = cm.YlGnBu_r else: print("Unsupported colormap %s" % self.config['colormap']) if self.config['extent'] is None: h, w = self.imageData.shape x0 = self.config['xorigin'] y0 = self.config['yorigin'] w = w * self.config['xpixelsize'] h = h * self.config['ypixelsize'] if origin == 'upper': extent = (x0, w+x0, h+y0, y0) else: extent = (x0, w+x0, y0, h+y0) else: extent = self.config['extent'] vlimits = self.__getValueLimits() if vlimits is None: imageData = self.imageData vmin = self.imageData.min() vmax = self.imageData.max() else: vmin = min(vlimits[0], vlimits[1]) vmax = max(vlimits[0], vlimits[1]) imageData = self.imageData.clip(vmin,vmax) if self.config['linlogcolormap'] != 'linear': if vmin <= 0: if vmax > 0: vmin = min(imageData[imageData>0]) else: vmin = 0.0 vmax = 1.0 self._image = self.axes.imshow(imageData.clip(vmin,vmax), interpolation=interpolation, origin=origin, cmap=cmap, extent=extent, norm=LogNorm(vmin, vmax)) else: self._image = self.axes.imshow(imageData, interpolation=interpolation, origin=origin, cmap=cmap, extent=extent, norm=Normalize(vmin, vmax)) ylim = self.axes.get_ylim() if self.config['colorbar'] is not None: barorientation = self.config['colorbar'] self._colorbar = self.figure.colorbar(self._image, orientation=barorientation) #contour plot if self.config['contour'] != 'off': dataMin = imageData.min() dataMax = imageData.max() ncontours = int(self.config['contourlevels']) contourlinewidth = int(self.config['contourlinewidth'])/10. levels = (numpy.arange(ncontours)) *\ (dataMax - dataMin)/float(ncontours) if self.config['contour'] == 'filled': self._contour = self.axes.contourf(imageData, levels, origin=origin, cmap=ccmap, extent=extent) else: self._contour = self.axes.contour(imageData, levels, origin=origin, cmap=ccmap, linewidths=contourlinewidth, extent=extent) if self.config['contourlabels'] != 'off': self.axes.clabel(self._contour, fontsize=9, inline=1, fmt=self.config['contourlabelformat']) if 0 and self.config['colorbar'] is not None: if barorientation == 'horizontal': barorientation = 'vertical' else: barorientation = 'horizontal' self._ccolorbar=self.figure.colorbar(self._contour, orientation=barorientation, extend='both') self.__postImage(ylim, filename)
[docs] def setPixmapImage(self, image=None, bgr=False): if bgr: self.pixmapImage = image * 1 self.pixmapImage[:,:,0] = image[:,:,2] self.pixmapImage[:,:,2] = image[:,:,0] else: self.pixmapImage = image
def _savePixmapFigure(self, filename): interpolation = self.config['interpolation'] origin = self.config['origin'] if self.config['extent'] is None: h= self.pixmapImage.shape[0] w= self.pixmapImage.shape[1] x0 = self.config['xorigin'] y0 = self.config['yorigin'] w = w * self.config['xpixelsize'] h = h * self.config['ypixelsize'] if origin == 'upper': extent = (x0, w+x0, h+y0, y0) else: extent = (x0, w+x0, y0, h+y0) else: extent = self.config['extent'] self._image = self.axes.imshow(self.pixmapImage, interpolation=interpolation, origin=origin, extent=extent) ylim = self.axes.get_ylim() self.__postImage(ylim, filename) def __getValueLimits(self): if (self.config['valuemin'] is not None) and\ (self.config['valuemax'] is not None) and\ (self.config['valuemin'] != self.config['valuemax']): vlimits = (self.config['valuemin'], self.config['valuemax']) elif self.config['vlimits'] is not None: vlimits = self.config['vlimits'] else: vlimits = None return vlimits def __postImage(self, ylim, filename): self.axes.set_title(self.config['title']) self.axes.set_xlabel(self.config['xlabel']) self.axes.set_ylabel(self.config['ylabel']) origin = self.config['origin'] if (self.config['zoomxmin'] is not None) and\ (self.config['zoomxmax'] is not None)and\ (self.config['zoomxmax'] != self.config['zoomxmin']): xlimits = (self.config['zoomxmin'], self.config['zoomxmax']) elif self.config['xlimits'] is not None: xlimits = self.config['xlimits'] else: xlimits = None if (self.config['zoomymin'] is not None) and\ (self.config['zoomymax'] is not None) and\ (self.config['zoomymax'] != self.config['zoomymin']): ylimits = (self.config['zoomymin'], self.config['zoomymax']) elif self.config['ylimits'] is not None: ylimits = self.config['ylimits'] else: ylimits = None if ylimits is None: self.axes.set_ylim(ylim[0],ylim[1]) else: ymin = min(ylimits) ymax = max(ylimits) if origin == "lower": self.axes.set_ylim(ymin, ymax) else: self.axes.set_ylim(ymax, ymin) if xlimits is not None: xmin = min(xlimits) xmax = max(xlimits) self.axes.set_xlim(xmin, xmax) self.canvas.print_figure(filename)
if __name__ == "__main__": import sys if len(sys.argv) < 2: a=numpy.arange(1200.) a.shape = 20, 60 PyMcaMatplotlibSaveImage(a, "filename.png", colormap="rainbow") print("Image filename.png saved") else: w=PyMcaMatplotlibSave(legends=True) x = numpy.arange(1200.) w.setLimits(0, 1200., 0, 12000.) if len(sys.argv) > 2: n = int(sys.argv[2]) else: n = 14 for i in range(n): y = x * i w.addDataToPlot(x,y, legend="%d" % i) #w.setTitle('title') w.setXLabel('Channel') w.setYLabel('Counts') w.plotLegends() w.saveFile("filename.png") print("Plot filename.png saved") sys.exit(0)