Skip to content

Commit

Permalink
requested options for visualizations, see AdvancedPhotonSource#72: co…
Browse files Browse the repository at this point in the history
…nfig var for powder plot colors; edit colors on Phase/General window
  • Loading branch information
briantoby committed Oct 13, 2024
1 parent 1eea656 commit ab0be80
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 52 deletions.
14 changes: 12 additions & 2 deletions GSASII/GSASIIElem.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 13,7 @@
import atmdata
import GSASIImath as G2mth
import ElementTable as ET
import GSASIIElem as G2elem
#import GSASIIElem as G2elem # but this module is GSASIIElem. Why are we doing this?
nxs = np.newaxis
Bohr = 0.529177

Expand Down Expand Up @@ -256,6 256,15 @@ def FixValence(El):
if '-0' in El:
El = El.split('-0')[0]
return El

def SetAtomColor(El,RGB):
'Overrides the default color in the atoms table; not saved'
Elem = ET.ElTable
Elements = [elem[0][0] for elem in Elem]
if 'Q' in El: El = 'Q' #patch - remove Qa, etc.
ElS = getElSym(El)
ET.ElTable[Elements.index(ElS)] = ET.ElTable[Elements.index(ElS)][0:6] (
tuple(RGB),)

def GetAtomInfo(El,ifMag=False):
'reads element information from atmdata.py'
Expand Down Expand Up @@ -900,7 909,8 @@ def SetupGeneral(data, dirname):
continue
nSh = len(Srb['RBId'])
for iSh in range(nSh):
Info = G2elem.GetAtomInfo(Srb['atType'][iSh])
# Info = G2elem.GetAtomInfo(Srb['atType'][iSh])
Info = GetAtomInfo(Srb['atType'][iSh])
if Info['Symbol'] not in generalData['AtomTypes']:
generalData['AtomTypes'].append(Info['Symbol'])
generalData['Z'] = Info['Z']
Expand Down
18 changes: 17 additions & 1 deletion GSASII/GSASIIpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 53,18 @@
fmtver = lambda v: str(v//1000) '.' str(v%1000)
intver = lambda vs: sum([int(i) for i in vs.split('.')[0:2]]*np.array((1000,1)))

def GetConfigValue(key,default=None):
def GetConfigValue(key,default=None,getDefault=False):
'''Return the configuration file value for key or a default value if not present
:param str key: a value to be found in the configuration (config.py) file
:param default: a value to be supplied if none is in the config file or
the config file is not found. Defaults to None
:returns: the value found or the default.
'''
if getDefault:
if default is not None:
raise ValueError('Cannot use default and getDefault together')
default = GetConfigDefault(key)
try:
return configDict.get(key,default)
except NameError: # this happens when building docs
Expand All @@ -82,6 86,18 @@ def SetConfigValue(parmdict):
if parmdict[var][0] == parmdict[var][1]: continue
configDict[var] = parmdict[var][1]

def GetConfigDefault(key):
'''Return the default value for a config value
:param str key: a value to be found in the configuration (config_example.py) file
:returns: the default value or None
'''
try:
import config_example
except:
return None
return config_example.__dict__.get(key)

def addPrevGPX(fil,cDict):
'''Add a GPX file to the list of previous files.
Move previous names to start of list. Keep most recent five files
Expand Down
30 changes: 29 additions & 1 deletion GSASII/GSASIIphsGUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -2048,6 2048,32 @@ def OnIsotope(event):
denSizer[1].SetValue('%.3f'%(density))
if denSizer[2]:
denSizer[2].SetValue('%.3f'%(mattCoeff))

def onDefColor(event):
'''Called when a color bar in elements table is clicked on.
Changes default color for element in all phases
N.B. Change is not saved; will go back to original color when
GSAS-II is restarted.
Changes colors of matching atoms in Draw Atoms table for
current phase -- only.
'''
if not hasattr(event.GetEventObject(),'atomNum'): return
anum = event.GetEventObject().atomNum
(R,G,B) = generalData['Color'][anum]
dlg = wx.ColourDialog(event.GetEventObject().GetTopLevelParent())
dlg.GetColourData().SetChooseFull(False)
dlg.GetColourData().SetColour(wx.Colour(R,G,B))
if dlg.ShowModal() == wx.ID_OK:
El = generalData['AtomTypes'][anum]
RGB = dlg.GetColourData().GetColour()[0:3]
G2elem.SetAtomColor(El, RGB)
cx,ct,cs,ci = data['Drawing']['atomPtrs']
for atom in data['Drawing']['Atoms']:
if atom[ct] != El: continue
atom[cs 2] = RGB
breakpoint()
wx.CallAfter(UpdateGeneral)
dlg.Destroy()

elemSizer = wx.FlexGridSizer(0,len(generalData['AtomTypes']) 1,1,1)
elemSizer.Add(wx.StaticText(General,label=' Elements'),0,WACV)
Expand Down Expand Up @@ -2083,9 2109,11 @@ def OnIsotope(event):
elemTxt = G2G.ReadOnlyTextCtrl(General,value='%.2f'%(rad))
elemSizer.Add(elemTxt,0,WACV)
elemSizer.Add(wx.StaticText(General,label=' Default color'),0,WACV)
for R,G,B in generalData['Color']:
for i,(R,G,B) in enumerate(generalData['Color']):
colorTxt = G2G.ReadOnlyTextCtrl(General,value='')
colorTxt.SetBackgroundColour(wx.Colour(R,G,B))
colorTxt.atomNum = i
colorTxt.Bind(wx.EVT_SET_FOCUS,onDefColor)
elemSizer.Add(colorTxt,0,WACV)
if generalData['Type'] == 'magnetic':
elemSizer.Add(wx.StaticText(General,label=' Lande g factor: '),0,WACV)
Expand Down
91 changes: 62 additions & 29 deletions GSASII/GSASIIpwdplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 1205,11 @@ def incCptn(string):
global Ymax
global Pattern,mcolors,Plot,Page,imgAx,Temps
plottype = plotType

# get powder pattern colors from config settings
pwdrCol = {}
for i in 'Obs_color','Calc_color','Diff_color','Bkg_color':
pwdrCol[i] = '#' GSASIIpath.GetConfigValue(i,getDefault=True)

if not G2frame.PatternId:
return
Expand Down Expand Up @@ -1428,15 1433,26 @@ def incCptn(string):
magLineList = [] # null value indicates no magnification
Page.toolbar.updateActions = None # no update actions
G2frame.cid = None
Page.keyPress = OnPlotKeyPress
try:
colors = GSASIIpath.GetConfigValue('Plot_Colors').split()
for color in colors:
if color not in ['k','r','g','b','m','c']:
print('**** bad color code: ' str(color) ' - redo Preferences/Plot Colors ****')
raise Exception
except:
colors = ['b','g','r','c','m','k']
Page.keyPress = OnPlotKeyPress
# assemble a list of validated colors (not currently needed)
# valid_colors = []
# invalid_colors = []
# try:
# colors = GSASIIpath.GetConfigValue('Plot_Colors').split()
# for color in colors:
# #if color not in ['k','r','g','b','m','c']:
# if mpl.colors.is_color_like(color):
# valid_colors.append(color)
# else:
# invalid_colors.append(color)
# except:
# pass
# if invalid_colors:
# print(f'**** bad color code(s): "{", ".join(invalid_colors)}" - redo Preferences/Plot Colors ****')
# if len(valid_colors) < 3:
# colors = ['b','g','r','c','m','k']
# else:
# colors = valid_colors
Lines = []
exclLines = []
time0 = time.time()
Expand Down Expand Up @@ -1878,7 1894,7 @@ def incCptn(string):
DZ = (xye[1]-xye[3])*np.sqrt(wtFactor*xye[2])
if 'PWDR' in plottype and len(limits[2:]):
DZ = ma.array(DZ,mask=Emask) # weighted difference is always masked
DifLine = Plot1.plot(X,DZ,colors[3],picker=True,pickradius=1.,label=incCptn('diff')) #(Io-Ic)/sig(Io)
DifLine = Plot1.plot(X,DZ,pwdrCol['Diff_color'],picker=True,pickradius=1.,label=incCptn('diff')) #(Io-Ic)/sig(Io)
if Page.plotStyle.get('font',False):
Plot1.tick_params(labelsize=14)
else:
Expand All @@ -1891,12 1907,12 @@ def incCptn(string):
Plot.set_yscale("log",nonpositive='mask') # >=3.3
except:
Plot.set_yscale("log",nonpositive='mask')
Plot.plot(X,Y,marker=pP,color=colors[0],linewidth=lW,picker=True,pickradius=3.,
Plot.plot(X,Y,marker=pP,color=pwdrCol['Obs_color'],linewidth=lW,picker=True,pickradius=3.,
clip_on=Clip_on,label=incCptn('obs'))
if G2frame.SinglePlot or G2frame.plusPlot:
Plot.plot(X,Z,colors[1],picker=False,label=incCptn('calc'),linewidth=1.5)
Plot.plot(X,Z,pwdrCol['Calc_color'],picker=False,label=incCptn('calc'),linewidth=1.5)
if G2frame.plusPlot:
Plot.plot(X,W,colors[2],picker=False,label=incCptn('bkg'),linewidth=1.5) #background
Plot.plot(X,W,pwdrCol['Bkg_color'],picker=False,label=incCptn('bkg'),linewidth=1.5) #background
elif plottype in ['SASD','REFD']:
try:
Plot.set_xscale("log",nonpositive='mask') # >=3.3
Expand All @@ -1907,45 1923,45 @@ def incCptn(string):
if G2frame.ErrorBars:
if Page.plotStyle['sqPlot']:
Plot.errorbar(X,YB,yerr=X**4*Sample['Scale'][0]*np.sqrt(1./(Pattern[0]['wtFactor']*xye[2])),
ecolor=colors[0],
ecolor=pwdrCol['Obs_color'],
picker=True,pickradius=3.,clip_on=Clip_on)
else:
Plot.errorbar(X,YB,yerr=Sample['Scale'][0]*np.sqrt(1./(Pattern[0]['wtFactor']*xye[2])),
ecolor=colors[0],
ecolor=pwdrCol['Obs_color'],
picker=True,pickradius=3.,clip_on=Clip_on,label=incCptn('obs'))
else:
Plot.plot(X,YB,marker=pP,color=colors[0],linewidth=lW,
Plot.plot(X,YB,marker=pP,color=pwdrCol['Obs_color'],linewidth=lW,
picker=True,pickradius=3.,clip_on=Clip_on,label=incCptn('obs'))
Plot.plot(X,W,colors[1],picker=False,label=incCptn('bkg'),linewidth=1.5) #const. background
Plot.plot(X,ZB,colors[2],picker=False,label=incCptn('calc'),linewidth=1.5)
Plot.plot(X,W,pwdrCol['Calc_color'],picker=False,label=incCptn('bkg'),linewidth=1.5) #const. background
Plot.plot(X,ZB,pwdrCol['Bkg_color'],picker=False,label=incCptn('calc'),linewidth=1.5)
else: # not logPlot
ymax = 1.
if Page.plotStyle['Normalize'] and Y.max() != 0 and not G2frame.SinglePlot:
ymax = Y.max()
if G2frame.SubBack:
if 'PWDR' in plottype:
ObsLine = Plot.plot(Xum,Y/ymax,color=colors[0],marker=pP,linewidth=lW,
ObsLine = Plot.plot(Xum,Y/ymax,color=pwdrCol['Obs_color'],marker=pP,linewidth=lW,
picker=False,clip_on=Clip_on,label=incCptn('obs-bkg')) #Io-Ib
if np.any(Z): #only if there is a calc pattern
CalcLine = Plot.plot(X,(Z-W)/ymax,colors[1],picker=False,
CalcLine = Plot.plot(X,(Z-W)/ymax,pwdrCol['Calc_color'],picker=False,
label=incCptn('calc-bkg'),linewidth=1.5) #Ic-Ib
else:
Plot.plot(X,YB,color=colors[0],marker=pP,linewidth=lW,
Plot.plot(X,YB,color=pwdrCol['Obs_color'],marker=pP,linewidth=lW,
picker=True,pickradius=3.,clip_on=Clip_on,label=incCptn('obs'))
Plot.plot(X,ZB,colors[2],picker=False,label=incCptn('calc'),linewidth=1.5)
Plot.plot(X,ZB,pwdrCol['Bkg_color'],picker=False,label=incCptn('calc'),linewidth=1.5)
else:
if 'PWDR' in plottype:
ObsLine = Plot.plot(Xum,Y/ymax,color=colors[0],marker=pP,linewidth=lW,
ObsLine = Plot.plot(Xum,Y/ymax,color=pwdrCol['Obs_color'],marker=pP,linewidth=lW,
picker=True,pickradius=3.,clip_on=Clip_on,label=incCptn('obs')) #Io
CalcLine = Plot.plot(X,Z/ymax,colors[1],picker=False,label=incCptn('calc'),linewidth=1.5) #Ic
CalcLine = Plot.plot(X,Z/ymax,pwdrCol['Calc_color'],picker=False,label=incCptn('calc'),linewidth=1.5) #Ic
else:
Plot.plot(X,YB,color=colors[0],marker=pP,linewidth=lW,
Plot.plot(X,YB,color=pwdrCol['Obs_color'],marker=pP,linewidth=lW,
picker=True,pickradius=3.,clip_on=Clip_on,label=incCptn('obs'))
Plot.plot(X,ZB,colors[2],picker=False,label=incCptn('calc'),linewidth=1.5)
Plot.plot(X,ZB,pwdrCol['Bkg_color'],picker=False,label=incCptn('calc'),linewidth=1.5)
if 'PWDR' in plottype and (G2frame.SinglePlot and G2frame.plusPlot):
BackLine = Plot.plot(X,W/ymax,colors[2],picker=False,label=incCptn('bkg'),linewidth=1.5) #Ib
BackLine = Plot.plot(X,W/ymax,pwdrCol['Bkg_color'],picker=False,label=incCptn('bkg'),linewidth=1.5) #Ib
if not G2frame.Weight and np.any(Z):
DifLine = Plot.plot(X,D/ymax,colors[3],linewidth=1.5,
DifLine = Plot.plot(X,D/ymax,pwdrCol['Diff_color'],linewidth=1.5,
picker=True,pickradius=1.,label=incCptn('diff')) #Io-Ic
Plot.axhline(0.,color='k',label='_zero')

Expand Down Expand Up @@ -2124,7 2140,24 @@ def incCptn(string):
Phases = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId,'Reflection Lists'))
l = GSASIIpath.GetConfigValue('Tick_length',8.0)
w = GSASIIpath.GetConfigValue('Tick_width',1.)
refColors=['b','r','c','g','m','k']
# assemble a list of validated colors for tickmarks
valid_colors = []
invalid_colors = []
for color in GSASIIpath.GetConfigValue('Ref_Colors',getDefault=True).split():
try:
if mpl.colors.is_color_like(color):
valid_colors.append(color)
else:
invalid_colors.append(color)
except:
pass
if invalid_colors:
print(f'**** bad color code(s): "{", ".join(invalid_colors)}" - redo Preferences/Ref_Colors ****')
if len(valid_colors) < 3:
refColors=['b','r','c','g','m','k']
else:
refcolors = valid_colors

Page.phaseList = sorted(Phases.keys()) # define an order for phases (once!)
Page.phaseColors = {p:refColors[i%len(refColors)] for i,p in enumerate(Phases)}
for pId,phase in enumerate(Page.phaseList):
Expand Down
67 changes: 48 additions & 19 deletions GSASII/config_example.py
Original file line number Diff line number Diff line change
@@ -1,12 1,5 @@
# -*- coding: utf-8 -*-
#config.py - Variables used to set optional configuration options
########### SVN repository information ###################
# $Date: 2024-05-24 10:06:45 -0500 (Fri, 24 May 2024) $
# $Author: toby $
# $Revision: 5789 $
# $URL: https://subversion.xray.aps.anl.gov/pyGSAS/trunk/config_example.py $
# $Id: config_example.py 5789 2024-05-24 15:06:45Z toby $
########### SVN repository information ###################
'''
This file contains optional configuration options for GSAS-II. The variables
in this file can be copied to file config.py, which is imported if present.
Expand All @@ -16,21 9,28 @@
directory (GSASIIpath.Path2GSAS2) or a directory for local GSAS-II
modifications (~/.G2local/ or /Documents and Settings/<User>/.G2local/).
Note that the contents of config.py is usually changed
using GSASIIctrlGUI.SelectConfigSetting.
using :func:`GSASIIctrlGUI.SelectConfigSetting`.
When defining new config variables for GSAS-II, define them here with a
default value: use None or a string for strings, or use integers or real
values. Include a doc string after each variable is defined to explain
what it does. Use names ending in _location or _directory for items
that will contain directory names. Use names ending in _exec for executable
files (.exe on windows).
values as defaults to ensure that only values of that type are allowed.
Include a doc string after each variable is defined to explain
what it does.
If a name ends with a particular keyword, then specialized edit
routines are used.
* Names ending in _location or _directory are for items
* Names ending in _exec for executable files (.exe on windows).
* Names ending in _color for colors, to be specified as RGBA values
(note that Contour_color is restricted to color maps).
For example::
test_int = 0
test_float = 0.0
test_string = None (or)
test_string = 'value'
int_config = 0
float_config = 0.0
string_config = None (or)
string_config = 'value'
'''

debug = False
Expand Down Expand Up @@ -198,9 198,38 @@
'''when True, GSAS-II instprm file are shown as default; when False, old GSAS stype prm, etc files are default
'''

Plot_Colors = 'k r g b m c'
'''The colors for line plots: use one of 'k'-black, 'r'-red, 'b'-blue, 'g'-green, 'm'-magenta, 'c'-cyan for the
line colors in order of obs., calc., back., diff., color5 & color6 separated by spaces; 6 items required.
Ref_Colors = 'b r c g m k'
'''The colors for reflection tick marks by phase.
Use one of 'k'-black, 'r'-red, 'b'-blue, 'g'-green, 'm'-magenta, 'c'-cyan
for the line colors, or any other valid matplotlib color name or hex code.
'''

Obs_color = '0000ffff'
'''The color for plotting the observed powder diffraction pattern.
Colors are specified as hex RGBA values, as used in Matplotlib (without
preceding #).
The default is 0000ffff, which sets the color to blue.
'''

Calc_color = '008000ff'
'''The color for plotting the computed powder diffraction pattern.
Colors are specified as hex RGBA values, as used in Matplotlib (without
preceding #).
The default is 00ff00ff, which sets the color to green.
'''

Diff_color = '00bfbfff'
'''The color for plotting the obs-calc powder diffraction pattern.
Colors are specified as hex RGBA values, as used in Matplotlib (without
preceding #).
The default is 00ffffff, which sets the color to cyan.
'''

Bkg_color = 'ff0000ff'
'''The color for plotting the background powder diffraction pattern.
Colors are specified as hex RGBA values, as used in Matplotlib (without
preceding #).
The default is ff0000ff, which sets the color to red.
'''

PDF_Rmax = 100.
Expand Down

0 comments on commit ab0be80

Please sign in to comment.