diff --git a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/pkg.info b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/pkg.info index 9fceb7f..5501ac5 100644 --- a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/pkg.info +++ b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/pkg.info @@ -1,4 +1,4 @@ -package( USEPKG Units USEEXT Numpy ) +package( USEPKG Units PyAnaMisc USEEXT Numpy ) ###################################################################### diff --git a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/__init__.py b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/__init__.py index 30f9f8b..b222038 100644 --- a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/__init__.py +++ b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/__init__.py @@ -71,7 +71,7 @@ def kh(evt): #3) disable FPE's certain matplotlib function calls (we don't care too # much about FPE's in other peoples gui/plotting code): -from PyAna.fpe import standardMPLFixes as _standardMPLFixes +from PyAnaMisc.fpe import standardMPLFixes as _standardMPLFixes _standardMPLFixes() #4) Make all legends draggable by default (unless new kw notdraggable=True) and set default numpoints=1 : diff --git a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/_fix_backend_gtk.py b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/_fix_backend_gtk.py index f3eee7e..b22342d 100644 --- a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/_fix_backend_gtk.py +++ b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/_fix_backend_gtk.py @@ -1,28 +1 @@ -#To avoid confusing users with useless(?) warnings such as the following: -# -#/usr/lib64/python2.7/site-packages/matplotlib/backends/backend_gtk.py:250: Warning: Source ID 2 was not found when attempting to remove it -# gobject.source_remove(self._idle_event_id) -# -#we monkey-patch FigureCanvasGTK.destroy and block stderr while it is invoked. -# -#Hopefully in some future version of matplotlib this warning will disappear by itself. -import sys,os -try: - from matplotlib.backends.backend_gtk import FigureCanvasGTK - if hasattr(FigureCanvasGTK,'destroy'): - _FigureCanvasGTK_destroy = FigureCanvasGTK.destroy - def patched_FigureCanvasGTK_destroy(self): - _stderr = sys.stderr - null = open(os.devnull,'wb') - try: - sys.stderr.flush() - sys.stderr = null - _FigureCanvasGTK_destroy(self) - finally: - sys.stderr.flush() - sys.stderr = _stderr - null.close() - FigureCanvasGTK.destroy=patched_FigureCanvasGTK_destroy -except ImportError: - #Something unexpected, but let us not break stuff for users because of it! - pass +import PyAnaMisc._fix_backend_gtk diff --git a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/dyncmap.py b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/dyncmap.py index 8ed545e..2858354 100644 --- a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/dyncmap.py +++ b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAna/python/dyncmap.py @@ -1,118 +1 @@ -from __future__ import division -__all__=['dynamic_2d_colormap'] - -import numpy as np -from matplotlib.colors import LinearSegmentedColormap - -def dynamic_2d_colormap(data,imgobj=None,ncols=65536): - #attempt to use high-precision floating point for intermediate calculations: - try: - import decimal - _=decimal.Context(prec=999) - hpfloat,hpabs,hpmin,hpmax=_.create_decimal,_.abs,_.min,_.max - hpceil = lambda x : x.to_integral_value(rounding=decimal.ROUND_CEILING) - except ImportError: - import math - hpfloat,hpabs,hpmin,hpmax,hpceil=float,abs,min,max,math.ceil - - hpncols=hpfloat(ncols) - zero,one=hpfloat(0.0),hpfloat(1.0) - #figure out limits (remember that all values in data might be masked): - rawmin = np.min(data) - rawmax = np.max(data) - if rawmin is np.ma.masked and rawmax is np.ma.masked: - rawmin,rawmax = -one, one - datamin = hpfloat(rawmin) - datamax = hpfloat(rawmax) - ddata=datamax-datamin - if ddata: - datamin -= hpfloat(0.005)*hpabs(ddata) - datamax += hpfloat(0.005)*hpabs(ddata) - else: - datamin -= hpfloat(0.5); - datamax += hpfloat(0.5); - - #NB: In principle there is a bug here, ispos+isneg should be based on - #rawmin/rawmax not datamin/datamax. However, at least the code in - #NCSABVal/scripts/sabstudio is relying on the present behaviour, so we can't - #just fix it right away: - ispos=datamin>=zero - isneg=datamax<=zero - #ispos=rawmin>=zero - #isneg=rawmax<=zero - - if ispos and dataminzero: - datamax=zero - if not ispos and not isneg: - #make sure that 0.0 falls on a "bin-edge" in the colormap, so as to - #not let small positive values accidentally acquire blue values or - #vice versa: - assert datamax>zero and datamin -datamin: datamin -= eps - else: datamax += eps - # d=(datamax-datamin)/hpncols - - #relative root-mean-square clipped to [0.0001,0.3]: - npmean=np.mean(np.square(data)) - if npmean is np.ma.masked: - rms = hpfloat(0.1) - else: - rms=hpmax(hpfloat(0.0001), - hpmin(hpfloat(0.3), - hpfloat(np.sqrt(npmean))/(datamax-datamin))) - if datamin>=0.0: - cdict = {'red': [(0.0, 0.10, 0.10), - (float(rms), 0.7, 0.7), - (float(3*rms), 1.0, 1.0), - (1.0, 1.0, 1.0)], - 'green': [(0.0, 0.0, 0.0), - (1.0, 1.0, 1.0)], - 'blue': [(0.0, 0.0, 0.0), - (1.0, 0.1, 0.1)]} - elif datamax<=0.0: - cdict = {'red': [(0.0, 0.1, 0.1), - (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), - (float(one-3*rms), 1.0, 1.0), - (float(one-rms), 0.7, 0.7), - (1.0, 0.1, 0.1)]} - else: - rneg = - datamin / ( datamax - datamin ) - dbin = one/hpncols - #In rneg-dbin to rneg+dbin, we keep equal mix of red and blue, so - #numerical errors won't show e.g. very small positive values as blue or - #vice versa: - cdict = {'red': [(0.0, 0.1, 0.1), - (float(rneg-dbin), 0.0, 0.1), - (float(rneg+dbin), 0.1, 0.1), - (float(rneg+hpmax(hpfloat(2)*dbin,(one-rneg)*rms)), 0.7, 0.7), - (float(rneg+hpmax(hpfloat(3)*dbin,(one-rneg)*rms*hpfloat(3))), 1.0, 1.0), - (1.0, 1.0, 1.0)], - 'green': [(0.0, 1.0, 1.0), - (float(rneg-dbin), 0.0, 0.0), - (float(rneg+dbin), 0.0, 0.0), - (1.0, 1.0, 1.0)], - 'blue': [(0.0, 1.0, 1.0), - (float(rneg-hpmax(hpfloat(3)*dbin,rneg*hpfloat(3)*rms)), 1.0, 1.0), - (float(rneg-hpmax(hpfloat(2)*dbin,rneg*rms)), 0.7, 0.7), - (float(rneg-dbin), 0.1, 0.1), - (float(rneg+dbin), 0.1, 0.0), - (1.0, 0.1, 0.1)]} - #for k,v in cdict.items(): - # print k,v - import matplotlib.colors - cmap=LinearSegmentedColormap('dynamic_rbcmap', cdict, N=ncols, gamma=1.0) - cmap.set_bad('black')#color of masked values (if any) - if imgobj: - imgobj.set_clim(float(datamin),float(datamax)) - imgobj.set_cmap(cmap) - return float(datamin),float(datamax),cmap +from PyAnaMisc.dyncmap import dynamic_2d_colormap diff --git a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/pkg.info b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/pkg.info new file mode 100644 index 0000000..0d75716 --- /dev/null +++ b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/pkg.info @@ -0,0 +1,7 @@ +package() + +###################################################################### + +Package providing standalone modules (empty __init__.py!) related to PyAna. + +primary author: thomas.kittelmann@ess.eu diff --git a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/_fix_backend_gtk.py b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/_fix_backend_gtk.py new file mode 100644 index 0000000..7a410b8 --- /dev/null +++ b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/_fix_backend_gtk.py @@ -0,0 +1,29 @@ +#To avoid confusing users with useless(?) warnings such as the following: +# +#/usr/lib64/python2.7/site-packages/matplotlib/backends/backend_gtk.py:250: Warning: Source ID 2 was not found when attempting to remove it +# gobject.source_remove(self._idle_event_id) +# +#we monkey-patch FigureCanvasGTK.destroy and block stderr while it is invoked. +# +#Hopefully in some future version of matplotlib this warning will disappear by itself. +import sys +import os +try: + from matplotlib.backends.backend_gtk import FigureCanvasGTK + if hasattr(FigureCanvasGTK,'destroy'): + _FigureCanvasGTK_destroy = FigureCanvasGTK.destroy + def patched_FigureCanvasGTK_destroy(self): + _stderr = sys.stderr + null = open(os.devnull,'wb') + try: + sys.stderr.flush() + sys.stderr = null + _FigureCanvasGTK_destroy(self) + finally: + sys.stderr.flush() + sys.stderr = _stderr + null.close() + FigureCanvasGTK.destroy=patched_FigureCanvasGTK_destroy +except ImportError: + #Something unexpected, but let us not break stuff for users because of it! + pass diff --git a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/dyncmap.py b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/dyncmap.py new file mode 100644 index 0000000..eedabfd --- /dev/null +++ b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/dyncmap.py @@ -0,0 +1,117 @@ +__all__=['dynamic_2d_colormap'] + +import numpy as np +from matplotlib.colors import LinearSegmentedColormap + +def dynamic_2d_colormap(data,imgobj=None,ncols=65536): + #attempt to use high-precision floating point for intermediate calculations: + try: + import decimal + _=decimal.Context(prec=999) + hpfloat,hpabs,hpmin,hpmax=_.create_decimal,_.abs,_.min,_.max + hpceil = lambda x : x.to_integral_value(rounding=decimal.ROUND_CEILING) + except ImportError: + import math + hpfloat,hpabs,hpmin,hpmax,hpceil=float,abs,min,max,math.ceil + + hpncols=hpfloat(ncols) + zero,one=hpfloat(0.0),hpfloat(1.0) + #figure out limits (remember that all values in data might be masked): + rawmin = np.min(data) + rawmax = np.max(data) + if rawmin is np.ma.masked and rawmax is np.ma.masked: + rawmin,rawmax = -one, one + datamin = hpfloat(rawmin) + datamax = hpfloat(rawmax) + ddata=datamax-datamin + if ddata: + datamin -= hpfloat(0.005)*hpabs(ddata) + datamax += hpfloat(0.005)*hpabs(ddata) + else: + datamin -= hpfloat(0.5); + datamax += hpfloat(0.5); + + #NB: In principle there is a bug here, ispos+isneg should be based on + #rawmin/rawmax not datamin/datamax. However, at least the code in + #NCSABVal/scripts/sabstudio is relying on the present behaviour, so we can't + #just fix it right away: + ispos=datamin>=zero + isneg=datamax<=zero + #ispos=rawmin>=zero + #isneg=rawmax<=zero + + if ispos and dataminzero: + datamax=zero + if not ispos and not isneg: + #make sure that 0.0 falls on a "bin-edge" in the colormap, so as to + #not let small positive values accidentally acquire blue values or + #vice versa: + assert datamax>zero and datamin -datamin: datamin -= eps + else: datamax += eps + # d=(datamax-datamin)/hpncols + + #relative root-mean-square clipped to [0.0001,0.3]: + npmean=np.mean(np.square(data)) + if npmean is np.ma.masked: + rms = hpfloat(0.1) + else: + rms=hpmax(hpfloat(0.0001), + hpmin(hpfloat(0.3), + hpfloat(np.sqrt(npmean))/(datamax-datamin))) + if datamin>=0.0: + cdict = {'red': [(0.0, 0.10, 0.10), + (float(rms), 0.7, 0.7), + (float(3*rms), 1.0, 1.0), + (1.0, 1.0, 1.0)], + 'green': [(0.0, 0.0, 0.0), + (1.0, 1.0, 1.0)], + 'blue': [(0.0, 0.0, 0.0), + (1.0, 0.1, 0.1)]} + elif datamax<=0.0: + cdict = {'red': [(0.0, 0.1, 0.1), + (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), + (float(one-3*rms), 1.0, 1.0), + (float(one-rms), 0.7, 0.7), + (1.0, 0.1, 0.1)]} + else: + rneg = - datamin / ( datamax - datamin ) + dbin = one/hpncols + #In rneg-dbin to rneg+dbin, we keep equal mix of red and blue, so + #numerical errors won't show e.g. very small positive values as blue or + #vice versa: + cdict = {'red': [(0.0, 0.1, 0.1), + (float(rneg-dbin), 0.0, 0.1), + (float(rneg+dbin), 0.1, 0.1), + (float(rneg+hpmax(hpfloat(2)*dbin,(one-rneg)*rms)), 0.7, 0.7), + (float(rneg+hpmax(hpfloat(3)*dbin,(one-rneg)*rms*hpfloat(3))), 1.0, 1.0), + (1.0, 1.0, 1.0)], + 'green': [(0.0, 1.0, 1.0), + (float(rneg-dbin), 0.0, 0.0), + (float(rneg+dbin), 0.0, 0.0), + (1.0, 1.0, 1.0)], + 'blue': [(0.0, 1.0, 1.0), + (float(rneg-hpmax(hpfloat(3)*dbin,rneg*hpfloat(3)*rms)), 1.0, 1.0), + (float(rneg-hpmax(hpfloat(2)*dbin,rneg*rms)), 0.7, 0.7), + (float(rneg-dbin), 0.1, 0.1), + (float(rneg+dbin), 0.1, 0.0), + (1.0, 0.1, 0.1)]} + #for k,v in cdict.items(): + # print k,v + import matplotlib.colors + cmap=LinearSegmentedColormap('dynamic_rbcmap', cdict, N=ncols, gamma=1.0) + cmap.set_bad('black')#color of masked values (if any) + if imgobj: + imgobj.set_clim(float(datamin),float(datamax)) + imgobj.set_cmap(cmap) + return float(datamin),float(datamax),cmap diff --git a/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/fpe.py b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/fpe.py new file mode 100644 index 0000000..147d8b7 --- /dev/null +++ b/src/simplebuild_dgcode/data/pkgs/PyAnalysis/PyAnaMisc/python/fpe.py @@ -0,0 +1,43 @@ +def disableFPEDuringCall(obj,fctname): + import Core.misc + if not Core.misc.is_debug_build(): + return + orig = getattr(obj,fctname) + import Core.FPE + nofpectxmgr = Core.FPE.DisableFPEContextManager + def safefct(*args,**kwargs): + with nofpectxmgr(): + return orig(*args,**kwargs) + setattr(obj,fctname,safefct) + +__standardFixesDone = [False] +def standardMPLFixes(): + global __standardFixesDone + if __standardFixesDone[0]: + return + __standardFixesDone[0] = True + import Core.misc + if not Core.misc.is_debug_build(): + return + + try: + import matplotlib.pyplot + except ImportError: + return#do nothing + + import matplotlib.figure + import matplotlib.scale + try: + import matplotlib.backends.backend_pdf + except ImportError: + pass + disableFPEDuringCall(matplotlib.pyplot,'tight_layout') + disableFPEDuringCall(matplotlib.figure.Figure,'tight_layout') + disableFPEDuringCall(matplotlib.figure.Figure,'savefig') + disableFPEDuringCall(matplotlib.pyplot,'show') + disableFPEDuringCall(matplotlib.pyplot,'plot') + disableFPEDuringCall(matplotlib.pyplot,'savefig') + if hasattr(matplotlib.scale,'LogTransformBase'): + disableFPEDuringCall(matplotlib.scale.LogTransformBase,'transform_non_affine') + if hasattr(matplotlib.scale,'LogTransform'): + disableFPEDuringCall(matplotlib.scale.LogTransform,'transform_non_affine') diff --git a/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/pkg.info b/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/pkg.info index c63fd2a..bc71d64 100644 --- a/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/pkg.info +++ b/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/pkg.info @@ -1,4 +1,4 @@ -package(USEPKG Utils USEEXT ZLib) +package(USEPKG Utils PyAnaMisc USEEXT ZLib) ###################################################################### diff --git a/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/python/_backend_test.py b/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/python/_backend_test.py index 07b6d8f..524da4b 100644 --- a/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/python/_backend_test.py +++ b/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/python/_backend_test.py @@ -7,9 +7,9 @@ if _backend_ok and _backend=='gtkagg': #attempt to silence some useless/confusing warnings try: - import PyAna._fix_backend_gtk # noqa F401 + import PyAnaMisc._fix_backend_gtk # noqa F401 except ImportError: - #perhaps PyAna package was not built, no biggie, users might get warnings. + #perhaps PyAnaMisc package was not built, no biggie, users might get warnings. pass if _backend_ok and _backend=='tkagg': @@ -21,11 +21,7 @@ message=('Treat the new Tool classes introduced in v1.5 as experimental'+ ' for now, the API will likely change in version 2.1')) -try: - from PyAna.fpe import standardMPLFixes as _standardMPLFixes # noqa E402 -except ModuleNotFoundError: - #fail silently, the PyAna pkg might be disabled - _standardMPLFixes = lambda : None +from PyAnaMisc.fpe import standardMPLFixes as _standardMPLFixes # noqa E402 _standardMPLFixes() def _ensure_backend_ok(): diff --git a/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/python/plotutils.py b/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/python/plotutils.py index f830b67..d7add09 100644 --- a/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/python/plotutils.py +++ b/src/simplebuild_dgcode/data/pkgs/SimpleHists/SimpleHists/python/plotutils.py @@ -978,6 +978,16 @@ def _has_cmap(cm): return False return True +def _mpl_register_cmap(name, cmap, fail_if_present = True ): + if fail_if_present and _has_cmap(name): + return + if hasattr(matplotlib,'colormaps'): + #force to allow overwrite: + matplotlib.colormaps.register(name=name,cmap=cmap,force=True) + else: + #deprecated? at least it stopped working. + plt.register_cmap(name=name,cname=cname) + def plot2d_lego(hist,show=True,cmap=None): _ensure_backend_ok() if not cmap: @@ -1036,15 +1046,15 @@ def plot2d(hist,show=True,cmap=None,statbox=False,statbox_exactcorner=False,figu cmap = cmaps[0] try: - from PyAna.dyncmap import dynamic_2d_colormap + from PyAnaMisc.dyncmap import dynamic_2d_colormap _,_,dynamic_cmap=dynamic_2d_colormap(tmp['X']) - plt.register_cmap(name=dynamic_cmap.name, cmap=dynamic_cmap) + _mpl_register_cmap(name=dynamic_cmap.name, cmap=dynamic_cmap) #to not break other functionality, make a fake copy for the "reverse" of #this custom map as well: import copy dynamic_cmap_r = copy.deepcopy(dynamic_cmap) dynamic_cmap_r.name = dynamic_cmap.name+'_r' - plt.register_cmap(name=dynamic_cmap_r.name, cmap=dynamic_cmap_r)#register a fake inverse + _mpl_register_cmap(name=dynamic_cmap_r.name, cmap=dynamic_cmap_r)#register a fake inverse cmaps+=[dynamic_cmap.name] except ImportError: pass diff --git a/src/simplebuild_dgcode/data/pkgs/Utils/Mesh3D/python/viewer.py b/src/simplebuild_dgcode/data/pkgs/Utils/Mesh3D/python/viewer.py index 31874b9..255e3ee 100644 --- a/src/simplebuild_dgcode/data/pkgs/Utils/Mesh3D/python/viewer.py +++ b/src/simplebuild_dgcode/data/pkgs/Utils/Mesh3D/python/viewer.py @@ -1,6 +1,6 @@ from PyAna import plt, np from Mesh3D import Mesh3D -import PyAna.dyncmap +import PyAna.dyncmap#FIXME: PyAna.misc ? import matplotlib.widgets as mplwidgets class Mesh3DViewer: