diff --git a/GSASII/GSASIIdataGUI.py b/GSASII/GSASIIdataGUI.py index 9951f148..0a4707a0 100644 --- a/GSASII/GSASIIdataGUI.py +++ b/GSASII/GSASIIdataGUI.py @@ -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 @@ -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 @@ -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 @@ -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) @@ -4326,6 +4329,8 @@ 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: @@ -4333,19 +4338,27 @@ def StartProject(self): 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() @@ -5525,6 +5538,8 @@ def OnRefine(self,event): self.SaveTreeSetting() # save the current tree selection self.GPXtree.SaveExposedItems() # save the exposed/hidden tree items if self.PatternId and self.GPXtree.GetItemText(self.PatternId).startswith('PWDR '): + # true when a pattern is selected for plotting, which includes + # when a group is selected. refPlotUpdate = G2pwpl.PlotPatterns(self,refineMode=True) # prepare for plot updating else: refPlotUpdate = None @@ -7495,6 +7510,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): @@ -7901,26 +7930,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: @@ -7961,11 +8027,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'): @@ -8879,6 +8978,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)) ############################################################################ @@ -9076,6 +9180,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(G2pwpl) + # 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) diff --git a/GSASII/GSASIIfiles.py b/GSASII/GSASIIfiles.py index 231a34bb..e8e6f976 100644 --- a/GSASII/GSASIIfiles.py +++ b/GSASII/GSASIIfiles.py @@ -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!) diff --git a/GSASII/GSASIIgroupGUI.py b/GSASII/GSASIIgroupGUI.py new file mode 100644 index 00000000..089ee838 --- /dev/null +++ b/GSASII/GSASIIgroupGUI.py @@ -0,0 +1,1117 @@ +# -*- coding: utf-8 -*- +''' +Routines for working with groups of histograms. + +Groups are defined in Controls entry ['Groups'] which contains three entries: + +* Controls['Groups']['groupDict'] + a dict where each key is the name of the group and the value is a list of + histograms in the group +* Controls['Groups']['notGrouped'] + a count of the number of histograms that are not in any group +* Controls['Groups']['template'] + the string used to set the grouping + +** Parameter Data Table ** + +For use to create GUI tables and to copy values between histograms, parameters +are organized in a dict where each dict entry has contents of form: + + * dict['__dataSource'] : SourceArray + + * dict[histogram]['label'] : `innerdict` + +where `label` is the text shown on the row label and `innerdict` can contain +one or more of the following elements: + + * 'val' : (key1,key2,...) + * 'ref' : (key1, key2,...) + * 'range' : (float,float) + * 'str' : (key1,key2,...) + * 'fmt' : str + * 'txt' : str + * 'init' : float + * 'rowlbl' : (array, key) + +One of 'val', 'ref' or 'str' elements will be present. + + * The 'val' tuple provides a reference to the float value for the + defined quantity, where SourceArray[histogram][key1][key2][...] + provides r/w access to the parameter. + + * The 'ref' tuple provides a reference to the bool value, where + SourceArray[histogram][key1][key2][...] provides r/w access to the + refine flag for the labeled quantity + + Both 'ref' and 'val' are usually defined together, but either may + occur alone. These exceptions will be for parameters where a single + refine flag is used for a group of parameters or for non-refined + parameters. + + * The 'str' value is something that cannot be edited from the GUI; If 'str' is + present, the only other possible entries that can be present is either 'fmt' + or 'txt. + 'str' is used for a parameter value that is typically computed or must be + edited in the histogram section. + + * The 'fmt' value is a string used to format the 'str' value to + convert it to a string, if it is a float or int value. + + * The 'txt' value is a string that replaces the value in 'str'. + + * The 'init' value is also something that cannot be edited. + These 'init' values are used for Instrument Parameters + where there is both a current value for the parameter as + well as an initial value (usually read from the instrument + parameters file when the histogram is read. If 'init' is + present in `innerdict`, there will also be a 'val' entry + in `innerdict` and likely a 'ref' entry as well. + + * The 'rowlbl' value provides a reference to a str value that + will be an editable row label (FreePrmX sample parametric + values). + + * The 'range' list/tuple provides min and max float value for the + defined quantity to be defined. Use None for any value that + should not be enforced. The 'range' values will be used as limits + for the entry widget. + +''' + +# import math +# import os +import re +# import copy +# import platform +# import pickle +# import sys +# import random as ran + +#import numpy as np +# import numpy.ma as ma +import wx + +# from . import GSASIIpath +from . import GSASIIdataGUI as G2gd +# from . import GSASIIobj as G2obj +# from . import GSASIIpwdGUI as G2pdG +# from . import GSASIIimgGUI as G2imG +# from . import GSASIIElem as G2el +# from . import GSASIIfiles as G2fil +# from . import GSASIIctrlGUI as G2G +# from . import GSASIImath as G2mth +# from . import GSASIIElem as G2elem +from . import GSASIIspc as G2spc +from . import GSASIIlattice as G2lat +# from . import GSASIIpwd as G2pwd +from . import GSASIIctrlGUI as G2G +from . import GSASIIpwdplot as G2pwpl +WACV = wx.ALIGN_CENTER_VERTICAL + +def SearchGroups(G2frame,Histograms,hist): + '''Determine which histograms are in groups, called by SearchGroups in + :func:`GSASIIdataGUI.UpdateControls`. + ''' + repeat = True + srchStr = hist[5:] + msg = ('Edit the histogram name below placing a question mark (?) ' + 'at the location ' + 'of characters that change between groups of ' + 'histograms. Use backspace or delete to remove ' + 'characters that should be ignored as they will ' + 'vary within a histogram group (e.g. Bank 1). ' + 'Be sure to leave enough characters so the string ' + 'can be uniquely matched.') + while repeat: + srchStr = G2G.StringSearchTemplate(G2frame,'Set match template', + msg,srchStr) + if srchStr is None: return {} # cancel pressed + reSrch = re.compile(srchStr.replace('.',r'\.').replace('?','.')) + setDict = {} + keyList = [] + noMatchCount = 0 + for hist in Histograms: + if hist.startswith('PWDR '): + m = reSrch.search(hist) + if m: + key = hist[m.start():m.end()] + setDict[hist] = key + if key not in keyList: keyList.append(key) + else: + noMatchCount += 1 + groupDict = {} + groupCount = {} + for k in keyList: + groupDict[k] = [hist for hist,key in setDict.items() if k == key] + groupCount[k] = len(groupDict[k]) + + msg1 = f'With search template "{srchStr}", ' + + buttons = [] + OK = True + if len(groupCount) == 0: + msg1 += f'there are ho histograms in any groups.' + elif min(groupCount.values()) == max(groupCount.values()): + msg1 += f'there are {len(groupDict)} groups with {min(groupCount.values())} histograms each.' + else: + msg1 += (f'there are {len(groupDict)} groups with between {min(groupCount.values())}' + f' and {min(groupCount.values())} histograms in each.') + if noMatchCount: + msg1 += f"\n\nNote that {noMatchCount} PWDR histograms were not included in any groups." + # place a sanity check limit on the number of histograms in a group + if len(groupCount) == 0: + OK = False + elif max(groupCount.values()) >= 150: + OK = False + msg1 += '\n\nThis exceeds the maximum group length of 150 histograms' + elif min(groupCount.values()) == max(groupCount.values()) == 1: + OK = False + msg1 += '\n\nEach histogram is in a separate group. Grouping histograms only makes sense with multiple histograms in at least some groups.' + if OK: + buttons += [('OK', lambda event: event.GetEventObject().GetParent().EndModal(wx.ID_OK))] + buttons += [('try again', lambda event: event.GetEventObject().GetParent().EndModal(wx.ID_CANCEL))] + res = G2G.ShowScrolledInfo(G2frame,msg1,header='Grouping result', + buttonlist=buttons,height=150) + if res == wx.ID_OK: + repeat = False + + return {'groupDict':groupDict,'notGrouped':noMatchCount,'template':srchStr} + +def UpdateGroup(G2frame,item,plot=True): + def onDisplaySel(event): + G2frame.GroupInfo['displayMode'] = dsplType.GetValue() + wx.CallAfter(UpdateGroup,G2frame,item,False) + + def copyPrep(): + Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')) + groupDict = Controls.get('Groups',{}).get('groupDict',{}) + groupName = G2frame.GroupInfo['groupName'] + # make a list of groups of the same length as the current + curLen = len(groupDict[groupName]) + matchGrps = [] + selList = [] + for g in groupDict: + if g == groupName: continue + if curLen != len(groupDict[g]): continue + matchGrps.append(g) + if len(matchGrps) == 0: + G2G.G2MessageBox(G2frame, + f'No groups found with {curLen} histograms', + 'No matching groups') + return + elif len(matchGrps) > 1: + dlg = G2G.G2MultiChoiceDialog(G2frame, 'Copy to which groups?', 'Copy to?', matchGrps) + try: + if dlg.ShowModal() == wx.ID_OK: + selList = [matchGrps[i] for i in dlg.GetSelections()] + finally: + dlg.Destroy() + else: + selList = matchGrps + if len(selList) == 0: return + return selList,groupDict,groupName + + def OnCopyAll(event): + res = copyPrep() + if res is None: return + selList,groupDict,groupName = res + dataSource = prmArray['_dataSource'] + for h in selList: # selected groups + for src,dst in zip(groupDict[groupName],groupDict[h]): # histograms in groups (same length enforced) + for i in prmArray[src]: + for j in ('ref','val','str'): + if j in prmArray[src][i]: + if prmArray[src][i][j] is None: continue + try: + arr,indx = indexArrayRef(dataSource,dst,prmArray[src][i][j]) + arr[indx] = indexArrayVal(dataSource,src,prmArray[src][i][j]) + except Exception as msg: # could hit an error if an array element is not defined + pass + #print(msg) + #print('error with',i,dst) + def OnCopySel(event): + res = copyPrep() + if res is None: return + selList,groupDict,groupName = res + dataSource = prmArray['_dataSource'] + choices = [] + for src in groupDict[groupName]: + for i in prmArray[src]: + for j in ('ref','val','str'): + if prmArray[src][i].get(j) is None: + continue + if i not in choices: + choices.append(i) + dlg = G2G.G2MultiChoiceDialog(G2frame, 'Copy which items?', 'Copy what?', choices) + itemList = [] + try: + if dlg.ShowModal() == wx.ID_OK: + itemList = [choices[i] for i in dlg.GetSelections()] + finally: + dlg.Destroy() + if len(itemList) == 0: return + for h in selList: # selected groups + for src,dst in zip(groupDict[groupName],groupDict[h]): # histograms in groups (same length enforced) + for i in prmArray[src]: + if i not in itemList: continue + for j in ('ref','val','str'): + if j in prmArray[src][i]: + if prmArray[src][i][j] is None: continue + try: + arr,indx = indexArrayRef(dataSource,dst,prmArray[src][i][j]) + arr[indx] = indexArrayVal(dataSource,src,prmArray[src][i][j]) + except Exception as msg: # could hit an error if an array element is not defined + pass + #print(msg) + #print('error with',i,dst) + + Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree() + if not hasattr(G2frame,'GroupInfo'): + G2frame.GroupInfo = {} + G2frame.GroupInfo['displayMode'] = G2frame.GroupInfo.get('displayMode','Sample') + G2frame.GroupInfo['groupName'] = G2frame.GPXtree.GetItemText(item) + G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.GroupMenu) + G2frame.Bind(wx.EVT_MENU, OnCopyAll, id=G2G.wxID_GRPALL) + G2frame.Bind(wx.EVT_MENU, OnCopySel, id=G2G.wxID_GRPSEL) + + G2frame.dataWindow.ClearData() + G2frame.dataWindow.helpKey = "Groups/Powder" + topSizer = G2frame.dataWindow.topBox + topParent = G2frame.dataWindow.topPanel + dsplType = wx.ComboBox(topParent,wx.ID_ANY, + value=G2frame.GroupInfo['displayMode'], + choices=['Hist/Phase','Sample','Instrument', + 'Instrument-\u0394', + 'Limits','Background'], + style=wx.CB_READONLY|wx.CB_DROPDOWN) + dsplType.Bind(wx.EVT_COMBOBOX, onDisplaySel) + topSizer.Add(dsplType,0,WACV) + topSizer.Add(wx.StaticText(topParent, + label=f' parameters for group "{histLabels(G2frame)[0]}"'), + 0,WACV) + topSizer.Add((-1,-1),1,wx.EXPAND) + topSizer.Add(G2G.HelpButton(topParent,helpIndex=G2frame.dataWindow.helpKey)) + + if G2frame.GroupInfo['displayMode'].startswith('Hist'): + HAPframe(G2frame,Histograms,Phases) + else: + HistFrame(G2frame,Histograms) + if plot: G2pwpl.PlotPatterns(G2frame,plotType='GROUP') + G2frame.dataWindow.SetDataSize() + #wx.CallLater(100,G2frame.SendSizeEvent) + wx.CallAfter(G2frame.SendSizeEvent) + +def histLabels(G2frame): + '''Find portion of the set of hist names that are the same for all + histograms in the current group (determined by ``G2frame.GroupInfo['groupName']``) + and then for each histogram, the characters that are different. + + :Returns: commonltrs, histlbls where + + * commonltrs is a str containing the letters shared by all + histograms in the group and where differing letters are + replaced by a square box. + * histlbls is a list with an str for each histogram listing + the characters that differ in each histogram. + ''' + Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId( + G2frame,G2frame.root, 'Controls')) + groupName = G2frame.GroupInfo['groupName'] + groupDict = Controls.get('Groups',{}).get('groupDict',{}) + l = max([len(i) for i in groupDict[groupName]]) + h0 = groupDict[groupName][0].ljust(l) + msk = [True] * l + for h in groupDict[groupName][1:]: + msk = [m & (h0i == hi) for h0i,hi,m in zip(h0,h.ljust(l),msk)] + # place rectangular box in the loc of non-common letter(s) + commonltrs = ''.join([h0i if m else '\u25A1' for (h0i,m) in zip(h0,msk)]) + # make list with histogram name unique letters + histlbls = [''.join([hi for (hi,m) in zip(h,msk) if not m]) + for h in groupDict[groupName]] + return commonltrs,histlbls + +def indexArrayRef(dataSource,hist,arrayIndices): + indx = arrayIndices[-1] + arr = dataSource[hist] + for i in arrayIndices[:-1]: + arr = arr[i] + return arr,indx + +def indexArrayVal(dataSource,hist,arrayIndices): + if arrayIndices is None: return None + arr = dataSource[hist] + for i in arrayIndices: + arr = arr[i] + return arr + +def onRefineAll(event): + '''Respond to the Refine All button. On the first press, all + refine check buttons are set as "on" and the button is relabeled + as 'C' (for clear). On the second press, all refine check + buttons are set as "off" and the button is relabeled as 'S' (for + set). + ''' + but = event.GetEventObject() + dataSource = but.refDict['dataSource'] + checkButList = but.checkButList + + if but.GetLabelText() == 'S': + setting = True + but.SetLabelText('C') + else: + setting = False + but.SetLabelText('S') + for c in checkButList: + c.SetValue(setting) + for item,hist in zip(but.refDict['arrays'],but.refDict['hists']): + arr,indx = indexArrayRef(dataSource,hist,item) + arr[indx] = setting + +def onSetAll(event): + '''Respond to the copy right button. Copies the first value to + all edit widgets + ''' + but = event.GetEventObject() + dataSource = but.valDict['dataSource'] + valList = but.valDict['arrays'] + histList = but.valDict['hists'] + valEditList = but.valDict['valEditList'] + firstVal = indexArrayVal(dataSource,histList[0],valList[0]) + for c in valEditList: + c.ChangeValue(firstVal) + +def displayDataArray(rowLabels,DataArray,Sizer,Panel,lblRow=False,deltaMode=False, + lblSizer=None,lblPanel=None,CopyCtrl=True): + '''Displays the data table in `DataArray` in Scrolledpanel `Panel` + with wx.FlexGridSizer `Sizer`. + ''' + firstentry = None + #lblRow = True + if lblSizer is None: lblSizer = Sizer + if lblPanel is None: lblPanel = Panel + checkButList = {} + valEditList = {} + lblDict = {} + dataSource = DataArray['_dataSource'] + for row in rowLabels: + checkButList[row] = [] + valEditList[row] = [] + # show the row labels, when not in a separate sizer + if lblRow: + # is a copy across and/or a refine all button needed? + refList = [] + valList = [] + for hist in DataArray: + if row not in DataArray[hist]: continue + if 'val' in DataArray[hist][row]: + valList.append(DataArray[hist][row]['val']) + if 'ref' in DataArray[hist][row]: + refList.append(DataArray[hist][row]['ref']) + + arr = None + histList = [] + for hist in DataArray: + if row not in DataArray[hist]: continue + histList.append(hist) + if 'rowlbl' in DataArray[hist][row]: + arr,key = DataArray[hist][row]['rowlbl'] + break + if arr is None: # text row labels + w = wx.StaticText(lblPanel,label=row) + else: # used for "renameable" sample vars (str) + w = G2G.ValidatedTxtCtrl(lblPanel,arr,key,size=(125,-1)) + lblSizer.Add(w,0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) + lblDict[row] = w + + if len(refList) > 2: + lbl = 'S' + if all([indexArrayVal(dataSource,hist,i) for i in refList]): lbl = 'C' + refAll = wx.Button(lblPanel,label=lbl,style=wx.BU_EXACTFIT) + refAll.refDict = {'arrays': refList, 'hists': histList, + 'dataSource':dataSource} + refAll.checkButList = checkButList[row] + lblSizer.Add(refAll,0,wx.ALIGN_CENTER_VERTICAL) + refAll.Bind(wx.EVT_BUTTON,onRefineAll) + else: + lblSizer.Add((-1,-1)) + + i = -1 + for hist in DataArray: + if hist == '_dataSource': continue + i += 1 + if i == 1 and len(valList) > 2 and not deltaMode and CopyCtrl: + but = wx.Button(Panel,wx.ID_ANY,'\u2192',style=wx.BU_EXACTFIT) + but.valDict = {'arrays': valList, 'hists': histList, + 'dataSource':dataSource, + 'valEditList' :valEditList[row]} + Sizer.Add(but,0,wx.ALIGN_CENTER_VERTICAL) + but.Bind(wx.EVT_BUTTON,onSetAll) + elif i == 1 and CopyCtrl: + Sizer.Add((-1,-1)) + minval = None + maxval = None + # format the entry depending on what is defined + if row not in DataArray[hist]: + Sizer.Add((-1,-1)) + continue + elif 'range' in DataArray[hist][row]: + minval, maxval = DataArray[hist][row]['range'] + if ('init' in DataArray[hist][row] and + deltaMode and 'ref' in DataArray[hist][row]): + arr,indx = indexArrayRef(dataSource,hist,DataArray[hist][row]['val']) + delta = arr[indx] + arr,indx = DataArray[hist][row]['init'] + delta -= arr[indx] + if abs(delta) < 9e-6: delta = 0. + if delta == 0: + deltaS = "" + else: + deltaS = f"\u0394 {delta:.4g} " + valrefsiz = wx.BoxSizer(wx.HORIZONTAL) + valrefsiz.Add(wx.StaticText(Panel,label=deltaS),0) + arr,indx = indexArrayRef(dataSource,hist,DataArray[hist][row]['ref']) + w = G2G.G2CheckBox(Panel,'',arr,indx) + valrefsiz.Add(w,0,wx.ALIGN_CENTER_VERTICAL) + checkButList[row].append(w) + Sizer.Add(valrefsiz,0, + wx.EXPAND|wx.ALIGN_RIGHT) + elif 'init' in DataArray[hist][row] and deltaMode: + # does this ever happen? + arr,indx = indexArrayRef(dataSource,hist,DataArray[hist][row]['val']) + delta = arr[indx] + arr,indx = DataArray[hist][row]['init'] + delta -= arr[indx] + if delta == 0: + deltaS = "" + else: + deltaS = f"\u0394 {delta:.4g} " + Sizer.Add(wx.StaticText(Panel,label=deltaS),0, + wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) + elif 'val' in DataArray[hist][row] and 'ref' in DataArray[hist][row]: + valrefsiz = wx.BoxSizer(wx.HORIZONTAL) + arr,indx = indexArrayRef(dataSource,hist,DataArray[hist][row]['val']) + w = G2G.ValidatedTxtCtrl(Panel,arr,indx,size=(80,-1), + nDig=[9,7,'g'], + xmin=minval,xmax=maxval) + valEditList[row].append(w) + valrefsiz.Add(w,0,WACV) + if firstentry is None: firstentry = w + arr,indx = indexArrayRef(dataSource,hist,DataArray[hist][row]['ref']) + w = G2G.G2CheckBox(Panel,'',arr,indx) + valrefsiz.Add(w,0,wx.ALIGN_CENTER_VERTICAL) + checkButList[row].append(w) + Sizer.Add(valrefsiz,0, + wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) + elif 'val' in DataArray[hist][row]: + arr,indx = indexArrayRef(dataSource,hist,DataArray[hist][row]['val']) + nDig = [9,7,'g'] + if type(arr[indx]) is str: nDig = None + w = G2G.ValidatedTxtCtrl(Panel,arr,indx,size=(80,-1), + nDig=nDig, + xmin=minval,xmax=maxval,notBlank=False) + valEditList[row].append(w) + Sizer.Add(w,0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) + if firstentry is None: firstentry = w + + elif 'ref' in DataArray[hist][row]: + arr,indx = indexArrayRef(dataSource,hist,DataArray[hist][row]['ref']) + w = G2G.G2CheckBox(Panel,'',arr,indx) + Sizer.Add(w,0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER) + checkButList[row].append(w) + elif 'str' in DataArray[hist][row]: + val = indexArrayVal(dataSource,hist,DataArray[hist][row]['str']) + if 'txt' in DataArray[hist][row]: + val = DataArray[hist][row]['txt'] + elif 'fmt' in DataArray[hist][row]: + f = DataArray[hist][row]['fmt'] + val = f'{val:{f}}' + Sizer.Add(wx.StaticText(Panel,label=val),0, + wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER) + else: + print('Should not happen',DataArray[hist][row],hist,row) + return firstentry,lblDict + +def HistFrame(G2frame,Histograms): + '''Put everything in a single FlexGridSizer. + ''' + #--------------------------------------------------------------------- + # generate a dict with values for each histogram + CopyCtrl = True + global prmArray + if G2frame.GroupInfo['displayMode'].startswith('Sample'): + prmArray = getSampleVals(G2frame,Histograms) + elif G2frame.GroupInfo['displayMode'].startswith('Instrument'): + prmArray = getInstVals(G2frame,Histograms) + elif G2frame.GroupInfo['displayMode'].startswith('Limits'): + CopyCtrl = False + prmArray = getLimitVals(G2frame,Histograms) + elif G2frame.GroupInfo['displayMode'].startswith('Background'): + prmArray = getBkgVals(G2frame,Histograms) + CopyCtrl = False + else: + prmArray = None + print('Unexpected', G2frame.GroupInfo['displayMode']) + return + rowLabels = [] + lpos = 0 + nonZeroRows = [] + dataSource = prmArray['_dataSource'] + for hist in prmArray: + if hist == '_dataSource': continue + cols = len(prmArray) + prevkey = None + for key in prmArray[hist]: + # find delta-terms that are non-zero + if '\u0394' in G2frame.GroupInfo['displayMode']: + if 'val' in prmArray[hist][key] and 'init' in prmArray[hist][key]: + arr,indx = prmArray[hist][key]['init'] + val = indexArrayVal(dataSource,hist,prmArray[hist][key]['val']) + if abs(val-arr[indx]) > 1e-5: nonZeroRows.append(key) + if key not in rowLabels: + if prevkey is None: + rowLabels.insert(lpos,key) + lpos += 1 + else: + rowLabels.insert(rowLabels.index(prevkey)+1,key) + prevkey = key + # remove rows where delta-terms are all zeros + if '\u0394' in G2frame.GroupInfo['displayMode']: + rowLabels = [i for i in rowLabels if i in nonZeroRows] + #======= Generate GUI =============================================== + # layout the window + panel = midPanel = G2frame.dataWindow + mainSizer = wx.BoxSizer(wx.VERTICAL) + G2G.HorizontalLine(mainSizer,panel) + panel.SetSizer(mainSizer) + deltaMode = "\u0394" in G2frame.GroupInfo['displayMode'] + n = 2 + if CopyCtrl and len(prmArray) > 2: n += 1 # add column for copy (when more than one histogram) + valSizer = wx.FlexGridSizer(0,len(prmArray)+n-1,3,10) + mainSizer.Add(valSizer,1,wx.EXPAND) + valSizer.Add(wx.StaticText(midPanel,label=' ')) + valSizer.Add(wx.StaticText(midPanel,label=' Ref ')) + for i,hist in enumerate(histLabels(G2frame)[1]): + if i == 1 and CopyCtrl: + if deltaMode: + valSizer.Add((-1,-1)) + elif CopyCtrl: + valSizer.Add(wx.StaticText(midPanel,label=' Copy ')) + valSizer.Add(wx.StaticText(midPanel, + label=f"\u25A1 = {hist}"), + 0,wx.ALIGN_CENTER) + firstentry,lblDict = displayDataArray(rowLabels,prmArray,valSizer,midPanel, + lblRow=True, + deltaMode=deltaMode,CopyCtrl=CopyCtrl) + if firstentry is not None: # prevent scroll to show last entry + wx.Window.SetFocus(firstentry) + firstentry.SetInsertionPoint(0) # prevent selection of text in widget + +def getSampleVals(G2frame,Histograms): + '''Generate the Parameter Data Table (a dict of dicts) with + all Sample values for all histograms in the + selected histogram group (from G2frame.GroupInfo['groupName']). + This will be used to generate the contents of the GUI for Sample values. + ''' + Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')) + groupName = G2frame.GroupInfo['groupName'] + groupDict = Controls.get('Groups',{}).get('groupDict',{}) + if groupName not in groupDict: + print(f'Unexpected: {groupName} not in groupDict') + return + # parameters to include in table + parms = [] + indexDict = {'_dataSource':Histograms} + def histderef(hist,l): + a = Histograms[hist] + for i in l: + a = a[i] + return a + # loop over histograms in group + for hist in groupDict[groupName]: + indexDict[hist] = {} + indexDict[hist]['Inst. name'] = { + 'val' : ('Sample Parameters','InstrName')} + indexDict[hist]['Diff type'] = { + 'str' : ('Sample Parameters','Type')} + indexDict[hist]['Scale factor'] = { + 'val' : ('Sample Parameters','Scale',0), + 'ref' : ('Sample Parameters','Scale',1),} + # make a list of parameters to show + histType = Histograms[hist]['Instrument Parameters'][0]['Type'][0] + dataType = Histograms[hist]['Sample Parameters']['Type'] + if histType[2] in ['A','B','C']: + parms.append(['Gonio. radius','Gonio radius','.3f']) + #if 'PWDR' in histName: + if dataType == 'Debye-Scherrer': + if 'T' in histType: + parms += [['Absorption','Sample abs, \xb5r/\u03bb',None,]] + else: + parms += [['DisplaceX',u'Sample X displ',None,], + ['DisplaceY','Sample Y displ',None,], + ['Absorption','Sample abs,\xb5\xb7r',None,]] + elif dataType == 'Bragg-Brentano': + parms += [['Shift','Sample displ',None,], + ['Transparency','Sample transp',None], + ['SurfRoughA','Surf rough A',None], + ['SurfRoughB','Surf rough B',None]] + #elif 'SASD' in histName: + # parms.append(['Thick','Sample thickness (mm)',[10,3]]) + # parms.append(['Trans','Transmission (meas)',[10,3]]) + # parms.append(['SlitLen',u'Slit length (Q,\xc5'+Pwrm1+')',[10,3]]) + parms.append(['Omega','Gonio omega',None]) + parms.append(['Chi','Gonio chi',None]) + parms.append(['Phi','Gonio phi',None]) + parms.append(['Azimuth','Detect azimuth',None]) + parms.append(['Time','time',None]) + parms.append(['Temperature','Sample T',None]) + parms.append(['Pressure','Sample P',None]) + + # and loop over them + for key,lbl,fmt in parms: + if fmt is None and type(Histograms[hist]['Sample Parameters'][key]) is list: + indexDict[hist][lbl] = { + 'val' : ('Sample Parameters',key,0), + 'ref' : ('Sample Parameters',key,1),} + + elif fmt is None: + indexDict[hist][lbl] = { + 'val' : ('Sample Parameters',key)} + elif type(fmt) is str: + indexDict[hist][lbl] = { + 'str' : ('Sample Parameters',key), + 'fmt' : fmt} + + for key in ('FreePrm1','FreePrm2','FreePrm3'): + lbl = Controls[key] + indexDict[hist][lbl] = { + 'val' : ('Sample Parameters',key), + 'rowlbl' : (Controls,key) + } + return indexDict + +def getInstVals(G2frame,Histograms): + '''Generate the Parameter Data Table (a dict of dicts) with + all Instrument Parameter values for all histograms in the + selected histogram group (from G2frame.GroupInfo['groupName']). + This will be used to generate the contents of the GUI values. + ''' + Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')) + groupName = G2frame.GroupInfo['groupName'] + groupDict = Controls.get('Groups',{}).get('groupDict',{}) + if groupName not in groupDict: + print(f'Unexpected: {groupName} not in groupDict') + return + # parameters to include in table + indexDict = {'_dataSource':Histograms} + # loop over histograms in group + for hist in groupDict[groupName]: + indexDict[hist] = {} + insVal = Histograms[hist]['Instrument Parameters'][0] + insType = insVal['Type'][1] + if 'Bank' in Histograms[hist]['Instrument Parameters'][0]: + indexDict[hist]['Bank'] = { + 'str' : ('Instrument Parameters',0,'Bank',1), + 'fmt' : '.0f' + } + indexDict[hist]['Hist type'] = { + 'str' : ('Instrument Parameters',0,'Type',1), + } + if insType[2] in ['A','B','C']: #constant wavelength + keylist = [('Azimuth','Azimuth','.3f'),] + if 'Lam1' in insVal: + keylist += [('Lam1','Lambda 1','.6f'), + ('Lam2','Lambda 2','.6f'), + (['Source',1],'Source','s'), + ('I(L2)/I(L1)','I(L2)/I(L1)',None)] + else: + keylist += [('Lam','Lambda',None),] + itemList = ['Zero','Polariz.'] + if 'C' in insType: + itemList += ['U','V','W','X','Y','Z','SH/L'] + elif 'B' in insType: + itemList += ['U','V','W','X','Y','Z','alpha-0','alpha-1','beta-0','beta-1'] + else: #'A' + itemList += ['U','V','W','X','Y','Z','alpha-0','alpha-1','beta-0','beta-1','SH/L'] + for lbl in itemList: + keylist += [(lbl,lbl,None),] + elif 'E' in insType: + for lbl in ['XE','YE','ZE','WE']: + keylist += [(lbl,lbl,'.6f'),] + for lbl in ['A','B','C','X','Y','Z']: + keylist += [(lbl,lbl,None),] + elif 'T' in insType: + keylist = [('fltPath','Flight path','.3f'), + ('2-theta','2\u03B8','.2f'),] + for lbl in ['difC','difA','difB','Zero','alpha', + 'beta-0','beta-1','beta-q', + 'sig-0','sig-1','sig-2','sig-q','X','Y','Z']: + keylist += [(lbl,lbl,None),] + else: + return {} + for key,lbl,fmt in keylist: + if fmt is None: + indexDict[hist][lbl] = { + 'init' : (insVal[key],0), + 'val' : ('Instrument Parameters',0,key,1), + 'ref' : ('Instrument Parameters',0,key,2),} + else: + indexDict[hist][lbl] = { + 'str' : ('Instrument Parameters',0,key,1), + 'fmt' : fmt + } + return indexDict + +def getLimitVals(G2frame,Histograms): + '''Generate the Limits Data Table (a dict of dicts) with + all limits values for all histograms in the + selected histogram group (from G2frame.GroupInfo['groupName']). + This will be used to generate the contents of the GUI for limits values. + ''' + Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')) + groupName = G2frame.GroupInfo['groupName'] + groupDict = Controls.get('Groups',{}).get('groupDict',{}) + if groupName not in groupDict: + print(f'Unexpected: {groupName} not in groupDict') + return + # parameters to include in table + indexDict = {'_dataSource':Histograms} + # loop over histograms in group + for hist in groupDict[groupName]: + indexDict[hist] = {} + for lbl,indx in [('Tmin',0),('Tmax',1)]: + indexDict[hist][lbl] = { + 'val' : ('Limits',1,indx), + 'range': [Histograms[hist]['Limits'][0][0], + Histograms[hist]['Limits'][0][1]] + } + for i,item in enumerate(Histograms[hist]['Limits'][2:]): + for l,indx in [('Low',0),('High',1)]: + lbl = f'excl {l} {i+1}' + indexDict[hist][lbl] = { + 'val' : ('Limits',2+i,indx), + 'range': [Histograms[hist]['Limits'][0][0], + Histograms[hist]['Limits'][0][1]]} + return indexDict + +def getBkgVals(G2frame,Histograms): + '''Generate the Background Data Table (a dict of dicts) with + all Background values for all histograms in the + selected histogram group (from G2frame.GroupInfo['groupName']). + This will be used to generate the contents of the GUI for + Background values. + ''' + Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')) + groupName = G2frame.GroupInfo['groupName'] + groupDict = Controls.get('Groups',{}).get('groupDict',{}) + if groupName not in groupDict: + print(f'Unexpected: {groupName} not in groupDict') + return + # parameters to include in table + indexDict = {'_dataSource':Histograms} + # loop over histograms in group + for hist in groupDict[groupName]: + indexDict[hist] = {} + for lbl,indx,typ in [('Function',0,'str'), + ('ref flag',1,'ref'), + ('# Bkg terms',2,'str')]: + indexDict[hist][lbl] = { + typ : ('Background',0,indx) + } + if indx == 2: + indexDict[hist][lbl]['fmt'] = '.0f' + indexDict[hist]['# Debye terms'] = { + 'str' : ('Background',1,'nDebye'), + 'fmt' : '.0f'} + for i,term in enumerate(Histograms[hist]['Background'][1]['debyeTerms']): + for indx,l in enumerate(['A','R','U']): + lbl = f'{l} #{i+1}' + indexDict[hist][lbl] = { + 'val' : ('Background',1,'debyeTerms',i,2*indx), + 'ref' : ('Background',1,'debyeTerms',i,2*indx+1)} + indexDict[hist]['# Bkg Peaks'] = { + 'str' : ('Background',1,'nPeaks'), + 'fmt' : '.0f'} + for i,term in enumerate(Histograms[hist]['Background'][1]['peaksList']): + for indx,l in enumerate(['pos','int','sig','gam']): + lbl = f'{l} #{i+1}' + indexDict[hist][lbl] = { + 'val' : ('Background',1,'peaksList',i,2*indx), + 'ref' : ('Background',1,'peaksList',i,2*indx+1)} + if Histograms[hist]['Background'][1]['background PWDR'][0]: + val = 'yes' + else: + val = 'no' + indexDict[hist]['Fixed bkg file'] = { + 'str' : ('Background',1,'background PWDR',0), + 'txt' : val} + return indexDict + +def HAPframe(G2frame,Histograms,Phases): + '''This creates two side-by-side scrolled panels, each containing + a FlexGridSizer. + The panel to the left contains the labels for the sizer to the right. + This way the labels are not scrolled horizontally and are always seen. + The two vertical scroll bars are linked together so that the labels + are synced to the table of values. + ''' + def selectPhase(event): + 'Display the selected phase' + def OnScroll(event): + 'Synchronize vertical scrolling between the two scrolled windows' + obj = event.GetEventObject() + pos = obj.GetViewStart()[1] + if obj == lblScroll: + HAPScroll.Scroll(-1, pos) + else: + lblScroll.Scroll(-1, pos) + event.Skip() + #--------------------------------------------------------------------- + # selectPhase starts here. Find which phase is selected. + if event: + page = event.GetSelection() + #print('page selected',page,phaseList[page]) + else: # initial call when window is created + page = 0 + #print('no page selected',phaseList[page]) + # generate a dict with HAP values for each phase (may not be the same) + global prmArray + prmArray = getHAPvals(G2frame,phaseList[page],Histograms,Phases) + # construct a list of row labels, attempting to keep the + # order they appear in the original array + rowLabels = [] + lpos = 0 + for hist in prmArray: + if hist == '_dataSource': continue + prevkey = None + for key in prmArray[hist]: + if key not in rowLabels: + if prevkey is None: + rowLabels.insert(lpos,key) + lpos += 1 + else: + rowLabels.insert(rowLabels.index(prevkey)+1,key) + prevkey = key + #======= Generate GUI =============================================== + for panel in HAPtabs: + if panel.GetSizer(): + panel.GetSizer().Destroy() # clear out old widgets + panel = HAPtabs[page] + bigSizer = wx.BoxSizer(wx.HORIZONTAL) + panel.SetSizer(bigSizer) + # panel for labels; show scroll bars to hold the space + lblScroll = wx.lib.scrolledpanel.ScrolledPanel(panel, + style=wx.VSCROLL|wx.HSCROLL|wx.ALWAYS_SHOW_SB) + hpad = 3 # space between rows + lblSizer = wx.FlexGridSizer(0,2,hpad,2) + lblScroll.SetSizer(lblSizer) + bigSizer.Add(lblScroll,0,wx.EXPAND) + + # Create scrolled panel to display HAP data + HAPScroll = wx.lib.scrolledpanel.ScrolledPanel(panel, + style=wx.VSCROLL|wx.HSCROLL|wx.ALWAYS_SHOW_SB) + HAPSizer = wx.FlexGridSizer(0,len(prmArray),hpad,10) + HAPScroll.SetSizer(HAPSizer) + bigSizer.Add(HAPScroll,1,wx.EXPAND) + + # Bind scroll events to synchronize scrolling + lblScroll.Bind(wx.EVT_SCROLLWIN, OnScroll) + HAPScroll.Bind(wx.EVT_SCROLLWIN, OnScroll) + # label columns with unique part of histogram names + for i,hist in enumerate(histLabels(G2frame)[1]): + if i == 1: + HAPSizer.Add(wx.StaticText(HAPScroll,label='Copy'), + 0,wx.ALIGN_CENTER) + HAPSizer.Add(wx.StaticText(HAPScroll,label=f"\u25A1 = {hist}"), + 0,wx.ALIGN_CENTER) + w0 = wx.StaticText(lblScroll,label=' ') + lblSizer.Add(w0) + lblSizer.Add(wx.StaticText(lblScroll,label=' Ref ')) + firstentry,lblDict = displayDataArray(rowLabels,prmArray,HAPSizer,HAPScroll, + lblRow=True,lblSizer=lblSizer,lblPanel=lblScroll) + # get row sizes in data table + HAPSizer.Layout() + rowHeights = HAPSizer.GetRowHeights() + # set row sizes in Labels + # (must be done after HAPSizer row heights are defined) + s = wx.Size(-1,rowHeights[0]) + w0.SetMinSize(s) + for i,row in enumerate(rowLabels): + s = wx.Size(-1,rowHeights[i+1]) + lblDict[row].SetMinSize(s) + # Fit the scrolled windows to their content + lblSizer.Layout() + xLbl,_ = lblSizer.GetMinSize() + xTab,yTab = HAPSizer.GetMinSize() + lblScroll.SetSize((xLbl,yTab)) + lblScroll.SetMinSize((xLbl+15,yTab)) # add room for scroll bar + lblScroll.SetVirtualSize(lblSizer.GetMinSize()) + HAPScroll.SetVirtualSize(HAPSizer.GetMinSize()) + lblScroll.SetupScrolling(scroll_x=True, scroll_y=True, rate_x=20, rate_y=20) + HAPScroll.SetupScrolling(scroll_x=True, scroll_y=True, rate_x=20, rate_y=20) + if firstentry is not None: # prevent scroll to show last entry + wx.Window.SetFocus(firstentry) + firstentry.SetInsertionPoint(0) # prevent selection of text in widget + + #G2frame.dataWindow.ClearData() + + # layout the HAP window. This has histogram and phase info, so a + # notebook is needed for phase name selection. (That could + # be omitted for single-phase refinements, but better to remind the + # user of the phase + # topSizer = G2frame.dataWindow.topBox + # topParent = G2frame.dataWindow.topPanel + midPanel = G2frame.dataWindow + mainSizer = wx.BoxSizer(wx.VERTICAL) + #botSizer = G2frame.dataWindow.bottomBox + #botParent = G2frame.dataWindow.bottomPanel + + G2G.HorizontalLine(mainSizer,midPanel) + midPanel.SetSizer(mainSizer) + if not Phases: + mainSizer.Add(wx.StaticText(midPanel, + label='There are no phases in use')) + G2frame.dataWindow.SetDataSize() + return + # notebook for phases + HAPBook = G2G.GSNoteBook(parent=midPanel) + mainSizer.Add(HAPBook,1,wx.ALL|wx.EXPAND,1) + HAPtabs = [] + phaseList = [] + for phaseName in Phases: + phaseList.append(phaseName) + HAPtabs.append(wx.Panel(HAPBook)) + HAPBook.AddPage(HAPtabs[-1],phaseName) + HAPBook.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, selectPhase) + + page = 0 + HAPBook.SetSelection(page) + selectPhase(None) + #G2frame.dataWindow.SetDataSize() + +def getHAPvals(G2frame,phase,Histograms,Phases): + '''Generate the Parameter Data Table (a dict of dicts) with + all HAP values for the selected phase and all histograms in the + selected histogram group (from G2frame.GroupInfo['groupName']). + This will be used to generate the contents of the GUI for HAP values. + ''' + PhaseData = Phases[phase] + SGData = PhaseData['General']['SGData'] + cell = PhaseData['General']['Cell'][1:] + Amat,Bmat = G2lat.cell2AB(cell[:6]) + Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')) + groupDict = Controls.get('Groups',{}).get('groupDict',{}) + groupName = G2frame.GroupInfo['groupName'] + if groupName not in groupDict: + print(f'Unexpected: {groupName} not in groupDict') + return + indexDict = {'_dataSource':PhaseData['Histograms']} + for hist in groupDict[groupName]: + indexDict[hist] = {} + # phase fraction + indexDict[hist]['Phase frac'] = { + 'val' : ('Scale',0), + 'ref' : ('Scale',1),} + PhaseData['Histograms'][hist]['LeBail'] = PhaseData['Histograms'][hist].get('LeBail',False) + indexDict[hist]['LeBail extract'] = { + 'str' : ('LeBail',), + 'txt' : "Yes" if PhaseData['Histograms'][hist]['LeBail'] else '(off)'} + # size values + if PhaseData['Histograms'][hist]['Size'][0] == 'isotropic': + indexDict[hist]['Size'] = { + 'val' : ('Size',1,0), + 'ref' : ('Size',2,0),} + elif PhaseData['Histograms'][hist]['Size'][0] == 'uniaxial': + indexDict[hist]['Size/Eq'] = { + 'val' : ('Size',1,0), + 'ref' : ('Size',2,0),} + indexDict[hist]['Size/Ax'] = { + 'val' : ('Size',1,1), + 'ref' : ('Size',2,1),} + indexDict[hist]['Size/dir'] = { + 'str' : ('Size',3), + 'txt' : ','.join([str(i) for i in PhaseData['Histograms'][hist]['Size'][3]])} + else: + for i,lbl in enumerate(['S11','S22','S33','S12','S13','S23']): + indexDict[hist][f'Size/{lbl}'] = { + 'val' : ('Size',4,i), + 'ref' : ('Size',5,i),} + indexDict[hist]['Size LGmix'] = { + 'val' : ('Size',1,2), + 'ref' : ('Size',2,2),} + # microstrain values + if PhaseData['Histograms'][hist]['Mustrain'][0] == 'isotropic': + indexDict[hist]['\u00B5Strain'] = { + 'val' : ('Mustrain',1,0), + 'ref' : ('Mustrain',2,0),} + elif PhaseData['Histograms'][hist]['Mustrain'][0] == 'uniaxial': + indexDict[hist]['\u00B5Strain/Eq'] = { + 'val' : ('Mustrain',1,0), + 'ref' : ('Mustrain',2,0),} + indexDict[hist]['\u00B5Strain/Ax'] = { + 'val' : ('Mustrain',1,1), + 'ref' : ('Mustrain',2,1),} + indexDict[hist]['\u00B5Strain/dir'] = { + 'str' : ('Mustrain',3), + 'txt' : ','.join([str(i) for i in PhaseData['Histograms'][hist]['Mustrain'][3]])} + else: + Snames = G2spc.MustrainNames(SGData) + for i,lbl in enumerate(Snames): + if i >= len(PhaseData['Histograms'][hist]['Mustrain'][4]): break + indexDict[hist][f'\u00B5Strain/{lbl}'] = { + 'val' : ('Mustrain',4,i), + 'ref' : ('Mustrain',5,i),} + muMean = G2spc.MuShklMean(SGData,Amat,PhaseData['Histograms'][hist]['Mustrain'][4][:len(Snames)]) + indexDict[hist]['\u00B5Strain/mean'] = { + 'str' : None, + 'txt' : f'{muMean:.2f}'} + indexDict[hist]['\u00B5Strain LGmix'] = { + 'val' : ('Mustrain',1,2), + 'ref' : ('Mustrain',2,2),} + + # Hydrostatic terms + Hsnames = G2spc.HStrainNames(SGData) + for i,lbl in enumerate(Hsnames): + if i >= len(PhaseData['Histograms'][hist]['HStrain'][0]): break + indexDict[hist][f'Size/{lbl}'] = { + 'val' : ('HStrain',0,i), + 'ref' : ('HStrain',1,i),} + + # Preferred orientation terms + if PhaseData['Histograms'][hist]['Pref.Ori.'][0] == 'MD': + indexDict[hist]['March-Dollase'] = { + 'val' : ('Pref.Ori.',1), + 'ref' : ('Pref.Ori.',2),} + indexDict[hist]['M-D/dir'] = { + 'str' : ('Pref.Ori.',3), + 'txt' : ','.join([str(i) for i in PhaseData['Histograms'][hist]['Pref.Ori.'][3]])} + else: + indexDict[hist]['Spherical harmonics'] = { + 'ref' : ('Pref.Ori.',2),} + indexDict[hist]['SH order'] = { + 'str' : ('Pref.Ori.',4), + 'fmt' : '.0f'} + for lbl in PhaseData['Histograms'][hist]['Pref.Ori.'][5]: + indexDict[hist][f'SP {lbl}']= { + 'val' : ('Pref.Ori.',5,lbl), + } + indexDict[hist]['SH txtr indx'] = { + 'str' : None, + 'txt' : f'{G2lat.textureIndex(PhaseData['Histograms'][hist]['Pref.Ori.'][5]):.3f}'} + # misc: Layer Disp, Extinction + if 'Layer Disp' in PhaseData['Histograms'][hist]: + indexDict[hist]['Layer displ'] = { + 'val' : ('Layer Disp',0), + 'ref' : ('Layer Disp',1),} + if 'Extinction' in PhaseData['Histograms'][hist]: + indexDict[hist]['Extinction'] = { + 'val' : ('Extinction',0), + 'ref' : ('Extinction',1),} + if 'Babinet' in PhaseData['Histograms'][hist]: + indexDict[hist]['Babinet A'] = { + 'val' : ('Babinet','BabA',0), + 'ref' : ('Babinet','BabA',1),} + if 'Babinet' in PhaseData['Histograms'][hist]: + indexDict[hist]['Babinet U'] = { + 'val' : ('Babinet','BabU',0), + 'ref' : ('Babinet','BabU',1),} + return indexDict diff --git a/GSASII/GSASIImiscGUI.py b/GSASII/GSASIImiscGUI.py index daac1cf8..7e12fa40 100644 --- a/GSASII/GSASIImiscGUI.py +++ b/GSASII/GSASIImiscGUI.py @@ -8,8 +8,6 @@ ''' -from __future__ import division, print_function - # # Allow this to be imported without wx present. # try: # import wx @@ -554,6 +552,8 @@ def ProjFileOpen(G2frame,showProvenance=True): finally: dlg.Destroy() wx.BeginBusyCursor() + groupDict = {} + groupInserted = False # only need to do this once try: if GSASIIpath.GetConfigValue('show_gpxSize'): posPrev = 0 @@ -575,6 +575,14 @@ def ProjFileOpen(G2frame,showProvenance=True): #if unexpectedObject: # print(datum[0]) # GSASIIpath.IPyBreak() + # insert groups before any individual PDWR items + if datum[0].startswith('PWDR') and groupDict and not groupInserted: + Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text='Groups/Powder') + G2frame.GPXtree.SetItemPyData(Id,{}) + for nam in groupDict: + sub = G2frame.GPXtree.AppendItem(parent=Id,text=nam) + G2frame.GPXtree.SetItemPyData(sub,{}) + groupInserted = True Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=datum[0]) if datum[0] == 'Phases' and GSASIIpath.GetConfigValue('SeparateHistPhaseTreeItem',False): G2frame.GPXtree.AppendItem(parent=G2frame.root,text='Hist/Phase') @@ -582,6 +590,8 @@ def ProjFileOpen(G2frame,showProvenance=True): for pdata in data[1:]: if pdata[0] in Phases: pdata[1].update(Phases[pdata[0]]) + elif datum[0] == 'Controls': + groupDict = datum[1].get('Groups',{}).get('groupDict',{}) elif updateFromSeq and datum[0] == 'Covariance': data[0][1] = CovData elif updateFromSeq and datum[0] == 'Rigid bodies': @@ -720,7 +730,7 @@ def ProjFileSave(G2frame): while item: data = [] name = G2frame.GPXtree.GetItemText(item) - if name.startswith('Hist/Phase'): # skip over this + if name.startswith('Hist/Phase') or name.startswith('Groups'): # skip over this item, cookie = G2frame.GPXtree.GetNextChild(G2frame.root, cookie) continue data.append([name,G2frame.GPXtree.GetItemPyData(item)]) diff --git a/GSASII/GSASIIplot.py b/GSASII/GSASIIplot.py index d6332d88..df93b1c3 100644 --- a/GSASII/GSASIIplot.py +++ b/GSASII/GSASIIplot.py @@ -214,14 +214,14 @@ def __init__(self,parent,id=-1,dpi=None,**kwargs): class G2PlotMpl(_tabPlotWin): 'Creates a Matplotlib 2-D plot in the GSAS-II graphics window' - def __init__(self,parent,id=-1,dpi=None,publish=None,**kwargs): + def __init__(self,parent,id=-1,dpi=None,**kwargs): _tabPlotWin.__init__(self,parent,id=id,**kwargs) mpl.rcParams['legend.fontsize'] = 10 mpl.rcParams['axes.grid'] = False #TODO: set dpi here via config var: this changes the size of the labeling font 72-100 is normal self.figure = mplfig.Figure(dpi=dpi,figsize=(5,6)) self.canvas = Canvas(self,-1,self.figure) - self.toolbar = GSASIItoolbar(self.canvas,publish=publish) + self.toolbar = GSASIItoolbar(self.canvas) self.toolbar.Realize() self.plotStyle = {'qPlot':False,'dPlot':False,'sqrtPlot':False,'sqPlot':False, 'logPlot':False,'exclude':False,'partials':True,'chanPlot':False} @@ -325,6 +325,7 @@ def __init__(self,parent,id=-1,G2frame=None): self.allowZoomReset = True # this indicates plot should be updated not initialized # (BHT: should this be in tabbed panel rather than here?) self.lastRaisedPlotTab = None + self.savedPlotLims = None def OnNotebookKey(self,event): '''Called when a keystroke event gets picked up by the notebook window @@ -395,7 +396,7 @@ def GetTabIndex(self,label): # if plotNum is not None: # wx.CallAfter(self.SetSelectionNoRefresh,plotNum) - def FindPlotTab(self,label,Type,newImage=True,publish=None): + def FindPlotTab(self,label,Type,newImage=True,saveLimits=False): '''Open a plot tab for initial plotting, or raise the tab if it already exists Set a flag (Page.plotInvalid) that it has been redrawn Record the name of the this plot in self.lastRaisedPlotTab @@ -409,9 +410,8 @@ def FindPlotTab(self,label,Type,newImage=True,publish=None): :param bool newImage: forces creation of a new graph for matplotlib plots only (defaults as True) - :param function publish: reference to routine used to create a - publication version of the current mpl plot (default is None, - which prevents use of this). + :param bool saveLimits: When True, limits for all MPL axes (plots) + are saved in self.savedPlotLims. :returns: new,plotNum,Page,Plot,limits where * new: will be True if the tab was just created @@ -420,8 +420,9 @@ def FindPlotTab(self,label,Type,newImage=True,publish=None): the plot appears * Plot: the mpl.Axes object for the graphic (mpl) or the figure for openGL. - * limits: for mpl plots, when a plot already exists, this will be a tuple - with plot scaling. None otherwise. + * limits: for mpl plots, when a plot already exists, this + will be a tuple with plot scaling. None otherwise. Only appropriate + for plots with one set of axes. ''' limits = None Plot = None @@ -429,6 +430,7 @@ def FindPlotTab(self,label,Type,newImage=True,publish=None): new = False plotNum,Page = self.GetTabIndex(label) if Type == 'mpl' or Type == '3d': + if saveLimits: self.savePlotLims(Page) Axes = Page.figure.get_axes() Plot = Page.figure.gca() #get previous plot limits = [Plot.get_xlim(),Plot.get_ylim()] # save previous limits @@ -444,7 +446,7 @@ def FindPlotTab(self,label,Type,newImage=True,publish=None): except (ValueError,AttributeError): new = True if Type == 'mpl': - Plot = self.addMpl(label,publish=publish).gca() + Plot = self.addMpl(label).gca() elif Type == 'ogl': Plot = self.addOgl(label) elif Type == '3d': @@ -469,8 +471,49 @@ def FindPlotTab(self,label,Type,newImage=True,publish=None): Page.helpKey = self.G2frame.dataWindow.helpKey except AttributeError: Page.helpKey = 'HelpIntro' + Page.toolbar.enableArrows() # Disable Arrow keys if present return new,plotNum,Page,Plot,limits + def savePlotLims(self,Page,debug=False): + '''Make a copy of all the current axes in the notebook object + ''' + self.savedPlotLims = [ + [i.get_xlim() for i in Page.figure.get_axes()], + [i.get_ylim() for i in Page.figure.get_axes()]] + if debug: + print(f'saved {len(self.savedPlotLims[1])} axes limits') + #print( self.savedPlotLims) + def restoreSavedPlotLims(self,Page): + '''Restore the plot limits, when previously saved, and when + ``G2frame.restorePlotLimits`` is set to True, which + is done when ``GSASIIpwdplot.refPlotUpdate`` is called with + ``restore=True``, which indicates that "live plotting" is + finished. This is also set for certain plot key-press + combinations. + The restore operation can only be done once, as the limits + are deleted after use in this method. + ''' + if self.savedPlotLims is None: + #print('---- nothing to restore') + return + if not getattr(self.G2frame,'restorePlotLimits',False): + #print('---- restorePlotLimits not set') + return + savedPlotLims = self.savedPlotLims + axesList = Page.figure.get_axes() + if len(axesList) != len(savedPlotLims[0]): + #print('saved lengths differ',len(axesList),len(savedPlotLims[0])) + return + for i,ax in enumerate(axesList): + ax.set_xlim(savedPlotLims[0][i]) + ax.set_ylim(savedPlotLims[1][i]) + #print(i, + # savedPlotLims[0][i][0],savedPlotLims[0][i][1], + # savedPlotLims[1][i][0],savedPlotLims[1][i][1]) + self.savedPlotLims = None + self.G2frame.restorePlotLimits = False + Page.canvas.draw() + def _addPage(self,name,page): '''Add the newly created page to the notebook and associated lists. @@ -493,9 +536,9 @@ def _addPage(self,name,page): #page.replotKWargs = {} #self.skipPageChange = False - def addMpl(self,name="",publish=None): + def addMpl(self,name=""): 'Add a tabbed page with a matplotlib plot' - page = G2PlotMpl(self.nb,publish=publish) + page = G2PlotMpl(self.nb) self._addPage(name,page) return page.figure @@ -606,7 +649,7 @@ def InvokeTreeItem(self,pid): class GSASIItoolbar(Toolbar): 'Override the matplotlib toolbar so we can add more icons' - def __init__(self,plotCanvas,publish=None,Arrows=True): + def __init__(self,plotCanvas,Arrows=True): '''Adds additional icons to toolbar''' self.arrows = {} # try to remove a button from the bar @@ -631,16 +674,25 @@ def __init__(self,plotCanvas,publish=None,Arrows=True): prfx = 'Shift plot ' fil = ''.join([i[0].lower() for i in direc.split()]+['arrow.ico']) self.arrows[direc] = self.AddToolBarTool(sprfx+direc,prfx+direc,fil,self.OnArrow) - if publish: - self.AddToolBarTool('Publish plot','Create publishable version of plot','publish.ico',publish) + self.publishId = self.AddToolBarTool('Publish plot','Create publishable version of plot','publish.ico',self.Publish) + self.publishRoutine = None + self.EnableTool(self.publishId,False) self.Realize() + def setPublish(self,publish=None): + 'Set the routine to be used to publsh the plot' + self.publishRoutine = publish + self.EnableTool(self.publishId,bool(publish)) + def Publish(self,*args,**kwargs): + 'Called to publish the current plot' + if not self.publishRoutine: return + self.publishRoutine(*args,**kwargs) def set_message(self,s): ''' this removes spurious text messages from the tool bar ''' pass -# TODO: perhaps someday we could pull out the bitmaps and rescale there here +# TODO: perhaps someday we could pull out the bitmaps and rescale them here # def AddTool(self,*args,**kwargs): # print('AddTool',args,kwargs) # return Toolbar.AddTool(self,*args,**kwargs) @@ -664,6 +716,27 @@ def _update_view(self): wx.CallAfter(*self.updateActions) Toolbar._update_view(self) + def home(self, *args): + '''Override home button to clear saved GROUP plot limits and trigger replot. + This ensures that pressing home resets to full data range while retaining x-units. + For GROUP plots, we need to replot rather than use matplotlib's home because + matplotlib's home would restore the original shared limits, not per-histogram limits. + (based on MG/Cl Sonnet code) + ''' + G2frame = wx.GetApp().GetMainTopWindow() + # Check if we're in GROUP plot mode - if so, clear saved GROUP + # plot x-limits and trigger a replot + if self.arrows.get('_groupMode'): + # PlotPatterns will use full data range + if hasattr(G2frame, 'groupXlim'): + del G2frame.groupXlim + # Trigger a full replot for GROUP plots + if self.updateActions: + wx.CallAfter(*self.updateActions) + return + # For non-GROUP plots, call the parent's home method + Toolbar.home(self, *args) + def AnyActive(self): for Itool in range(self.GetToolsCount()): if self.GetToolState(self.GetToolByPos(Itool).GetId()): @@ -679,6 +752,22 @@ def GetActive(self): def OnArrow(self,event): 'reposition limits to scan or zoom by button press' + if self.arrows.get('_groupMode'): + Page = self.arrows['_groupMode'] + if event.Id == self.arrows['right']: + Page.groupOff += 1 + elif event.Id == self.arrows['left']: + Page.groupOff -= 1 + elif event.Id == self.arrows['Expand X']: + Page.groupMax += 1 + elif event.Id == self.arrows['Shrink X']: + if Page.groupMax == 2: return + Page.groupMax -= 1 + else: + return + if self.updateActions: + wx.CallLater(100,*self.updateActions) + return axlist = self.plotCanvas.figure.get_axes() if len(axlist) == 1: ax = axlist[0] @@ -736,6 +825,21 @@ def OnArrow(self,event): # self.parent.toolbar.push_current() if self.updateActions: wx.CallAfter(*self.updateActions) + def enableArrows(self,mode='',updateActions=None): + '''Disable/Enable arrow keys. + Disables when updateActions is None. + mode='group' turns on 'x' buttons only + ''' + if not self.arrows: return + self.updateActions = updateActions + if mode == 'group': + # assumes that all arrows previously disabled + for lbl in ('left', 'right', 'Expand X', 'Shrink X'): + self.EnableTool(self.arrows[lbl],True) + else: + for lbl in ('left','right','up','down', 'Expand X', + 'Shrink X','Expand Y','Shrink Y'): + self.EnableTool(self.arrows[lbl],bool(updateActions)) def OnHelp(self,event): 'Respond to press of help button on plot toolbar' diff --git a/GSASII/GSASIIpwdplot.py b/GSASII/GSASIIpwdplot.py index 2b05674d..6d874d29 100644 --- a/GSASII/GSASIIpwdplot.py +++ b/GSASII/GSASIIpwdplot.py @@ -83,6 +83,7 @@ plotOpt['lineWid'] = '1' plotOpt['saveCSV'] = False plotOpt['CSVfile'] = None +plotOpt['sharedX'] = False for xy in 'x','y': for minmax in 'min','max': key = f'{xy}{minmax}' @@ -120,19 +121,6 @@ def ReplotPattern(G2frame,newPlot,plotType,PatternName=None,PickName=None): G2frame.Extinct = [] # array of extinct reflections PlotPatterns(G2frame,plotType=plotType) -def plotVline(Page,Plot,Lines,Parms,pos,color,pickrad,style='dotted'): - '''shortcut to plot vertical lines for limits & Laue satellites. - Was used for extrapeaks''' - if Page.plotStyle['qPlot']: - Lines.append(Plot.axvline(2.*np.pi/G2lat.Pos2dsp(Parms,pos),color=color, - picker=pickrad,linestyle=style)) - elif Page.plotStyle['dPlot']: - Lines.append(Plot.axvline(G2lat.Pos2dsp(Parms,pos),color=color, - picker=pickrad,linestyle=style)) - else: - Lines.append(Plot.axvline(pos,color=color, - picker=pickrad,linestyle=style)) - def PlotPatterns(G2frame,newPlot=False,plotType='PWDR',data=None, extraKeys=[],refineMode=False,indexFrom='',fromTree=False): '''Powder pattern plotting package - displays single or multiple powder @@ -198,17 +186,19 @@ def OnPlotKeyPress(event): try: #one way to check if key stroke will work on plot Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters')) except TypeError: - G2frame.G2plotNB.status.SetStatusText('Select '+plottype+' pattern first',1) + G2frame.G2plotNB.status.SetStatusText(f'Select {plottype} pattern first',1) return + if 'GROUP' in plottype: # save plot limits in case we want to restore them + G2frame.G2plotNB.savePlotLims(Page) newPlot = False - if event.key == 'w': + if event.key == 'w' and not 'GROUP' in plottype: G2frame.Weight = not G2frame.Weight if not G2frame.Weight and not G2frame.Contour and 'PWDR' in plottype: G2frame.SinglePlot = True elif 'PWDR' in plottype: # Turning on Weight plot clears previous limits G2frame.FixedLimits['dylims'] = ['',''] - newPlot = True - elif event.key in ['shift+1','!']: # save current plot settings as defaults + #newPlot = True # this resets the x & y limits, not wanted! + elif event.key in ['shift+1','!'] and not 'GROUP' in plottype: # save current plot settings as defaults # shift+1 assumes US keyboard print('saving plotting defaults for',G2frame.GPXtree.GetItemText(G2frame.PatternId)) data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId) @@ -222,10 +212,17 @@ def OnPlotKeyPress(event): G2frame.ErrorBars = not G2frame.ErrorBars elif event.key == 'T' and 'PWDR' in plottype: Page.plotStyle['title'] = not Page.plotStyle.get('title',True) - elif event.key == 'f' and 'PWDR' in plottype: # short,full length or no tick-marks + elif event.key == 'f' and ('PWDR' in plottype or 'GROUP' in plottype): # short,full length or no tick-marks if G2frame.Contour: return Page.plotStyle['flTicks'] = (Page.plotStyle.get('flTicks',0)+1)%3 - elif event.key == 'x'and 'PWDR' in plottype: + if 'GROUP' in plottype: G2frame.restorePlotLimits = True + elif event.key == 'x' and groupName is not None: # share X axis scale for Pattern Groups + plotOpt['sharedX'] = not plotOpt['sharedX'] + # Clear saved x-limits when toggling sharedX mode (MG/Cl Sonnet) + if hasattr(G2frame, 'groupXlim'): + del G2frame.groupXlim + newPlot = True + elif event.key == 'x' and 'PWDR' in plottype: Page.plotStyle['exclude'] = not Page.plotStyle['exclude'] elif event.key == '.': Page.plotStyle['WgtDiagnostic'] = not Page.plotStyle.get('WgtDiagnostic',False) @@ -310,6 +307,7 @@ def OnPlotKeyPress(event): elif Page.plotStyle['Offset'][0] > -100.: Page.plotStyle['Offset'][0] -= 10. elif event.key == 'g': + if 'GROUP' in plottype: G2frame.restorePlotLimits = True mpl.rcParams['axes.grid'] = not mpl.rcParams['axes.grid'] elif event.key == 'l' and not G2frame.SinglePlot: Page.plotStyle['Offset'][1] -= 1. @@ -335,8 +333,8 @@ def OnPlotKeyPress(event): G2frame.Cmin = 0.0 Page.plotStyle['Offset'] = [0,0] elif event.key == 'C' and 'PWDR' in plottype and G2frame.Contour: - #G2G.makeContourSliders(G2frame,Ymax,PlotPatterns,newPlot,plotType) - G2G.makeContourSliders(G2frame,Ymax,PlotPatterns,True,plotType) # force newPlot=True, prevents blank plot on Mac + #G2G.makeContourSliders(G2frame,Ymax,PlotPatterns,newPlot,plottype) + G2G.makeContourSliders(G2frame,Ymax,PlotPatterns,True,plottype) # force newPlot=True, prevents blank plot on Mac elif event.key == 'c' and 'PWDR' in plottype: newPlot = True if not G2frame.Contour: @@ -350,8 +348,11 @@ def OnPlotKeyPress(event): Page.plotStyle['partials'] = not Page.plotStyle['partials'] elif (event.key == 'e' and 'PWDR' in plottype and G2frame.SinglePlot and ifLimits and not G2frame.Contour): + # set limits in response to the'e' key. First press sets one side + # in Page.startExclReg. Second 'e' press defines other side and + # causes region to be saved (after d/Q conversion if needed) Page.excludeMode = not Page.excludeMode - if Page.excludeMode: + if Page.excludeMode: # first key press try: # fails from key menu Page.startExclReg = event.xdata except AttributeError: @@ -367,17 +368,24 @@ def OnPlotKeyPress(event): y1, y2= Page.figure.axes[0].get_ylim() Page.vLine = Plot.axvline(Page.startExclReg,color='b',dashes=(2,3)) Page.canvas.draw() - else: + else: # second key press Page.savedplot = None - wx.CallAfter(PlotPatterns,G2frame,newPlot=False, - plotType=plottype,extraKeys=extraKeys) - if abs(Page.startExclReg - event.xdata) < 0.1: return LimitId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits') limdat = G2frame.GPXtree.GetItemPyData(LimitId) mn = min(Page.startExclReg, event.xdata) mx = max(Page.startExclReg, event.xdata) + if Page.plotStyle['qPlot']: + mn = G2lat.Dsp2pos(Parms,2.0*np.pi/mn) + mx = G2lat.Dsp2pos(Parms,2.0*np.pi/mx) + elif Page.plotStyle['dPlot']: + mn = G2lat.Dsp2pos(Parms,mn) + mx = G2lat.Dsp2pos(Parms,mx) + if mx < mn: mx,mn = mn,mx + #if abs(mx - mn) < 0.1: return # very small regions are ignored limdat.append([mn,mx]) G2pdG.UpdateLimitsGrid(G2frame,limdat,plottype) + wx.CallAfter(PlotPatterns,G2frame,newPlot=False, + plotType=plottype,extraKeys=extraKeys) return elif event.key == 'a' and 'PWDR' in plottype and G2frame.SinglePlot and not ( Page.plotStyle['logPlot'] or Page.plotStyle['sqrtPlot'] or G2frame.Contour): @@ -401,10 +409,17 @@ def OnPlotKeyPress(event): Pattern[0]['Magnification'] += [[xpos,2.]] wx.CallAfter(G2gd.UpdatePWHKPlot,G2frame,plottype,G2frame.PatternId) return - elif event.key == 'q' and not ifLimits: + elif event.key == 'q': newPlot = True - if 'PWDR' in plottype: + if 'PWDR' in plottype or plottype.startswith('GROUP'): Page.plotStyle['qPlot'] = not Page.plotStyle['qPlot'] + # switching from d to Q + if (Page.plotStyle['qPlot'] and + Page.plotStyle['dPlot'] and + getattr(G2frame, 'groupXlim', None) is not None): + G2frame.groupXlim = ( + 2.0 * np.pi / G2frame.groupXlim[1], # Q_max -> d_min + 2.0 * np.pi / G2frame.groupXlim[0]) # Q_min -> d_max Page.plotStyle['dPlot'] = False Page.plotStyle['chanPlot'] = False elif plottype in ['SASD','REFD']: @@ -417,9 +432,16 @@ def OnPlotKeyPress(event): elif event.key == 'e' and G2frame.Contour: newPlot = True G2frame.TforYaxis = not G2frame.TforYaxis - elif event.key == 't' and 'PWDR' in plottype and not ifLimits: - newPlot = True + elif event.key == 't' and ('PWDR' in plottype or plottype.startswith('GROUP')): + newPlot = True Page.plotStyle['dPlot'] = not Page.plotStyle['dPlot'] + # switching from Q to d + if (Page.plotStyle['qPlot'] and + Page.plotStyle['dPlot'] and + getattr(G2frame, 'groupXlim', None) is not None): + G2frame.groupXlim = ( + 2.0 * np.pi / G2frame.groupXlim[1], # Q_min <- d_max + 2.0 * np.pi / G2frame.groupXlim[0]) # Q_max <- d_min Page.plotStyle['qPlot'] = False Page.plotStyle['chanPlot'] = False elif event.key == 'm': @@ -429,7 +451,7 @@ def OnPlotKeyPress(event): G2frame.Contour = False newPlot = True elif event.key == 'F' and not G2frame.SinglePlot: - choices = G2gd.GetGPXtreeDataNames(G2frame,plotType) + choices = G2gd.GetGPXtreeDataNames(G2frame,plottype) dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select dataset(s) to plot\n(select all or none to reset)', 'Multidata plot selection',choices) @@ -486,7 +508,7 @@ def OnMotion(event): global PlotList G2plt.SetCursor(Page) # excluded region animation - if Page.excludeMode and Page.savedplot: + if Page.excludeMode and Page.savedplot: # defining an excluded region if event.xdata is None or G2frame.GPXtree.GetItemText( G2frame.GPXtree.GetSelection()) != 'Limits': # reset if out of bounds or not on limits Page.savedplot = None @@ -494,7 +516,7 @@ def OnMotion(event): wx.CallAfter(PlotPatterns,G2frame,newPlot=False, plotType=plottype,extraKeys=extraKeys) return - else: + else: # mouse is out of plot region, give up on this region Page.canvas.restore_region(Page.savedplot) Page.vLine.set_xdata([event.xdata,event.xdata]) if G2frame.Weight: @@ -502,7 +524,7 @@ def OnMotion(event): else: axis = Page.figure.gca() axis.draw_artist(Page.vLine) - Page.canvas.blit(axis.bbox) + Page.canvas.blit(Page.figure.bbox) return elif Page.excludeMode or Page.savedplot: # reset if out of mode somehow Page.savedplot = None @@ -642,7 +664,7 @@ def OnMotion(event): Page.SetToolTipString(s) except TypeError: - G2frame.G2plotNB.status.SetStatusText('Select '+plottype+' pattern first',1) + G2frame.G2plotNB.status.SetStatusText(f'Select {plottype} pattern first',1) def OnPress(event): #ugh - this removes a matplotlib error for mouse clicks in log plots np.seterr(invalid='ignore') @@ -702,9 +724,15 @@ def OnPickPwd(event): to create a peak or an excluded region ''' def OnDragMarker(event): - '''Respond to dragging of a plot Marker + '''Respond to dragging of a plot Marker (fixed background point) ''' - if event.xdata is None or event.ydata is None: return # ignore if cursor out of window + if event.xdata is None or event.ydata is None: # mouse is out of plot area, reset drag + G2frame.itemPicked = None + if G2frame.cid is not None: # delete drag connection + Page.canvas.mpl_disconnect(G2frame.cid) + G2frame.cid = None + wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys) + return if G2frame.itemPicked is None: return # not sure why this happens, if it does Page.canvas.restore_region(savedplot) G2frame.itemPicked.set_data([event.xdata], [event.ydata]) @@ -713,28 +741,40 @@ def OnDragMarker(event): else: axis = Page.figure.gca() axis.draw_artist(G2frame.itemPicked) - Page.canvas.blit(axis.bbox) + Page.canvas.blit(Page.figure.bbox) def OnDragLine(event): '''Respond to dragging of a plot line ''' - if event.xdata is None: return # ignore if cursor out of window + if event.xdata is None: # mouse is out of plot area, reset drag + G2frame.itemPicked = None + if G2frame.cid is not None: # delete drag connection + Page.canvas.mpl_disconnect(G2frame.cid) + G2frame.cid = None + wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys) + return if G2frame.itemPicked is None: return # not sure why this happens Page.canvas.restore_region(savedplot) coords = G2frame.itemPicked.get_data() coords[0][0] = coords[0][1] = event.xdata - coords = G2frame.itemPicked.set_data(coords) + G2frame.itemPicked.set_data(coords) if G2frame.Weight: axis = Page.figure.axes[1] else: axis = Page.figure.gca() axis.draw_artist(G2frame.itemPicked) - Page.canvas.blit(axis.bbox) + Page.canvas.blit(Page.figure.bbox) def OnDragLabel(event): '''Respond to dragging of a HKL label ''' - if event.xdata is None: return # ignore if cursor out of window + if event.ydata is None: # mouse is out of plot area, reset drag + G2frame.itemPicked = None + if G2frame.cid is not None: # delete drag connection + Page.canvas.mpl_disconnect(G2frame.cid) + G2frame.cid = None + wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys) + return if G2frame.itemPicked is None: return # not sure why this happens try: coords = list(G2frame.itemPicked.get_position()) @@ -753,14 +793,20 @@ def OnDragLabel(event): else: axis = Page.figure.gca() axis.draw_artist(G2frame.itemPicked) - Page.canvas.blit(axis.bbox) + Page.canvas.blit(Page.figure.bbox) except: pass def OnDragTickmarks(event): '''Respond to dragging of the reflection tick marks ''' - if event.ydata is None: return # ignore if cursor out of window + if event.ydata is None: # mouse is out of plot area, reset drag + G2frame.itemPicked = None + if G2frame.cid is not None: # delete drag connection + Page.canvas.mpl_disconnect(G2frame.cid) + G2frame.cid = None + wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys) + return if Page.tickDict is None: return # not sure why this happens, if it does Page.canvas.restore_region(savedplot) if Page.pickTicknum: @@ -779,12 +825,19 @@ def OnDragTickmarks(event): coords[1][:] = pos Page.tickDict[phase].set_data(coords) axis.draw_artist(Page.tickDict[phase]) - Page.canvas.blit(axis.bbox) + Page.canvas.blit(Page.figure.bbox) def OnDragDiffCurve(event): '''Respond to dragging of the difference curve. ''' - if event.ydata is None: return # ignore if cursor out of window + if event.ydata is None: # mouse is out of plot area, reset drag + G2frame.itemPicked = None + if G2frame.cid is not None: # delete drag connection + Page.canvas.mpl_disconnect(G2frame.cid) + G2frame.cid = None + wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys) + return + return # ignore if cursor out of window if G2frame.itemPicked is None: return # not sure why this happens Page.canvas.restore_region(savedplot) coords = G2frame.itemPicked.get_data() @@ -792,8 +845,8 @@ def OnDragDiffCurve(event): Page.diffOffset = -event.ydata G2frame.itemPicked.set_data(coords) Page.figure.gca().draw_artist(G2frame.itemPicked) # Diff curve only found in 1-window plot - Page.canvas.blit(Page.figure.gca().bbox) - + Page.canvas.blit(Page.figure.bbox) + def DeleteHKLlabel(HKLmarkers,key): '''Delete an HKL label''' del HKLmarkers[key[0]][key[1]] @@ -938,20 +991,24 @@ def DeleteHKLlabel(HKLmarkers,key): if ind.all() != [0]: #picked a data point LimitId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits') limData = G2frame.GPXtree.GetItemPyData(LimitId) - # Q & d not currently allowed on limits plot - # if Page.plotStyle['qPlot']: #qplot - convert back to 2-theta - # xy[0] = G2lat.Dsp2pos(Parms,2*np.pi/xy[0]) - # elif Page.plotStyle['dPlot']: #dplot - convert back to 2-theta - # xy[0] = G2lat.Dsp2pos(Parms,xy[0]) + # reverse setting limits for Q plot & TOF + if Page.plotStyle['qPlot'] and 'T' in Parms['Type'][0]: + if G2frame.ifSetLimitsMode == 2: + G2frame.ifSetLimitsMode = 1 + elif G2frame.ifSetLimitsMode == 1: + G2frame.ifSetLimitsMode = 2 + # set limit selected limit or excluded region after menu command if G2frame.ifSetLimitsMode == 3: # add an excluded region excl = [0,0] excl[0] = max(limData[1][0],min(xy[0],limData[1][1])) excl[1] = excl[0]+0.1 limData.append(excl) - elif G2frame.ifSetLimitsMode == 2: # set upper - limData[1][1] = max(xy[0],limData[1][0]) + elif G2frame.ifSetLimitsMode == 2: + limData[1][1] = min(limData[0][1],max(xy[0],limData[0][0])) # upper elif G2frame.ifSetLimitsMode == 1: - limData[1][0] = min(xy[0],limData[1][1]) # set lower + limData[1][0] = max(limData[0][0],min(xy[0],limData[0][1])) # lower + if limData[1][0] > limData[1][1]: + limData[1][0],limData[1][1] = limData[1][1],limData[1][0] G2frame.ifSetLimitsMode = 0 G2frame.CancelSetLimitsMode.Enable(False) G2frame.GPXtree.SetItemPyData(LimitId,limData) @@ -1087,6 +1144,7 @@ def DeleteHKLlabel(HKLmarkers,key): Page.pickTicknum = Page.phaseList.index(pick) resetlist = [] for pId,phase in enumerate(Page.phaseList): # set the tickmarks to a lighter color + if phase not in Page.tickDict: return col = Page.tickDict[phase].get_color() rgb = mpcls.ColorConverter().to_rgb(col) rgb_light = [(2 + i)/3. for i in rgb] @@ -1433,12 +1491,19 @@ def onPlotFormat(event): def refPlotUpdate(Histograms,cycle=None,restore=False): '''called to update an existing plot during a Rietveld fit; it only updates the curves, not the reflection marks or the legend. - It should be called with restore=True to reset plotting - parameters after the refinement is done. + After the refinement is complete it is called with restore=True to + reset plotting parameters. + + Note that the ``Page.plotStyle`` values are stashed in + ``G2frame.savedPlotStyle`` to be restored after FindPlotTab is + called and ``G2frame.restorePlotLimits`` is set so that + saved plot limits will be applied when + ``G2frame.G2plotNB.restoreSavedPlotLims`` is called. ''' if restore: (G2frame.SinglePlot,G2frame.Contour,G2frame.Weight, - G2frame.plusPlot,G2frame.SubBack,Page.plotStyle['logPlot']) = savedSettings + G2frame.plusPlot,G2frame.SubBack,G2frame.savedPlotStyle) = savedSettings + G2frame.restorePlotLimits = True return if plottingItem not in Histograms: @@ -1600,7 +1665,138 @@ def onPartialConfig(event): Page.plotStyle['partials'] = True Replot() configPartialDisplay(G2frame,Page.phaseColors,Replot) - + def adjustDim(i,nx): + '''MPL creates a 1-D array when nx=1, 2-D otherwise. + This adjusts the array addressing. + ''' + if nx == 1: + return (0,1) + else: + return ((0,i),(1,i)) + def drawTicks(Phases,phaseList,group=False): + 'Draw the tickmarcks for phases in the current histogram' + l = GSASIIpath.GetConfigValue('Tick_length',8.0) + w = GSASIIpath.GetConfigValue('Tick_width',1.) + for pId,phase in enumerate(phaseList): + if 'list' in str(type(Phases[phase])): + continue + if phase in Page.phaseColors: + plcolor = Page.phaseColors[phase] + else: # how could this happen? + plcolor = 'k' + #continue + peaks = Phases[phase].get('RefList',[]) + if not len(peaks): + continue + if Phases[phase].get('Super',False): + peak = np.array([[peak[5],peak[6]] for peak in peaks]) + else: + peak = np.array([[peak[4],peak[5]] for peak in peaks]) + if group: + pos = (2.5-len(phaseList)*5 + pId*5)**np.ones_like(peak) # tick positions hard-coded + else: + pos = Page.plotStyle['refOffset']-pId*Page.plotStyle['refDelt']*np.ones_like(peak) + if Page.plotStyle['qPlot']: + xtick = 2*np.pi/peak.T[0] + elif Page.plotStyle['dPlot']: + xtick = peak.T[0] + else: + xtick = peak.T[1] + if Page.plotStyle.get('flTicks',0) == 0: # short tick-marks + Page.tickDict[phase],_ = Plot.plot( + xtick,pos,'|',mew=w,ms=l,picker=3., + label=phase,color=plcolor) + # N.B. above creates two Line2D objects, 2nd is ignored. + # Not sure what each does. + elif Page.plotStyle.get('flTicks',0) == 1: # full length tick-marks + # axvline changes plot limits, triggering onGroupXlimChanged + # so turn that off for now. + G2frame.stop_onGroupXlimChanged = True + if len(xtick) > 0: + # create an ~hidden tickmark to create a legend entry + Page.tickDict[phase] = Plot.plot(xtick[0],0,'|',mew=0.5,ms=l, + label=phase,color=plcolor)[0] + for xt in xtick: # a separate line for each reflection position + Plot.axvline(xt,color=plcolor, + picker=3., + label='_FLT_'+phase,lw=0.5) + del G2frame.stop_onGroupXlimChanged + + # Callback used to update y-limits when user zooms interactively (from MG/Cl Sonnet) + def onGroupXlimChanged(ax): + '''Callback to update y-limits for all panels in group plot when x-range changes. + We calculate the global y-range across all panels for the visible x-range, + then explicitly set y-limits on ALL panels. + + This code behaves a bit funny w/r to zoom or pan of one plot in a group + in that the plot that is modified can have its y-axis range changed, + but if the another plot is changed, then the previous plot is given the + same y-range as all the others, so only one y-range can be changed. + Perhaps this is because the zoom/pan is applied after the changes + here are applied. + + To do better, we probably need a mode that unlocks the coupling of + the y-axes ranges. + ''' + if getattr(G2frame,'stop_onGroupXlimChanged',False): + return # disable this routine when needed + xlim = ax.get_xlim() + # Save x-limits for persistence across refinements + if (plotOpt['sharedX'] and + (Page.plotStyle['qPlot'] or Page.plotStyle['dPlot'])): + G2frame.groupXlim = xlim + + # Calculate global y-range across ALL panels for visible x-range + global_ymin = float('inf') + global_ymax = float('-inf') + global_dzmin = float('inf') + global_dzmax = float('-inf') + max_tick_space = 0 + + for i in range(Page.groupN): + xarr = np.array(gX[i]) + xye = gdat[i] + mask = (xarr >= xlim[0]) & (xarr <= xlim[1]) + if np.any(mask): + # Calculate scaled y-values for visible data + scaleY = lambda Y, idx=i: (Y - gYmin[idx]) / (gYmax[idx] - gYmin[idx]) * 100 + visible_obs = scaleY(xye[1][mask]) + visible_calc = scaleY(xye[3][mask]) + visible_bkg = scaleY(xye[4][mask]) + ymin_visible = min(visible_obs.min(), visible_calc.min(), visible_bkg.min()) + ymax_visible = max(visible_obs.max(), visible_calc.max(), visible_bkg.max()) + global_ymin = min(global_ymin, ymin_visible) + global_ymax = max(global_ymax, ymax_visible) + # Track tick space needed + if not Page.plotStyle.get('flTicks', False): + max_tick_space = max(max_tick_space, len(RefTbl[i]) * 5) + else: + max_tick_space = max(max_tick_space, 1) + # Calculate diff y-limits + DZ_visible = (xye[1][mask] - xye[3][mask]) * np.sqrt(xye[2][mask]) + global_dzmin = min(global_dzmin, DZ_visible.min()) + global_dzmax = max(global_dzmax, DZ_visible.max()) + + # Apply global y-limits to ALL panels explicitly + if global_ymax > global_ymin: + yrange = global_ymax - global_ymin + ypad = max(yrange * 0.05, 1.0) + ylim_upper = (global_ymin - ypad - max_tick_space, global_ymax + ypad) + for i in range(Page.groupN): + up, down = adjustDim(i, Page.groupN) + Plots[up].set_ylim(ylim_upper) + Plots[up].autoscale(enable=False, axis='y') + if global_dzmax > global_dzmin: + dzrange = global_dzmax - global_dzmin + dzpad = max(dzrange * 0.05, 0.5) + ylim_lower = (global_dzmin - dzpad, global_dzmax + dzpad) + for i in range(Page.groupN): + up, down = adjustDim(i, Page.groupN) + Plots[down].set_ylim(ylim_lower) + Plots[down].autoscale(enable=False, axis='y') + # Force canvas redraw to apply new limits + Page.canvas.draw_idle() + #### beginning PlotPatterns execution ##################################### global exclLines,Page global DifLine @@ -1619,6 +1815,19 @@ def onPartialConfig(event): for i in 'Obs_color','Calc_color','Diff_color','Bkg_color': pwdrCol[i] = '#' + GSASIIpath.GetConfigValue(i,getDefault=True) + groupName = None + groupDict = {} + if plottype == 'GROUP': + groupName = G2frame.GroupInfo['groupName'] # set in GSASIIgroupGUI.UpdateGroup + Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')) + groupDict = Controls.get('Groups',{}).get('groupDict',{}) + if groupName not in groupDict: + print(f'Unexpected: {groupName} not in groupDict') + return + # set data to first histogram in group + G2frame.PatternId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, groupDict[groupName][0]) + data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId) + if not G2frame.PatternId: return if 'PKS' in plottype: # This is probably not used anymore; PlotPowderLines seems to be called directly @@ -1630,7 +1839,20 @@ def onPartialConfig(event): publish = PublishPlot else: publish = None - new,plotNum,Page,Plot,limits = G2frame.G2plotNB.FindPlotTab('Powder Patterns','mpl',publish=publish) + if G2frame.Contour: publish = None + + new,plotNum,Page,Plot,limits = G2frame.G2plotNB.FindPlotTab( + 'Powder Patterns','mpl',saveLimits=refineMode) + if hasattr(G2frame, 'savedPlotStyle'): + Page.plotStyle.update(G2frame.savedPlotStyle) + del G2frame.savedPlotStyle # do this only once & after Page is defined + Page.toolbar.setPublish(publish) + Page.toolbar.arrows['_groupMode'] = None + # if we are changing histogram types (including group to individual, reset plot) + if not new and hasattr(Page,'prevPlotType'): + if Page.prevPlotType != plottype: new = True + Page.prevPlotType = plottype + if G2frame.ifSetLimitsMode and G2frame.GPXtree.GetItemText(G2frame.GPXtree.GetSelection()) == 'Limits': # note mode if G2frame.ifSetLimitsMode == 1: @@ -1644,7 +1866,7 @@ def onPartialConfig(event): Page.excludeMode = False # True when defining an excluded region Page.savedplot = None #patch - if 'Offset' not in Page.plotStyle and plotType in ['PWDR','SASD','REFD']: #plot offset data + if 'Offset' not in Page.plotStyle and plottype in ['PWDR','SASD','REFD']: #plot offset data Ymax = max(data[1][1]) Page.plotStyle.update({'Offset':[0.0,0.0],'delOffset':float(0.02*Ymax), 'refOffset':float(-0.1*Ymax),'refDelt':float(0.1*Ymax),}) @@ -1656,7 +1878,8 @@ def onPartialConfig(event): G2frame.lastPlotType except: G2frame.lastPlotType = None - if plotType == 'PWDR': + + if plottype == 'PWDR' or plottype == 'GROUP': try: Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame, G2frame.PatternId, 'Instrument Parameters')) @@ -1696,7 +1919,8 @@ def onPartialConfig(event): plottingItem = G2frame.GPXtree.GetItemText(G2frame.PatternId) # save settings to be restored after refinement with repPlotUpdate({},restore=True) savedSettings = (G2frame.SinglePlot,G2frame.Contour,G2frame.Weight, - G2frame.plusPlot,G2frame.SubBack,Page.plotStyle['logPlot']) + G2frame.plusPlot,G2frame.SubBack, + copy.deepcopy(Page.plotStyle)) G2frame.SinglePlot = True G2frame.Contour = False G2frame.Weight = True @@ -1714,7 +1938,7 @@ def onPartialConfig(event): G2frame.PatternId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, plottingItem) data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId) G2frame.GPXtree.SelectItem(G2frame.PatternId) - PlotPatterns(G2frame,True,plotType,None,extraKeys) + PlotPatterns(G2frame,True,plottype,None,extraKeys) #===================================================================================== elif 'PlotDefaults' in data[0] and fromTree: # set style from defaults saved with '!' #print('setting plot style defaults') @@ -1732,17 +1956,21 @@ def onPartialConfig(event): newPlot = True G2frame.Cmin = 0.0 G2frame.Cmax = 1.0 - Page.canvas.mpl_connect('motion_notify_event', OnMotion) - Page.canvas.mpl_connect('pick_event', OnPickPwd) - Page.canvas.mpl_connect('button_release_event', OnRelease) - Page.canvas.mpl_connect('button_press_event',OnPress) - Page.bindings = [] - # redo OnPlotKeyPress binding each time the Plot is updated - # since needs values that may have been changed after 1st call - for b in Page.bindings: + # redo plot binding each time the Plot is updated since values + # may have been changed after 1st call + try: + G2frame.PlotBindings + except: + G2frame.PlotBindings = [] + for b in G2frame.PlotBindings: Page.canvas.mpl_disconnect(b) - Page.bindings = [] - Page.bindings.append(Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)) + G2frame.PlotBindings = [] + for e,r in [('motion_notify_event', OnMotion), + ('pick_event', OnPickPwd), + ('button_release_event', OnRelease), + ('button_press_event',OnPress), + ('key_press_event', OnPlotKeyPress)]: + G2frame.PlotBindings.append(Page.canvas.mpl_connect(e,r)) if not G2frame.PickId: print('No plot, G2frame.PickId,G2frame.PatternId=',G2frame.PickId,G2frame.PatternId) return @@ -1781,7 +2009,8 @@ def onPartialConfig(event): Phases = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId,'Reflection Lists')) Page.phaseList = sorted(Phases.keys()) # define an order for phases (once!) else: - Page.phaseList = Phases = [] + Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree() + Page.phaseList = Phases # assemble a list of validated colors for tickmarks valid_colors = [] invalid_colors = [] @@ -1809,7 +2038,7 @@ def onPartialConfig(event): if G2frame.PickId: kwargs['PickName'] = G2frame.GPXtree.GetItemText(G2frame.PickId) wx.CallAfter(G2frame.G2plotNB.RegisterRedrawRoutine(G2frame.G2plotNB.lastRaisedPlotTab,ReplotPattern, - (G2frame,newPlot,plotType),kwargs)) + (G2frame,newPlot,plottype),kwargs)) except: #skip a C++ error pass # now start plotting @@ -1822,8 +2051,6 @@ def onPartialConfig(event): ifLimits = False if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Limits': ifLimits = True - Page.plotStyle['qPlot'] = False - Page.plotStyle['dPlot'] = False # keys in use for graphics control: # a,b,c,d,e,f,g,i,l,m,n,o,p,q,r,s,t,u,w,x, (unused: j, k, y, z) # also: +,/, C,D,S,U @@ -1839,6 +2066,7 @@ def onPartialConfig(event): 'C: contour plot control window', ) else: +# Page.toolbar.updateActions = (PlotPatterns,G2frame) # command used to refresh after arrow key is pressed if 'PWDR' in plottype: Page.Choice = [' key press', 'a: add magnification region','b: toggle subtract background', @@ -1857,6 +2085,7 @@ def onPartialConfig(event): Page.Choice += [f'L: {addrem} {what} in legend',] if ifLimits: Page.Choice += ['e: create excluded region', + 'q: toggle Q plot','t: toggle d-spacing plot', 's: toggle sqrt plot','w: toggle (Io-Ic)/sig plot', '+: toggle obs line plot'] else: @@ -1895,7 +2124,7 @@ def onPartialConfig(event): for KeyItem in extraKeys: Page.Choice = Page.Choice + [KeyItem[0] + ': '+KeyItem[2],] magLineList = [] # null value indicates no magnification - Page.toolbar.updateActions = None # no update actions + #Page.toolbar.updateActions = None # no update actions, used with the arrow keys G2frame.cid = None Page.keyPress = OnPlotKeyPress # assemble a list of validated colors (not currently needed) @@ -1943,7 +2172,7 @@ def onPartialConfig(event): else: #G2frame.selection Title = os.path.split(G2frame.GSASprojectfile)[1] if G2frame.selections is None: - choices = G2gd.GetGPXtreeDataNames(G2frame,plotType) + choices = G2gd.GetGPXtreeDataNames(G2frame,plottype) else: choices = G2frame.selections PlotList = [] @@ -1999,8 +2228,7 @@ def onPartialConfig(event): if Ymax is None: Ymax = max(xye[1]) Ymax = max(Ymax,max(xye[1])) if Ymax is None: return # nothing to plot - offsetX = Page.plotStyle['Offset'][1] - offsetY = Page.plotStyle['Offset'][0] + offsetY,offsetX = Page.plotStyle.get('Offset',(0,0))[:2] if Page.plotStyle['logPlot']: Title = 'log('+Title+')' elif Page.plotStyle['sqrtPlot']: @@ -2010,9 +2238,9 @@ def onPartialConfig(event): Title = 'Scaling diagnostic for '+Title if G2frame.SubBack: Title += ' - background' - if Page.plotStyle['qPlot'] or plottype in ['SASD','REFD'] and not G2frame.Contour and not ifLimits: + if Page.plotStyle['qPlot'] or plottype in ['SASD','REFD'] and not G2frame.Contour: xLabel = r'$Q, \AA^{-1}$' - elif Page.plotStyle['dPlot'] and 'PWDR' in plottype and not ifLimits: + elif Page.plotStyle['dPlot'] and ('PWDR' in plottype or plottype == 'GROUP'): xLabel = r'$d, \AA$' elif Page.plotStyle['chanPlot'] and G2frame.Contour: xLabel = 'Channel no.' @@ -2023,8 +2251,247 @@ def onPartialConfig(event): xLabel = 'E, keV' else: xLabel = r'$\mathsf{2\theta}$' + if groupName is not None: + # plot a group of histograms + Page.toolbar.arrows['_groupMode'] = Page # set up use of arrow keys +# Page.toolbar.updateActions = (PlotPatterns,G2frame,False,plotType,data +# ) # command used to refresh after arrow key is pressed + Page.toolbar.enableArrows('group',(PlotPatterns,G2frame,False,plotType,data)) - if G2frame.Weight and not G2frame.Contour: + Page.Choice = [' key press', + 'f: toggle full-length ticks', + 'g: toggle grid', + #'s: toggle sqrt plot', # TODO: implement this + 'q: toggle Q plot', + 't: toggle d-spacing plot', + 'x: share x-axes (Q/d only)'] + Plot.set_visible(False) # removes "big" plot + gXmin = {} + gXmax = {} + gYmin = {} + gYmax = {} + gX = {} + gdat = {} + totalrange = 0 + DZmax = 0 + DZmin = 0 + RefTbl = {} + histlbl = {} + # find portion of hist name that is the same and different + l = max([len(i) for i in groupDict[groupName]]) + h0 = groupDict[groupName][0].ljust(l) + msk = [True] * l + for h in groupDict[groupName][1:]: + msk = [m & (h0i == hi) for h0i,hi,m in zip(h0,h.ljust(l),msk)] + if not hasattr(Page,'groupMax'): Page.groupMax = min(10,len(groupDict[groupName])) + if not hasattr(Page,'groupOff'): Page.groupOff = 0 + groupPlotList = groupDict[groupName][Page.groupOff:] + groupPlotList += groupDict[groupName] # pad with more from beginning + groupPlotList = groupPlotList[:Page.groupMax] + Page.groupN = len(groupPlotList) + # place centered-dot in loc of non-common letters + #commonltrs = ''.join([h0i if m else '\u00B7' for (h0i,m) in zip(h0,msk)]) + # place rectangular box in the loc of non-common letter(s) + commonltrs = ''.join([h0i if m else '\u25A1' for (h0i,m) in zip(h0,msk)]) + for i,h in enumerate(groupPlotList): + histlbl[i] = ''.join([hi for (hi,m) in zip(h,msk) if not m]) # unique letters + gPatternId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, h) + gParms,_ = G2frame.GPXtree.GetItemPyData( + G2gd.GetGPXtreeItemId(G2frame,gPatternId, + 'Instrument Parameters')) + LimitId = G2gd.GetGPXtreeItemId(G2frame,gPatternId, 'Limits') + limdat = G2frame.GPXtree.GetItemPyData(LimitId) + gd = G2frame.GPXtree.GetItemPyData(gPatternId) + RefTbl[i] = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,gPatternId,'Reflection Lists')) + # drop data outside limits + mask = (limdat[1][0] <= gd[1][0]) & (gd[1][0] <= limdat[1][1]) + gdat[i] = {} + for j in range(6): + y = gd[1][j][mask] + if Page.plotStyle['sqrtPlot']: + gdat[i][j] = np.where(y>=0.,np.sqrt(y),-np.sqrt(-y)) + else: + gdat[i][j] = y + if Page.plotStyle['qPlot']: + gX[i] = 2.*np.pi/G2lat.Pos2dsp(gParms,gdat[i][0]) + elif Page.plotStyle['dPlot']: + gX[i] = G2lat.Pos2dsp(gParms,gdat[i][0]) + else: + gX[i] = gdat[i][0] + gXmin[i] = min(gX[i]) + gXmax[i] = max(gX[i]) + # Calculate Y range from full data initially (may be updated later for zoom) + gYmax[i] = max(max(gdat[i][1]),max(gdat[i][3])) + gYmin[i] = min(min(gdat[i][1]),min(gdat[i][3])) + # obs-calc/sigma + DZ = (gdat[i][1]-gdat[i][3])*np.sqrt(gdat[i][2]) + DZmin = min(DZmin,DZ.min()) + DZmax = max(DZmax,DZ.max()) + totalrange += gXmax[i]-gXmin[i] + if plotOpt['sharedX'] and ( + Page.plotStyle['qPlot'] or Page.plotStyle['dPlot']): + Page.figure.text(0.94,0.03,'X shared',fontsize=10, + color='g') + GS_kw = {'height_ratios':[4, 1]} + #Plots = Page.figure.subplots(2,Page.groupN,sharey='row',sharex=True, + # gridspec_kw=GS_kw) + # Don't use sharey='row' when sharedX - we'll manage y-limits manually + # This avoids conflicts between sharey and our dynamic y-limit updates + Plots = Page.figure.subplots(2,Page.groupN,sharex=True, + gridspec_kw=GS_kw) + else: + # apportion axes lengths making some plots bigger so that initially units are equal + xfrac = [(gXmax[i]-gXmin[i])/totalrange for i in range(Page.groupN)] + GS_kw = {'height_ratios':[4, 1], 'width_ratios':xfrac,} + Plots = Page.figure.subplots(2,Page.groupN,sharey='row',sharex='col', + gridspec_kw=GS_kw) + Page.figure.subplots_adjust(left=5/100.,bottom=16/150., + right=.99,top=1.-3/200.,hspace=0,wspace=0) + + # Connect callback for all panels when sharedX is enabled + up,down = adjustDim(0,Page.groupN) + if (plotOpt['sharedX'] and + (Page.plotStyle['qPlot'] or Page.plotStyle['dPlot'])): + Plots[up].callbacks.connect('xlim_changed', onGroupXlimChanged) + + # pretty up the tick labels + Plots[up].tick_params(axis='y', direction='inout', left=True, right=True) + Plots[down].tick_params(axis='y', direction='inout', left=True, right=True) + if Page.groupN > 1: + for ax in Plots[:,1:].ravel(): + ax.tick_params(axis='y', direction='in', left=True, right=True) + # remove 1st upper y-label so that it does not overlap with lower box + Plots[up].get_yticklabels()[0].set_visible(False) + Plots[down].set_ylabel(r'$\mathsf{\Delta I/\sigma_I}$',fontsize=12) + if Page.plotStyle['sqrtPlot']: + Plots[up].set_ylabel(r'$\rm\sqrt{Normalized\ intensity}$',fontsize=12) + else: + Plots[up].set_ylabel('Normalized Intensity',fontsize=12) + Page.figure.text(0.001,0.03,commonltrs,fontsize=13,color='g') + Page.figure.supxlabel(xLabel) + for i,h in enumerate(groupPlotList): + up,down = adjustDim(i,Page.groupN) + Plot = Plots[up] + Plot1 = Plots[down] + if Page.plotStyle['qPlot']: + pos = 0.98 + ha = 'right' + else: + pos = 0.02 + ha = 'left' + Plot.text(pos,0.98,histlbl[i], + transform=Plot.transAxes, + verticalalignment='top', + horizontalalignment=ha, + fontsize=14,color='g',fontweight='bold') + xye = gdat[i] + DZ = (xye[1]-xye[3])*np.sqrt(xye[2]) + DifLine = Plot1.plot(gX[i],DZ,pwdrCol['Diff_color']) #,picker=1.,label=incCptn('diff')) #(Io-Ic)/sig(Io) + pP = '+' + lW = 1.5 + scaleY = lambda Y: (Y-gYmin[i])/(gYmax[i]-gYmin[i])*100 + Plot.plot(gX[i],scaleY(xye[1]),marker=pP,color=pwdrCol['Obs_color'],linewidth=lW,# picker=3., + clip_on=Clip_on,label=incCptn('obs')) + Plot.plot(gX[i],scaleY(xye[3]),pwdrCol['Calc_color'],picker=0.,label=incCptn('calc'),linewidth=1.5) + Plot.plot(gX[i],scaleY(xye[4]),pwdrCol['Bkg_color'],picker=0.,label=incCptn('bkg'),linewidth=1.5) #background + drawTicks(RefTbl[i],list(RefTbl[i].keys()),True) + + # Set axis limits AFTER plotting data to prevent autoscaling from overriding them (MG/Cl Sonnet) + # When sharedX is enabled, calculate common x-range encompassing all histograms + if (plotOpt['sharedX'] and + (Page.plotStyle['qPlot'] or Page.plotStyle['dPlot'])): + if getattr(G2frame, 'groupXlim', None) is not None: + commonXlim = getattr(G2frame, 'groupXlim', None) + else: + # Calculate union of all histogram x-ranges + commonXmin = min(gXmin.values()) + commonXmax = max(gXmax.values()) + commonXlim = (commonXmin, commonXmax) + + # First pass: set x-limits and calculate global y-range for visible data + # Since sharey='row', all upper panels share y-limits, all lower panels share y-limits + global_ymin = float('inf') + global_ymax = float('-inf') + global_dzmin = float('inf') + global_dzmax = float('-inf') + max_tick_space = 0 + + for i in range(Page.groupN): + up, down = adjustDim(i, Page.groupN) + if (plotOpt['sharedX'] and + (Page.plotStyle['qPlot'] or Page.plotStyle['dPlot'])): + xlim = commonXlim + Plots[up].set_xlim(xlim) + Plots[down].set_xlim(xlim) + else: + xlim = (gXmin[i], gXmax[i]) + Plots[up].set_xlim(xlim) + Plots[down].set_xlim(xlim) + + # Calculate y-range for this panel's visible data + xarr = np.array(gX[i]) + xye = gdat[i] + mask = (xarr >= xlim[0]) & (xarr <= xlim[1]) + if np.any(mask): + scaleY = lambda Y, idx=i: (Y - gYmin[idx]) / (gYmax[idx] - gYmin[idx]) * 100 + visible_obs = scaleY(xye[1][mask]) + visible_calc = scaleY(xye[3][mask]) + visible_bkg = scaleY(xye[4][mask]) + ymin_visible = min(visible_obs.min(), visible_calc.min(), visible_bkg.min()) + ymax_visible = max(visible_obs.max(), visible_calc.max(), visible_bkg.max()) + global_ymin = min(global_ymin, ymin_visible) + global_ymax = max(global_ymax, ymax_visible) + # Track tick space needed + if not Page.plotStyle.get('flTicks', False): + max_tick_space = max(max_tick_space, len(RefTbl[i]) * 5) + else: + max_tick_space = max(max_tick_space, 1) + # Calculate diff y-limits + DZ_visible = (xye[1][mask] - xye[3][mask]) * np.sqrt(xye[2][mask]) + global_dzmin = min(global_dzmin, DZ_visible.min()) + global_dzmax = max(global_dzmax, DZ_visible.max()) + + # Apply global y-limits to ALL panels explicitly (sharey may not propagate properly) + if global_ymax > global_ymin: + yrange = global_ymax - global_ymin + ypad = max(yrange * 0.05, 1.0) + ylim_upper = (global_ymin - ypad - max_tick_space, global_ymax + ypad) + else: + # Fallback to full range + if not Page.plotStyle.get('flTicks', False): + ylim_upper = (-max_tick_space, 102) + else: + ylim_upper = (-1, 102) + if global_dzmax > global_dzmin: + dzrange = global_dzmax - global_dzmin + dzpad = max(dzrange * 0.05, 0.5) + ylim_lower = (global_dzmin - dzpad, global_dzmax + dzpad) + else: + ylim_lower = (DZmin, DZmax) + + # Set y-limits on ALL panels + for i in range(Page.groupN): + up, down = adjustDim(i, Page.groupN) + Plots[up].set_ylim(ylim_upper) + Plots[down].set_ylim(ylim_lower) + + try: # try used as in PWDR menu not Groups + # Not sure if this does anything + G2frame.dataWindow.moveTickLoc.Enable(False) + G2frame.dataWindow.moveTickSpc.Enable(False) + # G2frame.dataWindow.moveDiffCurve.Enable(True) + except: + pass + # Save the current x-limits for GROUP plots so they can be restored after refinement (MG/Cl Sonnet) + # When sharedX is enabled in Q/d-space, all panels share the same x-range + if (plotOpt['sharedX'] and + (Page.plotStyle['qPlot'] or Page.plotStyle['dPlot'])): + up,down = adjustDim(0,Page.groupN) + G2frame.groupXlim = Plots[up].get_xlim() + wx.CallAfter(G2frame.G2plotNB.restoreSavedPlotLims,Page) # restore limits to previous, if saved & requested + Page.canvas.draw() + return # end of group plot + elif G2frame.Weight and not G2frame.Contour: Plot.set_visible(False) #hide old plot frame, will get replaced below GS_kw = {'height_ratios':[4, 1],} # try: @@ -2033,10 +2500,12 @@ def onPartialConfig(event): # Plot,Plot1 = MPLsubplots(Page.figure, 2, 1, sharex=True, gridspec_kw=GS_kw) Plot1.set_ylabel(r'$\mathsf{\Delta(I)/\sigma(I)}$',fontsize=16) Plot1.set_xlabel(xLabel,fontsize=16) - Page.figure.subplots_adjust(left=16/100.,bottom=16/150., - right=.98,top=1.-16/200.,hspace=0) else: Plot.set_xlabel(xLabel,fontsize=16) + Page.figure.subplots_adjust(left=8/100.,bottom=16/150., + right=.98,top=1.-8/100.,hspace=0,wspace=0) + if not G2frame.Contour: + Page.toolbar.enableArrows('',(PlotPatterns,G2frame)) if G2frame.Weight and G2frame.Contour: Title = r'$\mathsf{\Delta(I)/\sigma(I)}$ for '+Title if 'T' in ParmList[0]['Type'][0] or (Page.plotStyle['Normalize'] and not G2frame.SinglePlot): @@ -2086,9 +2555,9 @@ def onPartialConfig(event): if G2frame.Contour: # detect unequally spaced points in a contour plot for N,Pattern in enumerate(PlotList): xye = np.array(ma.getdata(Pattern[1])) # strips mask = X,Yo,W,Yc,Yb,Yd - if Page.plotStyle['qPlot'] and 'PWDR' in plottype and not ifLimits: + if Page.plotStyle['qPlot'] and 'PWDR' in plottype: X = 2.*np.pi/G2lat.Pos2dsp(Parms,xye[0]) - elif Page.plotStyle['dPlot'] and 'PWDR' in plottype and not ifLimits: + elif Page.plotStyle['dPlot'] and 'PWDR' in plottype: X = G2lat.Pos2dsp(Parms,xye[0]) else: X = copy.deepcopy(xye[0]) @@ -2138,9 +2607,9 @@ def onPartialConfig(event): # convert all X values and then reapply mask if xye0 is a masked array mask = None if hasattr(xye0,'mask'): mask = xye0.mask - if Page.plotStyle['qPlot'] and 'PWDR' in plottype and not ifLimits: + if Page.plotStyle['qPlot'] and 'PWDR' in plottype: X = ma.array(2.*np.pi/G2lat.Pos2dsp(Parms,xye0.data),mask=mask) - elif Page.plotStyle['dPlot'] and 'PWDR' in plottype and not ifLimits: + elif Page.plotStyle['dPlot'] and 'PWDR' in plottype: X = ma.array(G2lat.Pos2dsp(Parms,xye0.data),mask=mask) else: X = copy.deepcopy(xye0) @@ -2200,7 +2669,6 @@ def onPartialConfig(event): lbl = Plot.annotate("x{}".format(ml0), xy=(tcorner, tpos), xycoords="axes fraction", verticalalignment='bottom',horizontalalignment=halign,label='_maglbl') Plot.magLbls.append(lbl) - Page.toolbar.updateActions = (PlotPatterns,G2frame) multArray = ma.getdata(multArray) if 'PWDR' in plottype: YI = copy.copy(xye[1]) #yo @@ -2231,9 +2699,9 @@ def onPartialConfig(event): if ifpicked and not G2frame.Contour: # draw limit & excluded region lines lims = limits[1:] - if Page.plotStyle['qPlot'] and 'PWDR' in plottype and not ifLimits: + if Page.plotStyle['qPlot'] and 'PWDR' in plottype: lims = 2.*np.pi/G2lat.Pos2dsp(Parms,lims) - elif Page.plotStyle['dPlot'] and 'PWDR' in plottype and not ifLimits: + elif Page.plotStyle['dPlot'] and 'PWDR' in plottype: lims = G2lat.Pos2dsp(Parms,lims) # limit lines Lines.append(Plot.axvline(lims[0][0],color='g',dashes=(5,5),picker=3.)) @@ -2438,12 +2906,12 @@ def onPartialConfig(event): else: Plot.plot(X,YB,color=pwdrCol['Obs_color'],marker=pP,linewidth=lW, picker=3.,clip_on=Clip_on,label=incCptn('obs')) - Plot.plot(X,ZB,pwdrCol['Bkg_color'],picker=False,label=incCptn('calc'),linewidth=1.5) + Plot.plot(X,ZB,pwdrCol['Bkg_color'],picker=0.,label=incCptn('calc'),linewidth=1.5) if 'PWDR' in plottype and (G2frame.SinglePlot and G2frame.plusPlot): - BackLine = Plot.plot(X,W/ymax,pwdrCol['Bkg_color'],picker=False,label=incCptn('bkg'),linewidth=1.5) #Ib + BackLine = Plot.plot(X,W/ymax,pwdrCol['Bkg_color'],picker=0.,label=incCptn('bkg'),linewidth=1.5) #Ib if not G2frame.Weight and np.any(Z): DifLine = Plot.plot(X,D/ymax,pwdrCol['Diff_color'],linewidth=1.5, - picker=True,pickradius=1.,label=incCptn('diff')) #Io-Ic + picker=1.,label=incCptn('diff')) #Io-Ic Plot.axhline(0.,color='k',label='_zero') Plot.tick_params(labelsize=14) @@ -2550,7 +3018,7 @@ def onPartialConfig(event): # waterfall mode=3: name in legend? name = Pattern[2] if Pattern[0].get('histTitle'): name = Pattern[0]['histTitle'] - Plot.plot(X,Y/ymax,color=mcolors.cmap(icolor),picker=False,label=incCptn(name)) + Plot.plot(X,Y/ymax,color=mcolors.cmap(icolor),picker=0.,label=incCptn(name)) elif plottype in ['SASD','REFD']: try: Plot.loglog(X,Y,mcolors.cmap(icolor),nonpositive='mask',linewidth=1.5) @@ -2600,7 +3068,7 @@ def onPartialConfig(event): if Page.plotStyle['sqrtPlot']: ypos = np.sqrt(abs(ypos))*np.sign(ypos) artist = Plot.text(xpos,ypos,lbl,fontsize=font,c=color,ha='center', - va='top',bbox=props,picker=True,rotation=angle,label='_'+ph) + va='top',bbox=props,picker=1.,rotation=angle,label='_'+ph) artist.key = (ph,key) #============================================================ if timeDebug: @@ -2672,42 +3140,7 @@ def onPartialConfig(event): or (inXtraPeakMode and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Peak List') ): - l = GSASIIpath.GetConfigValue('Tick_length',8.0) - w = GSASIIpath.GetConfigValue('Tick_width',1.) - for pId,phase in enumerate(Page.phaseList): - if 'list' in str(type(Phases[phase])): - continue - if phase in Page.phaseColors: - plcolor = Page.phaseColors[phase] - else: # how could this happen? - plcolor = 'k' - #continue - peaks = Phases[phase].get('RefList',[]) - if not len(peaks): - continue - if Phases[phase].get('Super',False): - peak = np.array([[peak[5],peak[6]] for peak in peaks]) - else: - peak = np.array([[peak[4],peak[5]] for peak in peaks]) - pos = Page.plotStyle['refOffset']-pId*Page.plotStyle['refDelt']*np.ones_like(peak) - if Page.plotStyle['qPlot']: - xtick = 2*np.pi/peak.T[0] - elif Page.plotStyle['dPlot']: - xtick = peak.T[0] - else: - xtick = peak.T[1] - if Page.plotStyle.get('flTicks',0) == 0: # short tick-marks - Page.tickDict[phase],_ = Plot.plot( - xtick,pos,'|',mew=w,ms=l,picker=3.,label=phase,color=plcolor) - # N.B. above creates two Line2D objects, 2nd is ignored. - # Not sure what each does. - elif Page.plotStyle.get('flTicks',0) == 1: # full length tick-marks - if len(xtick) > 0: - # create an ~hidden tickmark to create a legend entry - Page.tickDict[phase] = Plot.plot(xtick[0],0,'|',mew=0.5,ms=l, - label=phase,color=plcolor)[0] - for xt in xtick: # a separate line for each reflection position - Plot.axvline(xt,color=plcolor,picker=3.,label='_FLT_'+phase,lw=0.5) + drawTicks(Phases,Page.phaseList) handles,legends = Plot.get_legend_handles_labels() if handles: labels = dict(zip(legends,handles)) # remove duplicate phase entries @@ -2871,7 +3304,10 @@ def onPartialConfig(event): G2frame.dataWindow.moveTickSpc.Enable(True) if DifLine[0]: G2frame.dataWindow.moveDiffCurve.Enable(True) - if refineMode: return refPlotUpdate + if refineMode: + return refPlotUpdate + else: + wx.CallLater(100,G2frame.G2plotNB.restoreSavedPlotLims,Page) # restore limits to previous, if saved def PublishRietveldPlot(G2frame,Pattern,Plot,Page,reuse=None): '''Creates a window to show a customizable "Rietveld" plot. Exports that @@ -4388,3 +4824,17 @@ def StyleChange(*args): mainSizer.Fit(dlg) dlg.ShowModal() StyleChange() + +def plotVline(Page,Plot,Lines,Parms,pos,color,pickrad,style='dotted'): + '''shortcut to plot vertical lines for limits & Laue satellites. + Was used for extrapeaks''' + if not pickrad: pickrad = 0.0 + if Page.plotStyle['qPlot']: + Lines.append(Plot.axvline(2.*np.pi/G2lat.Pos2dsp(Parms,pos),color=color, + picker=pickrad,linestyle=style)) + elif Page.plotStyle['dPlot']: + Lines.append(Plot.axvline(G2lat.Pos2dsp(Parms,pos),color=color, + picker=pickrad,linestyle=style)) + else: + Lines.append(Plot.axvline(pos,color=color, + picker=pickrad,linestyle=style)) diff --git a/GSASII/meson.build b/GSASII/meson.build index b9514904..e6c5cb7f 100644 --- a/GSASII/meson.build +++ b/GSASII/meson.build @@ -9,7 +9,6 @@ py.install_sources([ 'GSASIIGUI.py', 'GSASIIElem.py', 'GSASIIElemGUI.py', - # 'GSASIIIO.py', 'GSASIImiscGUI.py', 'GSASIIIntPDFtool.py', 'GSASIIconstrGUI.py', @@ -20,11 +19,11 @@ py.install_sources([ 'GSASIIexprGUI.py', 'GSASIIfiles.py', 'GSASIIfpaGUI.py', + 'GSASIIgroupGUI.py', 'GSASIIimage.py', 'GSASIIimgGUI.py', 'GSASIIindex.py', 'GSASIIlattice.py', - # 'GSASIIlog.py', 'GSASIImapvars.py', 'GSASIImath.py', 'GSASIImpsubs.py', diff --git a/pixi/pixi.lock b/pixi/pixi.lock index 277672e8..8584f3a0 100644 --- a/pixi/pixi.lock +++ b/pixi/pixi.lock @@ -3,6 +3,8 @@ environments: default: channels: - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -231,15 +233,30 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py313h253db18_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1030.6.3-llvm19_1_h67a6458_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_impl_osx-64-1030.6.3-llvm19_1_h3b512aa_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1030.6.3-llvm19_1_h8f0d4bb_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.10.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py313h8715ba9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19-19.1.7-default_hc369343_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19.1.7-default_h1323312_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-19.1.7-default_h1c12a56_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_28.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-19.1.7-he914875_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-19.1.7-h138dee1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compilers-1.11.0-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/contourpy-1.3.3-py313hc551f4f_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/crc32c-2.7.1-py313h6865ccc_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cython-3.1.4-py313ha8e042b_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda @@ -248,9 +265,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.60.1-py313h0f4d31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/fortran-compiler-1.11.0-h9ab62e8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.14.1-h694c41f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran-14.3.0-hcc3c99d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-14.3.0-h94fe04d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-14.3.0-h3223c34_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.12-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.45-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.14.0-nompi_py313h5e6d4bd_101.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.6-nompi_hc8237f9_103.conda @@ -263,10 +285,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-8.37.0-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/isl-0.26-imath32_h2e86a7b_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.9-py313hb91e98b_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.3-h37d8d59_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.17-h72f5680_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-956.6-llvm19_1_hc3792c1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-956.6-llvm19_1_h466f870_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lerc-4.0.0-hcca01a6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.4-ha6bc127_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-37_he492b99_openblas.conda @@ -274,8 +299,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlidec-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlienc-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-37_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_hc369343_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.14.1-h5dec5d8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-21.1.3-h3d58e20_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libcxx-headers-19.1.7-h707e725_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.24-hcc1b750_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda @@ -284,16 +312,19 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype-2.14.1-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype6-2.14.1-h6912278_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h306097a_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-14.3.0-h660b60f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-h336fb69_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-3.1.0-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-37_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-h56e7563_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm20-20.1.8-h56e7563_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.1-hd471939_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.67.0-h3338091_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.30-openmp_h83c2472_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.50-h84aeda2_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsigtool-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.50.4-h39a8b3b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.7.1-haa3b502_0.conda @@ -303,11 +334,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.15.0-h23bb396_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.2-h472b3d1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-h879f4bc_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-hb0207f0_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.10.6-py313h4ad75b8_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/mesalib-25.0.5-hcf854c5_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-1.9.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h9d8efa1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py313h5eff275_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda @@ -350,13 +385,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.16.2-py313h61f8160_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sdkroot_env_osx-64-14.5-hbf94ba6_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.1.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-codesign-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/smmap-5.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spglib-2.6.0-py313h2088a77_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spirv-tools-2025.4-hcb651aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1600.0.11.8-h8d8e812_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hf689a15_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda @@ -380,6 +418,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zarr-3.1.3-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py313hcb05632_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda osx-arm64: @@ -742,6 +781,8 @@ environments: py310: channels: - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -969,14 +1010,29 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py310h79c4529_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1030.6.3-llvm19_1_h67a6458_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_impl_osx-64-1030.6.3-llvm19_1_h3b512aa_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1030.6.3-llvm19_1_h8f0d4bb_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.10.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py310h8970a1e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19-19.1.7-default_hc369343_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19.1.7-default_h1323312_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-19.1.7-default_h1c12a56_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_28.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-19.1.7-he914875_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-19.1.7-h138dee1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compilers-1.11.0-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/contourpy-1.3.2-py310hf166250_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cython-3.1.4-py310h229d7d5_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda @@ -984,9 +1040,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fasteners-0.19-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.60.1-py310hd951482_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/fortran-compiler-1.11.0-h9ab62e8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.14.1-h694c41f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran-14.3.0-hcc3c99d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-14.3.0-h94fe04d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-14.3.0-h3223c34_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.12-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.45-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.14.0-nompi_py310h4c08e8d_101.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.6-nompi_hc8237f9_103.conda @@ -999,10 +1060,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-8.37.0-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/isl-0.26-imath32_h2e86a7b_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.9-py310hfcdb090_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.3-h37d8d59_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.17-h72f5680_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-956.6-llvm19_1_hc3792c1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-956.6-llvm19_1_h466f870_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lerc-4.0.0-hcca01a6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.4-ha6bc127_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-37_he492b99_openblas.conda @@ -1010,8 +1074,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlidec-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlienc-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-37_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_hc369343_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.14.1-h5dec5d8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-21.1.3-h3d58e20_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libcxx-headers-19.1.7-h707e725_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.24-hcc1b750_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda @@ -1020,15 +1087,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype-2.14.1-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype6-2.14.1-h6912278_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h306097a_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-14.3.0-h660b60f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-h336fb69_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-3.1.0-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-37_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-h56e7563_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm20-20.1.8-h56e7563_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.1-hd471939_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.67.0-h3338091_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.30-openmp_h83c2472_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.50-h84aeda2_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsigtool-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.50.4-h39a8b3b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.7.1-haa3b502_0.conda @@ -1038,11 +1108,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.15.0-h23bb396_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.2-h472b3d1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-h879f4bc_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-hb0207f0_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.10.6-py310h2102b89_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/mesalib-25.0.5-hcf854c5_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-1.9.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h9d8efa1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py310h8cf47bc_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda @@ -1084,13 +1158,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.15.2-py310hef62574_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sdkroot_env_osx-64-14.5-hbf94ba6_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.1.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-codesign-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/smmap-5.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spglib-2.6.0-py310h547be3f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spirv-tools-2025.4-hcb651aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1600.0.11.8-h8d8e812_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hf689a15_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda @@ -1113,6 +1190,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/xorg-libxshmfence-1.3.3-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zarr-2.18.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py310h3aa7efa_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda osx-arm64: @@ -1467,6 +1545,8 @@ environments: py311: channels: - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -1697,15 +1777,30 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py311h7b20566_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1030.6.3-llvm19_1_h67a6458_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_impl_osx-64-1030.6.3-llvm19_1_h3b512aa_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1030.6.3-llvm19_1_h8f0d4bb_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.10.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py311h8ebb5ae_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19-19.1.7-default_hc369343_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19.1.7-default_h1323312_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-19.1.7-default_h1c12a56_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_28.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-19.1.7-he914875_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-19.1.7-h138dee1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compilers-1.11.0-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/contourpy-1.3.3-py311hd4d69bb_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/crc32c-2.7.1-py311h179db11_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cython-3.1.4-py311h8726017_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda @@ -1714,9 +1809,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.60.1-py311he13f9b5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/fortran-compiler-1.11.0-h9ab62e8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.14.1-h694c41f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran-14.3.0-hcc3c99d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-14.3.0-h94fe04d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-14.3.0-h3223c34_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.12-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.45-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.14.0-nompi_py311h9f650d9_101.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.6-nompi_hc8237f9_103.conda @@ -1729,10 +1829,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-8.37.0-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/isl-0.26-imath32_h2e86a7b_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.9-py311ha94bed4_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.3-h37d8d59_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.17-h72f5680_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-956.6-llvm19_1_hc3792c1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-956.6-llvm19_1_h466f870_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lerc-4.0.0-hcca01a6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.4-ha6bc127_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-37_he492b99_openblas.conda @@ -1740,8 +1843,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlidec-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlienc-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-37_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_hc369343_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.14.1-h5dec5d8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-21.1.3-h3d58e20_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libcxx-headers-19.1.7-h707e725_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.24-hcc1b750_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda @@ -1750,15 +1856,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype-2.14.1-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype6-2.14.1-h6912278_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h306097a_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-14.3.0-h660b60f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-h336fb69_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-3.1.0-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-37_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-h56e7563_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm20-20.1.8-h56e7563_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.1-hd471939_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.67.0-h3338091_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.30-openmp_h83c2472_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.50-h84aeda2_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsigtool-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.50.4-h39a8b3b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.7.1-haa3b502_0.conda @@ -1768,11 +1877,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.15.0-h23bb396_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.2-h472b3d1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-h879f4bc_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-hb0207f0_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.10.6-py311h48d7e91_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/mesalib-25.0.5-hcf854c5_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-1.9.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h9d8efa1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py311haec20ae_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda @@ -1815,13 +1928,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.16.2-py311h32c7e5c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sdkroot_env_osx-64-14.5-hbf94ba6_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.1.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-codesign-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/smmap-5.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spglib-2.6.0-py311h9dffb50_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spirv-tools-2025.4-hcb651aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1600.0.11.8-h8d8e812_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hf689a15_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda @@ -1846,6 +1962,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zarr-3.1.3-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py311h62e9434_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda osx-arm64: @@ -2208,6 +2325,8 @@ environments: py312: channels: - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -2438,15 +2557,30 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py312h462f358_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1030.6.3-llvm19_1_h67a6458_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_impl_osx-64-1030.6.3-llvm19_1_h3b512aa_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1030.6.3-llvm19_1_h8f0d4bb_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.10.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py312hf9bc6d9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19-19.1.7-default_hc369343_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19.1.7-default_h1323312_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-19.1.7-default_h1c12a56_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_28.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-19.1.7-he914875_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-19.1.7-h138dee1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compilers-1.11.0-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/contourpy-1.3.3-py312hedd4973_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/crc32c-2.7.1-py312h6efa6bc_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cython-3.1.4-py312hfbda96f_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda @@ -2455,9 +2589,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.60.1-py312hacf3034_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/fortran-compiler-1.11.0-h9ab62e8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.14.1-h694c41f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran-14.3.0-hcc3c99d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-14.3.0-h94fe04d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-14.3.0-h3223c34_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.12-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.45-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.14.0-nompi_py312ha1048bf_101.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.6-nompi_hc8237f9_103.conda @@ -2470,10 +2609,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-8.37.0-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/isl-0.26-imath32_h2e86a7b_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.9-py312hef387a8_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.3-h37d8d59_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.17-h72f5680_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-956.6-llvm19_1_hc3792c1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-956.6-llvm19_1_h466f870_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lerc-4.0.0-hcca01a6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.4-ha6bc127_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-37_he492b99_openblas.conda @@ -2481,8 +2623,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlidec-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlienc-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-37_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_hc369343_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.14.1-h5dec5d8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-21.1.3-h3d58e20_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libcxx-headers-19.1.7-h707e725_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.24-hcc1b750_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda @@ -2491,15 +2636,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype-2.14.1-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype6-2.14.1-h6912278_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h306097a_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-14.3.0-h660b60f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-h336fb69_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-3.1.0-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-37_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-h56e7563_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm20-20.1.8-h56e7563_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.1-hd471939_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.67.0-h3338091_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.30-openmp_h83c2472_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.50-h84aeda2_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsigtool-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.50.4-h39a8b3b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.7.1-haa3b502_0.conda @@ -2509,11 +2657,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.15.0-h23bb396_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.2-h472b3d1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-h879f4bc_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-hb0207f0_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.10.6-py312h7894933_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/mesalib-25.0.5-hcf854c5_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-1.9.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h9d8efa1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py312hd099df3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda @@ -2556,13 +2708,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.16.2-py312he2acf2f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sdkroot_env_osx-64-14.5-hbf94ba6_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.1.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-codesign-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/smmap-5.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spglib-2.6.0-py312hbb39f8f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spirv-tools-2025.4-hcb651aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1600.0.11.8-h8d8e812_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hf689a15_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda @@ -2587,6 +2742,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zarr-3.1.3-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py312h01f6755_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda osx-arm64: @@ -2949,6 +3105,8 @@ environments: py313: channels: - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -3177,15 +3335,30 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py313h253db18_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1030.6.3-llvm19_1_h67a6458_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_impl_osx-64-1030.6.3-llvm19_1_h3b512aa_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1030.6.3-llvm19_1_h8f0d4bb_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.10.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py313h8715ba9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19-19.1.7-default_hc369343_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19.1.7-default_h1323312_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-19.1.7-default_h1c12a56_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_28.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_28.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-19.1.7-he914875_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-19.1.7-h138dee1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compilers-1.11.0-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/contourpy-1.3.3-py313hc551f4f_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/crc32c-2.7.1-py313h6865ccc_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cython-3.1.4-py313ha8e042b_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda @@ -3194,9 +3367,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.60.1-py313h0f4d31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/fortran-compiler-1.11.0-h9ab62e8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.14.1-h694c41f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran-14.3.0-hcc3c99d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-14.3.0-h94fe04d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-14.3.0-h3223c34_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.12-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.45-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.14.0-nompi_py313h5e6d4bd_101.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.6-nompi_hc8237f9_103.conda @@ -3209,10 +3387,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-8.37.0-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/isl-0.26-imath32_h2e86a7b_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.9-py313hb91e98b_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.3-h37d8d59_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.17-h72f5680_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-956.6-llvm19_1_hc3792c1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-956.6-llvm19_1_h466f870_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lerc-4.0.0-hcca01a6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.4-ha6bc127_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-37_he492b99_openblas.conda @@ -3220,8 +3401,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlidec-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlienc-1.1.0-h1c43f85_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-37_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_hc369343_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.14.1-h5dec5d8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-21.1.3-h3d58e20_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libcxx-headers-19.1.7-h707e725_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.24-hcc1b750_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda @@ -3230,16 +3414,19 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype-2.14.1-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libfreetype6-2.14.1-h6912278_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h306097a_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-14.3.0-h660b60f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-h336fb69_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-3.1.0-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-37_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-h56e7563_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm20-20.1.8-h56e7563_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.1-hd471939_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.67.0-h3338091_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.30-openmp_h83c2472_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.50-h84aeda2_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsigtool-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.50.4-h39a8b3b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.7.1-haa3b502_0.conda @@ -3249,11 +3436,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.15.0-h23bb396_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.2-h472b3d1_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-h879f4bc_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-hb0207f0_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.10.6-py313h4ad75b8_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/mesalib-25.0.5-hcf854c5_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-1.9.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h9d8efa1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py313h5eff275_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda @@ -3296,13 +3487,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.16.2-py313h61f8160_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sdkroot_env_osx-64-14.5-hbf94ba6_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.1.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-codesign-0.1.3-hc0f2934_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/smmap-5.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spglib-2.6.0-py313h2088a77_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/spirv-tools-2025.4-hcb651aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1600.0.11.8-h8d8e812_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hf689a15_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda @@ -3326,6 +3520,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zarr-3.1.3-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py313hcb05632_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda osx-arm64: @@ -4211,6 +4406,18 @@ packages: license_family: MIT size: 179696 timestamp: 1744128058734 +- conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda + sha256: 2bd1cf3d26789b7e1d04e914ccd169bd618fceed68abf7b6a305266b88dcf861 + md5: 2b23ec416cef348192a5a17737ddee60 + depends: + - cctools >=949.0.1 + - clang_osx-64 19.* + - ld64 >=530 + - llvm-openmp + license: BSD-3-Clause + license_family: BSD + size: 6695 + timestamp: 1753098825695 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.11.0-h61f9b84_0.conda sha256: b51bd1551cfdf41500f732b4bd1e4e70fb1e74557165804a648f32fa9c671eec md5: 148516e0c9edf4e9331a4d53ae806a9b @@ -4291,6 +4498,17 @@ packages: license: LGPL-2.1-only or MPL-1.1 size: 978114 timestamp: 1741554591855 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1030.6.3-llvm19_1_h67a6458_3.conda + sha256: b07dfc5023c9bfa0abb6e77e1bed86a7c6bde6b737addedb85129e808173ff29 + md5: acdbe6dbefafb1eba531160c68328456 + depends: + - cctools_impl_osx-64 1030.6.3 llvm19_1_h3b512aa_3 + - ld64 956.6 llvm19_1_hc3792c1_3 + - libllvm19 >=19.1.7,<19.2.0a0 + license: APSL-2.0 + license_family: Other + size: 24286 + timestamp: 1767114529119 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools-1024.3-hd01ab73_1.conda sha256: 5f155c8ef4e2b1a3a9a0cf9544defb439f94e032147e515464732cc027f842ba md5: 50f17681b331bc28cf1d55df2b2414dd @@ -4302,6 +4520,37 @@ packages: license_family: Other size: 20699 timestamp: 1756645577110 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_impl_osx-64-1030.6.3-llvm19_1_h3b512aa_3.conda + sha256: 60dfb2c7b685aeb867c7b359ae0c7e2147b90cc15b0397040f256d17e62c4d5b + md5: a52bbde5581ef42bdcbf050ca8c83646 + depends: + - __osx >=10.13 + - ld64_osx-64 >=956.6,<956.7.0a0 + - libcxx + - libllvm19 >=19.1.7,<19.2.0a0 + - libzlib >=1.3.1,<2.0a0 + - llvm-tools 19.1.* + - sigtool-codesign + constrains: + - ld64 956.6.* + - cctools 1030.6.3.* + - clang 19.1.* + license: APSL-2.0 + license_family: Other + size: 742929 + timestamp: 1767114490312 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1030.6.3-llvm19_1_h8f0d4bb_3.conda + sha256: 060b807b306f0e3476db009a2b218f419977740d8708975fabceb138d135aec3 + md5: 09ff64ce958395c9dd58c847d709d28d + depends: + - cctools_impl_osx-64 1030.6.3 llvm19_1_h3b512aa_3 + - ld64_osx-64 956.6 llvm19_1_h466f870_3 + constrains: + - cctools 1030.6.3.* + license: APSL-2.0 + license_family: Other + size: 23229 + timestamp: 1767114532748 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools_osx-arm64-1024.3-haeb51d2_1.conda sha256: ea77d8790feb469a1440a330bca1641194b5de21ba8ccdf9c7a05e355e1f153e md5: bdecbcc574c1ae36f164346368404f63 @@ -4554,6 +4803,15 @@ packages: license_family: MIT size: 51033 timestamp: 1754767444665 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19.1.7-default_h1323312_5.conda + sha256: 5bcabcc3a5689bc47dbd6a58a3a785f8fe3f4e91410a299392d9cdf7ae7c16d6 + md5: 5bd21a5ea37ab0fbe1d9cbba4e0e7c80 + depends: + - clang-19 19.1.7 default_hc369343_5 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 24455 + timestamp: 1759436889569 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-19.1.7-default_h474c9e2_3.conda sha256: e2061f7a16ae5a381d7f66b5ccd91a92b7ad6ac356f1d2ee2934015581eb3bf7 md5: b5a92027d9f6136108beeda7b6edfec9 @@ -4563,6 +4821,18 @@ packages: license_family: Apache size: 24360 timestamp: 1747709802932 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19-19.1.7-default_hc369343_5.conda + sha256: 2631c79a027ee8b9c2d4d0a458f0588e8fe03fe1dfb3e3bcd47e7b0f4d0d2175 + md5: b37d33a750251c79214c812eca726241 + depends: + - __osx >=10.13 + - libclang-cpp19.1 19.1.7 default_hc369343_5 + - libcxx >=19.1.7 + - libllvm19 >=19.1.7,<19.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 765727 + timestamp: 1759436729883 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-19-19.1.7-default_hf90f093_3.conda sha256: c7f21028560ee5cc72d882d930b56c8521126987308819c37b97e1760d3e39bc md5: 8ea1b606f2c5cb255b53c868d1eb8dbc @@ -4575,6 +4845,19 @@ packages: license_family: Apache size: 760894 timestamp: 1747709675681 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_28.conda + sha256: a393747ffc868fe4e51b4b20570bab597024e49798568647e66340bc19d1986f + md5: 11b55abbdae1166253b57800d267e748 + depends: + - cctools_impl_osx-64 + - clang 19.1.7.* + - compiler-rt 19.1.7.* + - ld64_osx-64 + - llvm-tools 19.1.7.* + license: BSD-3-Clause + license_family: BSD + size: 17860 + timestamp: 1765841971797 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_impl_osx-arm64-19.1.7-h76e6a08_25.conda sha256: ee3c0976bde0ac19f84d29213ea3d9c3fd9c56d56c33ee471a8680cf69307ce1 md5: a4e2f211f7c3cf582a6cb447bee2cad9 @@ -4588,6 +4871,17 @@ packages: license_family: BSD size: 18159 timestamp: 1748575942374 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_28.conda + sha256: defe8d27247c063b7273b11e6dccbd9b55fb59686dea17e2bd54f138db4b7a32 + md5: 9e78ad15b683ff11b0e18a971ab78a54 + depends: + - cctools_osx-64 + - clang_impl_osx-64 19.1.7 hc73cdc9_28 + - sdkroot_env_osx-64 + license: BSD-3-Clause + license_family: BSD + size: 20764 + timestamp: 1765841975402 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_osx-arm64-19.1.7-h07b0088_25.conda sha256: 92a45a972af5eba3b7fca66880c3d5bdf73d0c69a3e21d1b3999fb9b5be1b323 md5: 1b53cb5305ae53b5aeba20e58c625d96 @@ -4597,6 +4891,16 @@ packages: license_family: BSD size: 21337 timestamp: 1748575949016 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-19.1.7-default_h1c12a56_5.conda + sha256: 6553c7b6a898bd00c218656d3438dc3a70f2bb79f795ce461792c55304558af2 + md5: 6b6f3133d60b448c0f12885f53d5ed09 + depends: + - clang 19.1.7 default_h1323312_5 + - libcxx-devel 19.1.* + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 24505 + timestamp: 1759436910517 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-19.1.7-default_h1ffe849_3.conda sha256: c6094b6c846248930ab2f559b04e14f9d6463e1c88b9d33b479bf27df916d6d7 md5: 8b6dff933df21ccf744b5ecbc9dfd3ab @@ -4607,6 +4911,18 @@ packages: license_family: Apache size: 24486 timestamp: 1747709816351 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_28.conda + sha256: 9b734bc9a1d3a53b7c7bc82d2989d959dfc4212b76516692b4996038be00f850 + md5: 53ea0e8ae9ed508da86574d64ec2be15 + depends: + - clang_osx-64 19.1.7 h7e5c614_28 + - clangxx 19.1.7.* + - libcxx >=19 + - libllvm19 >=19.1.7,<19.2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 17992 + timestamp: 1765842018470 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_impl_osx-arm64-19.1.7-h276745f_25.conda sha256: b997d325da6ca60e71937b9e28f114893401ca7cf94c4007d744e402a25c2c52 md5: 5eeaa7b2dd32f62eb3beb0d6ba1e664f @@ -4619,6 +4935,18 @@ packages: license_family: BSD size: 18297 timestamp: 1748576000726 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_28.conda + sha256: 78aba4e421a40442d157b9141d4bf38513d1e2288300efaa8d7e16558d9b6b3f + md5: 302456b38cee4b4b5c8ccd8498605cb6 + depends: + - cctools_osx-64 + - clang_osx-64 19.1.7 h7e5c614_28 + - clangxx_impl_osx-64 19.1.7 hb295874_28 + - sdkroot_env_osx-64 + license: BSD-3-Clause + license_family: BSD + size: 19573 + timestamp: 1765842022184 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_osx-arm64-19.1.7-h07b0088_25.conda sha256: 93801e6e821ae703d03629b1b993dbae1920b80012818edd5fcd18a9055897ce md5: 4e09188aa8def7d8b3ae149aa856c0e5 @@ -4638,6 +4966,17 @@ packages: license_family: BSD size: 27011 timestamp: 1733218222191 +- conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-19.1.7-he914875_1.conda + sha256: 28e5f0a6293acba68ebc54694a2fc40b1897202735e8e8cbaaa0e975ba7b235b + md5: e6b9e71e5cb08f9ed0185d31d33a074b + depends: + - __osx >=10.13 + - clang 19.1.7.* + - compiler-rt_osx-64 19.1.7.* + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + size: 96722 + timestamp: 1757412473400 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-hd2aecb6_0.conda sha256: db920f02717984329375c0c188335c23104895b0e5a2da295e475dabe4192c69 md5: 28f46d13b77fcc390c84ca49b68b9ecb @@ -4649,6 +4988,18 @@ packages: license_family: APACHE size: 96534 timestamp: 1736976644597 +- conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-19.1.7-h138dee1_1.conda + sha256: e6effe89523fc6143819f7a68372b28bf0c176af5b050fe6cf75b62e9f6c6157 + md5: 32deecb68e11352deaa3235b709ddab2 + depends: + - clang 19.1.7.* + constrains: + - compiler-rt 19.1.7 + - clangxx 19.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + size: 10425780 + timestamp: 1757412396490 - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-h7969c41_0.conda sha256: 6d9701824622609a47aae525d0a527e46dd7bbdc3f5648a3035df177f93d858e md5: bb78d3cc0758bb3fc3cb0fab51ec4424 @@ -4661,6 +5012,17 @@ packages: license_family: APACHE size: 10796006 timestamp: 1736976593839 +- conda: https://conda.anaconda.org/conda-forge/osx-64/compilers-1.11.0-h694c41f_0.conda + sha256: d95722dfe9a45b22fbb4e8d4f9531ac5ef7d829f3bfd2ed399d45d7590681bd0 + md5: 308ed38aeff454285547012272cb59f5 + depends: + - c-compiler 1.11.0 h7a00415_0 + - cxx-compiler 1.11.0 h307afc9_0 + - fortran-compiler 1.11.0 h9ab62e8_0 + license: BSD-3-Clause + license_family: BSD + size: 7509 + timestamp: 1753098827841 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compilers-1.11.0-hce30654_0.conda sha256: 01f02e9baa51ef2debfdc55df57ea6a7fce9b5fb9356c3267afb517e1dc4363a md5: aac0d423ecfd95bde39582d0de9ca657 @@ -5033,6 +5395,16 @@ packages: license: LGPL-2.1-or-later size: 53045 timestamp: 1756602227299 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda + sha256: d6976f8d8b51486072abfe1e76a733688380dcbd1a8e993a43d59b80f7288478 + md5: 463bb03bb27f9edc167fb3be224efe96 + depends: + - c-compiler 1.11.0 h7a00415_0 + - clangxx_osx-64 19.* + license: BSD-3-Clause + license_family: BSD + size: 6732 + timestamp: 1753098827160 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda sha256: 99800d97a3a2ee9920dfc697b6d4c64e46dc7296c78b1b6c746ff1c24dea5e6c md5: 043afed05ca5a0f2c18252ae4378bdee @@ -5635,6 +6007,19 @@ packages: license_family: MIT size: 2490458 timestamp: 1756328983115 +- conda: https://conda.anaconda.org/conda-forge/osx-64/fortran-compiler-1.11.0-h9ab62e8_0.conda + sha256: 21e2ec84b7b152daa22fa8cc98be5d4ba9ff93110bbc99e05dfd45eb6f7e8b77 + md5: ee1a3ecd568a695ea16747198df983eb + depends: + - cctools >=949.0.1 + - gfortran + - gfortran_osx-64 14.* + - ld64 >=530 + - llvm-openmp + license: BSD-3-Clause + license_family: BSD + size: 6749 + timestamp: 1753098826431 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fortran-compiler-1.11.0-h81a4f41_0.conda sha256: 1a030edc0e79e4e7a4ed9736ec6925303940148d00f20faf3a7abf0565de181e md5: d221c62af175b83186f96d8b0880bff6 @@ -5730,6 +6115,17 @@ packages: license_family: LGPL size: 579311 timestamp: 1754960116630 +- conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran-14.3.0-hcc3c99d_0.conda + sha256: e99605f629a4baceba28bfda6305f6898a42a1a05a5833a92808b737457a0711 + md5: 6077316830986f224d771f9e6ba5c516 + depends: + - cctools + - gfortran_osx-64 14.3.0 + - ld64 + license: GPL-3.0-or-later WITH GCC-exception-3.1 + license_family: GPL + size: 32631 + timestamp: 1751220511321 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gfortran-14.3.0-h3ef1dbf_0.conda sha256: cfdf9b4dd37ddfc15ea1c415619d4137004fa135d7192e5cdcea8e3944dc9df7 md5: e148e0bc9bbc90b6325a479a5501786d @@ -5752,6 +6148,27 @@ packages: license_family: BSD size: 756507 timestamp: 1740241113441 +- conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-14.3.0-h94fe04d_1.conda + sha256: 7a2a952ffee0349147768c1d6482cb0933349017056210118ebd5f0fb688f5d5 + md5: 1a81d1a0cb7f241144d9f10e55a66379 + depends: + - __osx >=10.13 + - cctools_osx-64 + - clang + - gmp >=6.3.0,<7.0a0 + - isl 0.26.* + - libcxx >=17 + - libgfortran-devel_osx-64 14.3.0.* + - libgfortran5 >=14.3.0 + - libiconv >=1.18,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - mpc >=1.3.1,<2.0a0 + - mpfr >=4.2.1,<5.0a0 + - zlib + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 23083852 + timestamp: 1759709470800 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gfortran_impl_osx-arm64-14.3.0-h969232b_1.conda sha256: 75b2c2d7718ac3084eea3b9b7a49203437bfa04806229a567d781ab827f199d9 md5: 2eb14ea8bce422d2f481cea83ec71f8d @@ -5786,6 +6203,22 @@ packages: license_family: GPL size: 14926629 timestamp: 1740241036024 +- conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-14.3.0-h3223c34_0.conda + sha256: 14014ad4d46e894645979cbad42dd509482172095c756bdb5474918e0638bd57 + md5: 979b3c36c57d31e1112fa1b1aec28e02 + depends: + - cctools_osx-64 + - clang + - clang_osx-64 + - gfortran_impl_osx-64 14.3.0 + - ld64_osx-64 + - libgfortran + - libgfortran-devel_osx-64 14.3.0 + - libgfortran5 >=14.3.0 + license: GPL-3.0-or-later WITH GCC-exception-3.1 + license_family: GPL + size: 35767 + timestamp: 1751220493617 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gfortran_osx-arm64-14.3.0-h3c33bd0_0.conda sha256: 2644e5f4b4eed171b12afb299e2413be5877db92f30ec03690621d1ae648502c md5: 8db8c0061c0f3701444b7b9cc9966511 @@ -5845,6 +6278,15 @@ packages: license: LGPL-2.1-or-later size: 116716 timestamp: 1754315054614 +- conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda + sha256: 75aa5e7a875afdcf4903b7dc98577672a3dc17b528ac217b915f9528f93c85fc + md5: 427101d13f19c4974552a4e5b072eef1 + depends: + - __osx >=10.13 + - libcxx >=16 + license: GPL-2.0-or-later OR LGPL-3.0-or-later + size: 428919 + timestamp: 1718981041839 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gmp-6.3.0-h7bae524_2.conda sha256: 76e222e072d61c840f64a44e0580c2503562b009090f55aa45053bf1ccb385dd md5: eed7278dfbab727b56f2c0b64330814b @@ -6428,6 +6870,17 @@ packages: license_family: BSD size: 638940 timestamp: 1748711254071 +- conda: https://conda.anaconda.org/conda-forge/osx-64/isl-0.26-imath32_h2e86a7b_101.conda + sha256: d39bf147cb9958f197dafa0b8ad8c039b7374778edac05b5c78b712786e305c7 + md5: d06222822a9144918333346f145b68c6 + depends: + - libcxx >=14.0.6 + track_features: + - isl_imath-32 + license: MIT + license_family: MIT + size: 894410 + timestamp: 1680649639107 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/isl-0.26-imath32_h347afa1_101.conda sha256: fc9272371750c56908b8e535755b1e23cf7803a2cc4a7d9ae539347baa14f740 md5: e80e44a3f4862b1da870dc0557f8cf3b @@ -6772,6 +7225,19 @@ packages: license_family: MIT size: 510641 timestamp: 1739161381270 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-956.6-llvm19_1_hc3792c1_3.conda + sha256: fc720deee55e62a21c7b3a86041acce201472731f9db826099f4060e8a92ad78 + md5: 2a1c17d828bd3916f871d9a49432e0a1 + depends: + - ld64_osx-64 956.6 llvm19_1_h466f870_3 + - libllvm19 >=19.1.7,<19.2.0a0 + constrains: + - cctools 1030.6.3.* + - cctools_osx-64 1030.6.3.* + license: APSL-2.0 + license_family: Other + size: 21562 + timestamp: 1767114511590 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64-955.13-he86490a_1.conda sha256: 0a86572557ba022dae78eb57ce8d2efd2a00fec595bf56abb733870dda611acf md5: b350b94c4bcf9e420affa09e0ce2ec8a @@ -6785,6 +7251,24 @@ packages: license_family: Other size: 18091 timestamp: 1756645549597 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-956.6-llvm19_1_h466f870_3.conda + sha256: f3d3eb60f756f9eda6ef9ca89bca372e2785762b31b42f2967253a6a17b1eac8 + md5: 5998e06528c03076d645c5d5c3479b81 + depends: + - __osx >=10.13 + - libcxx + - libllvm19 >=19.1.7,<19.2.0a0 + - sigtool-codesign + - tapi >=1600.0.11.8,<1601.0a0 + constrains: + - ld64 956.6.* + - cctools_impl_osx-64 1030.6.3.* + - cctools 1030.6.3.* + - clang 19.1.* + license: APSL-2.0 + license_family: Other + size: 1115701 + timestamp: 1767114433927 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64_osx-arm64-955.13-hc42d924_1.conda sha256: 112f4d57c4d451010f94d10c926a2a54f0f1d62e382ac3a0e13c4f611aa3b12d md5: 3cb7f3c67053be4f5b34156562f4f9c6 @@ -7152,6 +7636,17 @@ packages: license_family: BSD size: 70700 timestamp: 1754682490395 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_hc369343_5.conda + sha256: 16ff6eea7319f5e7a8091028e6ed66a33b0ea5a859075354b93674e6f0a1087a + md5: 51c684dbc10be31478e7fc0e85d27bfe + depends: + - __osx >=10.13 + - libcxx >=19.1.7 + - libllvm19 >=19.1.7,<19.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 14856234 + timestamp: 1759436552121 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp19.1-19.1.7-default_hf90f093_3.conda sha256: 581014d18bb6a9c2c7b46ca932b338b54b351bd8e9ccfd5ad665fd2d9810b8d0 md5: 560546d163a6622b494ce92204e67540 @@ -7254,6 +7749,16 @@ packages: license_family: Apache size: 568692 timestamp: 1756698505599 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_2.conda + sha256: 760af3509e723d8ee5a9baa7f923a213a758b3a09e41ffdaf10f3a474898ab3f + md5: 52031c3ab8857ea8bcc96fe6f1b6d778 + depends: + - libcxx >=19.1.7 + - libcxx-headers >=19.1.7,<19.1.8.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 23069 + timestamp: 1764648572536 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-devel-19.1.7-h6dc3340_1.conda sha256: 6dd08a65b8ef162b058dc931aba3bdb6274ba5f05b6c86fbd0c23f2eafc7cc47 md5: 1399af81db60d441e7c6577307d5cf82 @@ -7263,6 +7768,17 @@ packages: license_family: Apache size: 825628 timestamp: 1742451285589 +- conda: https://conda.anaconda.org/conda-forge/noarch/libcxx-headers-19.1.7-h707e725_2.conda + sha256: 36485e6807e03a4f15a8018ec982457a9de0a1318b4b49a44c5da75849dbe24f + md5: de91b5ce46dc7968b6e311f9add055a2 + depends: + - __unix + constrains: + - libcxx-devel 19.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 830747 + timestamp: 1764647922410 - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.24-h86f0d12_0.conda sha256: 8420748ea1cc5f18ecc5068b4f24c7a023cc9b20971c99c824ba10641fb95ddf md5: 64f0c503da58ec25ebd359e4d990afa8 @@ -7622,6 +8138,13 @@ packages: license_family: GPL size: 134383 timestamp: 1756239485494 +- conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-14.3.0-h660b60f_1.conda + sha256: b60e918409b71302ee61b61080b1b254a902c03fbcbb415c81925dc016c5990e + md5: 731190552d91ade042ddf897cfb361aa + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 551342 + timestamp: 1756238221735 - conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-arm64-14.3.0-hc965647_1.conda sha256: f6ecc12e02a30ab7ee7a8b7285e4ffe3c2452e43885ce324b85827b97659a8c8 md5: c1b69e537b3031d0f5af780b432ce511 @@ -7944,6 +8467,20 @@ packages: license_family: BSD size: 82224 timestamp: 1754682540087 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-h56e7563_2.conda + sha256: 375a634873b7441d5101e6e2a9d3a42fec51be392306a03a2fa12ae8edecec1a + md5: 05a54b479099676e75f80ad0ddd38eff + depends: + - __osx >=10.13 + - libcxx >=19 + - libxml2 + - libxml2-16 >=2.14.5 + - libzlib >=1.3.1,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 28801374 + timestamp: 1757354631264 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm19-19.1.7-hc4b4ae8_1.conda sha256: 5a1d3e7505e8ce6055c3aa361ae660916122089a80abfb009d8d4c49238a7ea4 md5: 020aeb16fc952ac441852d8eba2cf2fd @@ -8287,6 +8824,16 @@ packages: license: LGPL-2.1-or-later size: 6543651 timestamp: 1743368725313 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libsigtool-0.1.3-hc0f2934_0.conda + sha256: f87b743d5ab11c1a8ddd800dd9357fc0fabe47686068232ddc1d1eed0d7321ec + md5: 3576aba85ce5e9ab15aa0ea376ab864b + depends: + - __osx >=10.13 + - openssl >=3.5.4,<4.0a0 + license: MIT + license_family: MIT + size: 38085 + timestamp: 1767044977731 - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda sha256: 6d9c32fc369af5a84875725f7ddfbfc2ace795c28f246dc70055a79f9b2003da md5: 0b367fad34931cb79e0d6b7e5c06bb1c @@ -8776,6 +9323,22 @@ packages: license_family: APACHE size: 344490 timestamp: 1756145011384 +- conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-hb0207f0_2.conda + sha256: 8d042ee522bc9eb12c061f5f7e53052aeb4f13e576e624c8bebaf493725b95a0 + md5: 0f79b23c03d80f22ce4fe0022d12f6d2 + depends: + - __osx >=10.13 + - libllvm19 19.1.7 h56e7563_2 + - llvm-tools-19 19.1.7 h879f4bc_2 + constrains: + - llvmdev 19.1.7 + - llvm 19.1.7 + - clang 19.1.7 + - clang-tools 19.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 87962 + timestamp: 1757355027273 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-19.1.7-hd2aecb6_1.conda sha256: 0537eb46cd766bdae85cbdfc4dfb3a4d70a85c6c088a33722104bbed78256eca md5: b79a1a40211c67a3ae5dbd0cb36604d2 @@ -8792,6 +9355,19 @@ packages: license_family: Apache size: 87945 timestamp: 1737781780073 +- conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-h879f4bc_2.conda + sha256: fd281acb243323087ce672139f03a1b35ceb0e864a3b4e8113b9c23ca1f83bf0 + md5: bf644c6f69854656aa02d1520175840e + depends: + - __osx >=10.13 + - libcxx >=19 + - libllvm19 19.1.7 h56e7563_2 + - libzlib >=1.3.1,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 17198870 + timestamp: 1757354915882 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-19-19.1.7-h87a4c7e_1.conda sha256: 74588508746622baae1bb9c6a69ef571af68dfc7af2bd09546aff26ab3d31764 md5: ebaf5f56104cdb0481fda2a6069f85bf @@ -9402,6 +9978,17 @@ packages: license_family: Proprietary size: 103088799 timestamp: 1753975600547 +- conda: https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h9d8efa1_1.conda + sha256: dcf91571da6c2f0db96d43a1b639047def05a0e1b6436d42c9129ab14af47b10 + md5: 0520855aaae268ea413d6bc913f1384c + depends: + - __osx >=10.13 + - gmp >=6.3.0,<7.0a0 + - mpfr >=4.2.1,<5.0a0 + license: LGPL-3.0-or-later + license_family: LGPL + size: 107774 + timestamp: 1725629348601 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/mpc-1.3.1-h8f1351a_1.conda sha256: 2700899ad03302a1751dbf2bca135407e470dd83ac897ab91dd8675d4300f158 md5: a5635df796b71f6ca400fc7026f50701 @@ -9413,6 +10000,16 @@ packages: license_family: LGPL size: 104766 timestamp: 1725629165420 +- conda: https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda + sha256: dddb6721dff05b8dfb654c532725330231fcb81ff1e27d885ee0cdcc9fccf1c4 + md5: d511e58aaaabfc23136880d9956fa7a6 + depends: + - __osx >=10.13 + - gmp >=6.3.0,<7.0a0 + license: LGPL-3.0-only + license_family: LGPL + size: 373396 + timestamp: 1725746891597 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/mpfr-4.2.1-hb693164_3.conda sha256: 4463e4e2aba7668e37a1b8532859191b4477a6f3602a5d6b4d64ad4c4baaeac5 md5: 4e4ea852d54cc2b869842de5044662fb @@ -12442,6 +13039,13 @@ packages: license_family: BSD size: 15282796 timestamp: 1756530913317 +- conda: https://conda.anaconda.org/conda-forge/noarch/sdkroot_env_osx-64-14.5-hbf94ba6_4.conda + sha256: e0ec582a2ef7eca39fb40b17753e0a4006c02e794e3fc85ab598931d16ba28d5 + md5: bfc192e9093bd93e38185351be812157 + license: BSD-3-Clause + license_family: BSD + size: 8900 + timestamp: 1764616252089 - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.1.0-pyhd8ed1ab_2.conda sha256: 32a512965d887b2214ba4cb4bb92401a00539695fd7ce56b20786cf487b91052 md5: abe4bef6497cfea3f58566c43868cbe0 @@ -12471,6 +13075,17 @@ packages: license_family: MIT size: 210264 timestamp: 1643442231687 +- conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-codesign-0.1.3-hc0f2934_0.conda + sha256: b89d89d0b62e0a84093205607d071932cca228d4d6982a5b073eec7e765b146d + md5: 1261fc730f1d8af7eeea8a0024b23493 + depends: + - __osx >=10.13 + - libsigtool 0.1.3 hc0f2934_0 + - openssl >=3.5.4,<4.0a0 + license: MIT + license_family: MIT + size: 123083 + timestamp: 1767045007433 - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d md5: 3339e3b65d58accf4ca4fb8748ab16b3 @@ -12823,6 +13438,16 @@ packages: license_family: MIT size: 26988 timestamp: 1733569565672 +- conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1600.0.11.8-h8d8e812_0.conda + sha256: 2602632f7923fd59042a897bfb22f050d78f2b5960d53565eae5fa6a79308caa + md5: aae272355bc3f038e403130a5f6f5495 + depends: + - libcxx >=19.0.0.a0 + - __osx >=10.13 + - ncurses >=6.5,<7.0a0 + license: NCSA + size: 213480 + timestamp: 1762535196805 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tapi-1300.6.5-h03f4b80_0.conda sha256: 37cd4f62ec023df8a6c6f9f6ffddde3d6620a83cbcab170a8fff31ef944402e5 md5: b703bc3e6cba5943acf0e5f987b5d0e2 @@ -14252,6 +14877,16 @@ packages: license_family: MIT size: 22963 timestamp: 1749421737203 +- conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda + sha256: 219edbdfe7f073564375819732cbf7cc0d7c7c18d3f546a09c2dfaf26e4d69f3 + md5: c989e0295dcbdc08106fe5d9e935f0b9 + depends: + - __osx >=10.13 + - libzlib 1.3.1 hd23fc13_2 + license: Zlib + license_family: Other + size: 88544 + timestamp: 1727963189976 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda sha256: 58f8860756680a4831c1bf4f294e2354d187f2e999791d53b1941834c4b37430 md5: e3170d898ca6cb48f1bb567afb92f775 diff --git a/pixi/pixi.toml b/pixi/pixi.toml index 7c78c095..3efd41d6 100644 --- a/pixi/pixi.toml +++ b/pixi/pixi.toml @@ -67,6 +67,10 @@ gcc = ">=14.2.0,<14.3" compilers = ">=1.11.0,<2" clang = ">=19.1.7,<22" +[target.osx-64.dependencies] +compilers = ">=1.11.0,<2" +clang = ">=19.1.7,<22" + # for now assume gcc & gfortran already installed in Linux # The list above contains a number of items that are needed only for