Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
bb50393
code to create groups; remove CIF Author
briantoby Sep 6, 2025
96bc5e5
Merge remote-tracking branch 'origin/main' into TOFgroup
briantoby Sep 8, 2025
bf68f82
Merge remote-tracking branch 'origin/main' into TOFgroup
briantoby Sep 8, 2025
6d5470b
Add section for plotting grouped histograms. Still need to figure out…
briantoby Sep 10, 2025
0c00d51
Label plots using common & unique part of hist name; use reflection t…
briantoby Sep 10, 2025
3985cbe
make sharing X-axes an option for grouped plots
briantoby Sep 18, 2025
e99db49
WIP: adding group tree items & plot groups
briantoby Oct 22, 2025
bdb60ed
Merge remote-tracking branch 'origin/main' into TOFgroup to bring up …
briantoby Oct 22, 2025
751d211
WIP: get plotting working, fix display of groups. Next: table for edi…
briantoby Oct 23, 2025
68b0c08
WIP: shows table of HAP values, but can we make row labels not scroll?
briantoby Oct 27, 2025
789a02e
working implementation with unscrolled labels not 100% ideal and not …
briantoby Oct 29, 2025
88d1f19
clean implementation of group HAP display
briantoby Oct 30, 2025
df236d1
WIP: now sample param works
briantoby Nov 1, 2025
1f3458e
WIP: Edit parametric name; move refine after value
briantoby Nov 1, 2025
2019dbb
Full working version to display HAP, Sample & Inst vals
briantoby Nov 4, 2025
f9e6ed3
bring TOFgroup up to date with main
briantoby Nov 4, 2025
d2db3b9
Merge remote-tracking branch 'origin/main' into TOFgroup
briantoby Nov 7, 2025
98f2a43
Fix tickmarks in plot
briantoby Nov 8, 2025
31712f9
get latest changes in main
briantoby Nov 9, 2025
262e52b
update to latest main version
briantoby Nov 9, 2025
99cdfa5
fix bindings in plotting so that plotType etc is current
briantoby Nov 10, 2025
47b4858
WIP: implement Limits page; start on copy & ref/all
briantoby Nov 10, 2025
df1849d
finish copy/ref button implementation
briantoby Nov 10, 2025
d177f5c
Merge remote-tracking branch 'origin/main' into TOFgroup
briantoby Nov 19, 2025
d6263a5
bring in latest changes in main
briantoby Nov 22, 2025
6c44c16
allow limits to be set in Q & d; reset drags when mouse is out of plo…
briantoby Nov 29, 2025
b9d1c8d
update to match latest main branch & minor picker fixes
briantoby Nov 30, 2025
26fd234
move copy button to between 1st & 2nd column, but remove from limits …
briantoby Dec 1, 2025
0a25d8c
update from main
briantoby Dec 2, 2025
1a2742a
Add background terms
briantoby Dec 13, 2025
6e491f1
bring in fix for pdabc
briantoby Dec 13, 2025
c0ae310
implement limits on grouped plots; rework arrows & publish plot arrow…
briantoby Dec 14, 2025
8c32385
wrap group plot if too few entries
briantoby Dec 14, 2025
6a9fb4c
add menu bar for groups; fix bug for 2+ digit bank number
briantoby Dec 17, 2025
14d7ca2
pull in fix to bkg peaks
briantoby Dec 20, 2025
784e3be
refactor value reference in prep for copy by group
briantoby Dec 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 135 additions & 23 deletions GSASII/GSASIIdataGUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def new_util_find_library( name ):
from . import GSASIIfpaGUI as G2fpa
from . import GSASIIseqGUI as G2seq
from . import GSASIIddataGUI as G2ddG
from . import GSASIIgroupGUI as G2gr

try:
wx.NewIdRef
Expand Down Expand Up @@ -1404,6 +1405,7 @@ def OnImportSfact(self,event):
header = 'Select phase(s) to add the new\nsingle crystal dataset(s) to:'
for Name in newHistList:
header += '\n '+str(Name)
if len(header) > 200: header = header[:200]+'...'
result = G2G.ItemSelector(phaseNameList,self,header,header='Add to phase(s)',multiple=True)
if not result: return
# connect new phases to histograms
Expand Down Expand Up @@ -1997,7 +1999,7 @@ def OnImportPowder(self,event):
header = 'Select phase(s) to link\nto the newly-read data:'
for Name in newHistList:
header += '\n '+str(Name)

if len(header) > 200: header = header[:200]+'...'
result = G2G.ItemSelector(phaseNameList,self,header,header='Add to phase(s)',multiple=True)
if not result: return
# connect new phases to histograms
Expand Down Expand Up @@ -4300,13 +4302,14 @@ def OnFileBrowse(self, event):
print (traceback.format_exc())


def StartProject(self):
def StartProject(self,selectItem=True):
'''Opens a GSAS-II project file & selects the 1st available data set to
display (PWDR, HKLF, REFD or SASD)
'''

Id = 0
phaseId = None
GroupId = None
seqId = None
G2IO.ProjFileOpen(self)
self.GPXtree.SetItemText(self.root,'Project: '+self.GSASprojectfile)
Expand All @@ -4326,26 +4329,36 @@ def StartProject(self):
seqId = item
elif name == "Phases":
phaseId = item
elif name.startswith("Groups"):
GroupId = item
elif name == 'Controls':
data = self.GPXtree.GetItemPyData(item)
if data:
for item in self.Refine: item.Enable(True)
item, cookie = self.GPXtree.GetNextChild(self.root, cookie)
if phaseId: # show all phases
self.GPXtree.Expand(phaseId)
if seqId:
if GroupId:
self.GPXtree.Expand(GroupId)
# select an item
if seqId and selectItem:
self.EnablePlot = True
SelectDataTreeItem(self,seqId)
self.GPXtree.SelectItem(seqId) # needed on OSX or item is not selected in tree; perhaps not needed elsewhere
elif Id:
elif GroupId and selectItem:
self.EnablePlot = True
self.GPXtree.Expand(GroupId)
SelectDataTreeItem(self,GroupId)
self.GPXtree.SelectItem(GroupId) # needed on OSX or item is not selected in tree; perhaps not needed elsewhere
elif Id and selectItem:
self.EnablePlot = True
self.GPXtree.Expand(Id)
SelectDataTreeItem(self,Id)
self.GPXtree.SelectItem(Id) # needed on OSX or item is not selected in tree; perhaps not needed elsewhere
elif phaseId:
elif phaseId and selectItem:
Id = phaseId
# open 1st phase
Id, unused = self.GPXtree.GetFirstChild(phaseId)
Id,_ = self.GPXtree.GetFirstChild(phaseId)
SelectDataTreeItem(self,Id)
self.GPXtree.SelectItem(Id) # as before for OSX
self.CheckNotebook()
Expand Down Expand Up @@ -7495,6 +7508,20 @@ def _makemenu(): # routine to create menu when first used
# don't know which menu was selected, but should be General on first phase use
SetDataMenuBar(G2frame,self.DataGeneral)
self.DataGeneral = _makemenu

# Groups
G2G.Define_wxId('wxID_GRPALL','wxID_GRPSEL','wxID_HIDESAME')
def _makemenu(): # routine to create menu when first used
self.GroupMenu = wx.MenuBar()
self.PrefillDataMenu(self.GroupMenu)
self.GroupCmd = wx.Menu(title='')
self.GroupMenu.Append(menu=self.GroupCmd, title='Grp Cmds')
self.GroupCmd.Append(G2G.wxID_GRPALL,'Copy all','Copy all parameters by group')
self.GroupCmd.Append(G2G.wxID_GRPSEL,'Copy selected','Copy elected parameters by group')
# self.GroupCmd.Append(G2G.wxID_HIDESAME,'Hide identical rows','Omit rows that are the same and are not refinable from table')
self.PostfillDataMenu()
SetDataMenuBar(G2frame,self.GroupMenu)
self.GroupMenu = _makemenu
# end of GSAS-II menu definitions

def readFromFile(reader):
Expand Down Expand Up @@ -7901,26 +7928,63 @@ def OnFsqRef(event):
ShklSizer.Add(usrrej,0,WACV)
return LSSizer,ShklSizer

def AuthSizer():
def OnAuthor(event):
event.Skip()
data['Author'] = auth.GetValue()

Author = data['Author']
authSizer = wx.BoxSizer(wx.HORIZONTAL)
authSizer.Add(wx.StaticText(G2frame.dataWindow,label=' CIF Author (last, first):'),0,WACV)
auth = wx.TextCtrl(G2frame.dataWindow,-1,value=Author,style=wx.TE_PROCESS_ENTER)
auth.Bind(wx.EVT_TEXT_ENTER,OnAuthor)
auth.Bind(wx.EVT_KILL_FOCUS,OnAuthor)
authSizer.Add(auth,0,WACV)
return authSizer
# def AuthSizer():
# def OnAuthor(event):
# event.Skip()
# data['Author'] = auth.GetValue()
#
# Author = data['Author']
# authSizer = wx.BoxSizer(wx.HORIZONTAL)
# authSizer.Add(wx.StaticText(G2frame.dataWindow,label=' CIF Author (last, first):'),0,WACV)
# auth = wx.TextCtrl(G2frame.dataWindow,-1,value=Author,style=wx.TE_PROCESS_ENTER)
# auth.Bind(wx.EVT_TEXT_ENTER,OnAuthor)
# auth.Bind(wx.EVT_KILL_FOCUS,OnAuthor)
# authSizer.Add(auth,0,WACV)
# return authSizer

def ClearFrozen(event):
'Removes all frozen parameters by clearing the entire dict'
Controls['parmFrozen'] = {}
wx.CallAfter(UpdateControls,G2frame,data)

# start of UpdateControls
def SearchGroups(event):
'''Create a dict to group similar histograms. Similarity
is judged by a common string that matches a template
supplied by the user
'''
Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
for hist in Histograms:
if hist.startswith('PWDR '):
break
else:
G2G.G2MessageBox(G2frame,'No used PWDR histograms found to group. Histograms must be assigned phase(s).',
'Cannot group')
return
ans = G2frame.OnFileSave(None)
if not ans: return
data['Groups'] = G2gr.SearchGroups(G2frame,Histograms,hist)
# wx.CallAfter(UpdateControls,G2frame,data)
ans = G2frame.OnFileSave(None)
if not ans: return
G2frame.clearProject() # clear out data tree
G2frame.StartProject(False)
#self.EnablePlot = True
Id = GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')
SelectDataTreeItem(G2frame,Id)
G2frame.GPXtree.SelectItem(Id) # needed on OSX or item is not selected in tree; perhaps not needed elsewhere

def ClearGroups(event):
del data['Groups']
ans = G2frame.OnFileSave(None)
if not ans: return
G2frame.clearProject() # clear out data tree
G2frame.StartProject(False)
#self.EnablePlot = True
Id = GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')
SelectDataTreeItem(G2frame,Id)
G2frame.GPXtree.SelectItem(Id) # needed on OSX or item is not selected in tree; perhaps not needed elsewhere

#======= start of UpdateControls ===========================================
if 'SVD' in data['deriv type']:
G2frame.GetStatusBar().SetStatusText('Hessian SVD not recommended for initial refinements; use analytic Hessian or Jacobian',1)
else:
Expand Down Expand Up @@ -7961,11 +8025,44 @@ def ClearFrozen(event):
G2G.HorizontalLine(mainSizer,G2frame.dataWindow)
subSizer = wx.BoxSizer(wx.HORIZONTAL)
subSizer.Add((-1,-1),1,wx.EXPAND)
subSizer.Add(wx.StaticText(G2frame.dataWindow,label='Global Settings'),0,WACV)
subSizer.Add(wx.StaticText(G2frame.dataWindow,label='Histogram Grouping'),0,WACV)
subSizer.Add((-1,-1),1,wx.EXPAND)
mainSizer.Add(subSizer,0,wx.EXPAND)
subSizer = wx.BoxSizer(wx.HORIZONTAL)
groupDict = data.get('Groups',{}).get('groupDict',{})
subSizer.Add((-1,-1),1,wx.EXPAND)
if groupDict:
groupCount = [len(groupDict[k]) for k in groupDict]
if min(groupCount) == max(groupCount):
msg = f'Have {len(groupDict)} group(s) with {min(groupCount)} histograms in each'
else:
msg = (f'Have {len(groupDict)} group(s) with {min(groupCount)}'
f' to {min(groupCount)} histograms in each')
notGrouped = data.get('Groups',{}).get('notGrouped',0)
if notGrouped:
msg += f". {notGrouped} not in a group"
subSizer.Add(wx.StaticText(G2frame.dataWindow,label=msg),0,WACV)
subSizer.Add((5,-1))
btn = wx.Button(G2frame.dataWindow, wx.ID_ANY,'Redefine groupings')
else:
btn = wx.Button(G2frame.dataWindow, wx.ID_ANY,'Define groupings')
btn.Bind(wx.EVT_BUTTON,SearchGroups)
subSizer.Add(btn)
if groupDict:
btn = wx.Button(G2frame.dataWindow, wx.ID_ANY,'Clear groupings')
subSizer.Add((5,-1))
subSizer.Add(btn)
btn.Bind(wx.EVT_BUTTON,ClearGroups)
subSizer.Add((-1,-1),1,wx.EXPAND)
mainSizer.Add(subSizer,0,wx.EXPAND)
mainSizer.Add(AuthSizer())
mainSizer.Add((5,5),0)
mainSizer.Add((-1,8))
G2G.HorizontalLine(mainSizer,G2frame.dataWindow)
subSizer = wx.BoxSizer(wx.HORIZONTAL)
subSizer.Add((-1,-1),1,wx.EXPAND)
# subSizer.Add(wx.StaticText(G2frame.dataWindow,label='Global Settings'),0,WACV)
# subSizer.Add((-1,-1),1,wx.EXPAND)
# mainSizer.Add(subSizer,0,wx.EXPAND)
# mainSizer.Add(AuthSizer())
Controls = data
# count frozen variables (in appropriate place)
for key in ('parmMinDict','parmMaxDict','parmFrozen'):
Expand Down Expand Up @@ -8879,6 +8976,11 @@ def OnShowShift(event):
#import imp
#imp.reload(G2ddG)
G2ddG.MakeHistPhaseWin(G2frame)
elif G2frame.GPXtree.GetItemText(item).startswith('Groups/'):
# groupDict is defined (or item would not be in tree).
# At least for now, this does nothing, so advance to first group entry
item, cookie = G2frame.GPXtree.GetFirstChild(item)
wx.CallAfter(G2frame.GPXtree.SelectItem,item)
elif GSASIIpath.GetConfigValue('debug'):
print('Unknown tree item',G2frame.GPXtree.GetItemText(item))
############################################################################
Expand Down Expand Up @@ -9076,6 +9178,16 @@ def OnShowShift(event):
data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
G2pdG.UpdateReflectionGrid(G2frame,data,HKLF=True,Name=name)
G2frame.dataWindow.HideShow.Enable(True)
elif G2frame.GPXtree.GetItemText(parentID).startswith('Groups/'):
# if GSASIIpath.GetConfigValue('debug'):
# print('Debug: reloading',G2gr)
# from importlib import reload
# reload(G2G)
# reload(G2gr)
G2gr.UpdateGroup(G2frame,item)
elif GSASIIpath.GetConfigValue('debug'):
print(f'Unknown subtree item {G2frame.GPXtree.GetItemText(item)!r}',
f'\n\tparent: {G2frame.GPXtree.GetItemText(parentID)!r}')

if G2frame.PickId:
G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
Expand Down
6 changes: 5 additions & 1 deletion GSASII/GSASIIfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -1467,7 +1467,11 @@ def FormatValue(val,maxdigits=None):
digits.append('f')
if not val:
digits[2] = 'f'
fmt="{:"+str(digits[0])+"."+str(digits[1])+digits[2]+"}"
if digits[2] == 'g':
fmt="{:#"+str(digits[0])+"."+str(digits[1])+digits[2]+"}"
# the # above forces inclusion of a decimal place: 10.000 rather than 10 for 9.999999999
else:
fmt="{:"+str(digits[0])+"."+str(digits[1])+digits[2]+"}"
string = fmt.format(float(val)).strip() # will standard .f formatting work?
if len(string) <= digits[0]:
if ':' in string: # deal with weird bug where a colon pops up in a number when formatting (EPD 7.3.2!)
Expand Down
Loading
Loading