# -*- coding: utf-8 -*-
'''
Classes and routines defined in :mod:`GSASIIpwdplot` follow.
'''
from __future__ import division, print_function
import time
import copy
import math
import sys
import os.path
import numpy as np
import numpy.ma as ma
from . import GSASIIpath
# Don't depend on wx/matplotlib/scipy for scriptable; or for Sphinx docs
try:
import wx
import wx.aui
import wx.glcanvas
except (ImportError, ValueError):
print('GSASIIpwdplot: wx not imported')
try:
import matplotlib as mpl
if not mpl.get_backend(): #could be assigned by spyder debugger
mpl.use('wxAgg')
import matplotlib.figure as mplfig
except (ImportError, ValueError) as err:
print('GSASIIpwdplot: matplotlib not imported')
if GSASIIpath.GetConfigValue('debug'): print('error msg:',err)
from . import GSASIIdataGUI as G2gd
from . import GSASIIpwdGUI as G2pdG
from . import GSASIIlattice as G2lat
from . import GSASIImath as G2mth
from . import GSASIIctrlGUI as G2G
#import GSASIIobj as G2obj
from . import GSASIIplot as G2plt
import matplotlib.colors as mpcls
try:
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
except ImportError:
from matplotlib.backends.backend_wx import FigureCanvas as Canvas
try:
from matplotlib.backends.backend_agg import FigureCanvasAgg as hcCanvas
except ImportError:
from matplotlib.backends.backend_agg import FigureCanvas as hcCanvas # standard name
except RuntimeError: # happens during doc builds
pass
# useful degree trig functions
sind = lambda x: math.sin(x*math.pi/180.)
cosd = lambda x: math.cos(x*math.pi/180.)
tand = lambda x: math.tan(x*math.pi/180.)
asind = lambda x: 180.*math.asin(x)/math.pi
acosd = lambda x: 180.*math.acos(x)/math.pi
atan2d = lambda x,y: 180.*math.atan2(y,x)/math.pi
atand = lambda x: 180.*math.atan(x)/math.pi
# numpy versions
npsind = lambda x: np.sin(x*np.pi/180.)
npcosd = lambda x: np.cos(x*np.pi/180.)
nptand = lambda x: np.tan(x*np.pi/180.)
npacosd = lambda x: 180.*np.arccos(x)/np.pi
npasind = lambda x: 180.*np.arcsin(x)/np.pi
npatand = lambda x: 180.*np.arctan(x)/np.pi
npatan2d = lambda x,y: 180.*np.arctan2(x,y)/np.pi
# misc global vars
Clip_on = GSASIIpath.GetConfigValue('Clip_on',True)
Gkchisq = chr(0x03C7)+chr(0xb2)
plotDebug = False
timeDebug = GSASIIpath.GetConfigValue('Show_timing',False)
# options for publication-quality Rietveld plots
plotOpt = {}
plotOpt['obsInCaption'] = True # include the observed, calc,... items in the plot caption (PlotPatterns)
plotOpt['labelSize'] = '11'
plotOpt['dpi'] = 600
plotOpt['width'] = 8.
plotOpt['height'] = 6.
plotOpt['Show'] = {}
plotOpt['legend'] = {}
plotOpt['colors'] = {}
plotOpt['format'] = None
plotOpt['initNeeded'] = True
plotOpt['lineList'] = ('obs','calc','bkg','zero','diff')
plotOpt['phaseLabels'] = {}
plotOpt['lineWid'] = '1'
plotOpt['saveCSV'] = False
plotOpt['CSVfile'] = None
for xy in 'x','y':
for minmax in 'min','max':
key = f'{xy}{minmax}'
plotOpt[key] = 0.0
plotOpt[key+'_use'] = False
partialOpts = {} # options for display of partials
savedX = None # contains the X values in plot units for "master" pattern, with mask
#### PlotPatterns ################################################################################
[docs]
def ReplotPattern(G2frame,newPlot,plotType,PatternName=None,PickName=None):
'''This does the same as PlotPatterns except that it expects the information
to be plotted (pattern name, item picked in tree + eventually the reflection list)
to be passed as names rather than references to wx tree items, defined as class entries
'''
if PatternName:
pId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, PatternName)
if pId:
G2frame.PatternId = pId
else:
if GSASIIpath.GetConfigValue('debug'): print('PatternName not found',PatternName)
return
if PickName == PatternName:
G2frame.PickId = G2frame.PatternId
elif PickName:
pId = G2gd.GetGPXtreeItemId(G2frame, G2frame.PatternId, PickName)
if pId:
G2frame.PickId = pId
else:
if GSASIIpath.GetConfigValue('debug'): print('PickName not found',PickName)
return
elif GSASIIpath.GetConfigValue('debug'):
print('Possible PickId problem PickId=',G2frame.PickId)
# for now I am not sure how to regenerate G2frame.HKL
G2frame.HKL = [] # array of generated reflections
G2frame.Extinct = [] # array of extinct reflections
PlotPatterns(G2frame,plotType=plotType)
[docs]
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))
[docs]
def PlotPatterns(G2frame,newPlot=False,plotType='PWDR',data=None,
extraKeys=[],refineMode=False,indexFrom='',fromTree=False):
'''Powder pattern plotting package - displays single or multiple powder
patterns as intensity vs 2-theta, q or TOF. Can display multiple patterns
as "waterfall plots" or contour plots. Log I plotting available.
Note that information needed for plotting will be found in:
* G2frame.PatternId: contains the tree item for the current histogram
* G2frame.PickId: contains the actual selected tree item (can be child
of histogram)
* G2frame.HKL: used for tooltip display of hkl for a selected/generated
phase's reflections when mouse is moved to a reflection location;
HKL locations shown (usually as an orange line) in "Index Peak List"
& "Unit Cells List" plots.
N.B. reflection tick markers are generated from each phase's
reflection list.
* G2frame.Extinct: used for display of extinct reflections (in blue)
for generated reflections when "show extinct" is selected.
:param wx.Frame G2frame: main GSAS-II window
:param newPlot: Set to True when a new type of plot is drawn (default False)
:param plotType: Type of data entry to be plotted (SASD, REFD, PWDR)
(default is 'PWDR')
:param list data: Contents of histogram
:param list extraKeys: list of str values with extra "command" keys to
act on plot
:param bool refineMode: Set to True when called from inside a refinement
default is False
:param str indexFrom: Status line message used to label indexing results
:param bool fromTree: will be set to True when called from the data tree
:returns: if refineMode is True, returns a reference to
:func:`refPlotUpdate`. Otherwise, nothing is returned
'''
global PlotList,IndxFrom
IndxFrom = indexFrom
def PublishPlot(event):
msg = ""
if 'PWDR' not in plottype:
msg += " * only PWDR histograms can be used"
if G2frame.Contour or not G2frame.SinglePlot:
if msg: msg += '\n'
msg += " * only when a single histogram is plotted"
if Page.plotStyle['logPlot']:
if msg: msg += '\n'
msg += " * only when the intensity scale is linear/sqrt (not log)"
if msg:
msg = 'Publication export is only available under limited plot settings\n'+msg
G2G.G2MessageBox(G2frame,msg,'Wrong plot settings')
print(msg)
elif G2frame.Weight:
G2frame.Weight = False
PlotPatterns(G2frame,plotType=plottype,extraKeys=extraKeys)
PublishRietveldPlot(G2frame,Pattern,Plot,Page)
G2frame.Weight = True
PlotPatterns(G2frame,plotType=plottype,extraKeys=extraKeys)
return
else:
PublishRietveldPlot(G2frame,Pattern,Plot,Page)
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)
return
newPlot = False
if event.key == 'w':
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
# shift+1 assumes US keyboard
print('saving plotting defaults for',G2frame.GPXtree.GetItemText(G2frame.PatternId))
data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
data[0]['PlotDefaults'] = copy.deepcopy([
Plot.get_xlim(),Plot.get_ylim(),Page.plotStyle,
G2frame.SinglePlot, G2frame.Contour, G2frame.Weight,
G2frame.plusPlot, G2frame.SubBack])
elif event.key == 'X' and plottype == 'PWDR':
G2frame.CumeChi = not G2frame.CumeChi
elif event.key == 'e' and plottype in ['SASD','REFD']:
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
if G2frame.Contour: return
Page.plotStyle['flTicks'] = (Page.plotStyle.get('flTicks',0)+1)%3
elif event.key == 'x' and 'PWDR' in plottype:
Page.plotStyle['exclude'] = not Page.plotStyle['exclude']
elif event.key == 'k' and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Background':
# change the fixed-background mode
backPts = G2frame.dataWindow.wxID_BackPts
for i,mode in enumerate(('Add','Move','Delete')): # what menu is selected?
if G2frame.dataWindow.BackMenu.FindItemById(backPts[mode]).IsChecked():
break
else:
i = 0
next = (i+1)%3 # set next button
for i,mode in enumerate(('Add','Move','Delete')): # what menu is selected?
G2frame.dataWindow.BackMenu.FindItemById(backPts[mode]).Check(i==next)
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
elif event.key == '.':
Page.plotStyle['WgtDiagnostic'] = not Page.plotStyle.get('WgtDiagnostic',False)
newPlot = True
elif event.key == 'b' and plottype not in ['SASD','REFD'] and not Page.plotStyle['logPlot'] and not Page.plotStyle['sqrtPlot']:
G2frame.SubBack = not G2frame.SubBack
elif event.key == 'n':
if G2frame.Contour:
pass
else:
Page.plotStyle['logPlot'] = not Page.plotStyle['logPlot']
if Page.plotStyle['logPlot']:
Page.plotStyle['sqrtPlot'] = False
else:
Page.plotStyle['Offset'][0] = 0
newPlot = True
elif event.key == 's' and 'PWDR' in plottype:
Page.plotStyle['sqrtPlot'] = not Page.plotStyle['sqrtPlot']
if Page.plotStyle['sqrtPlot']:
Page.plotStyle['logPlot'] = False
G2frame.SubBack = False
YmaxS = max(Pattern[1][1])
if Page.plotStyle['sqrtPlot']:
Page.plotStyle['delOffset'] = float(.02*np.sqrt(YmaxS))
Page.plotStyle['refOffset'] = float(-0.1*np.sqrt(YmaxS))
Page.plotStyle['refDelt'] = float(.1*np.sqrt(YmaxS))
else:
Page.plotStyle['delOffset'] = float(.02*YmaxS)
Page.plotStyle['refOffset'] = float(-0.1*YmaxS)
Page.plotStyle['refDelt'] = float(.1*YmaxS)
newPlot = True
elif event.key == 'S' and 'PWDR' in plottype:
choice = [m for m in mpl.cm.datad.keys()]+['GSPaired','GSPaired_r',] # if not m.endswith("_r")
choice.sort()
dlg = wx.SingleChoiceDialog(G2frame,'Select','Color scheme',choice)
if dlg.ShowModal() == wx.ID_OK:
sel = dlg.GetSelection()
G2frame.ContourColor = choice[sel]
else:
G2frame.ContourColor = GSASIIpath.GetConfigValue('Contour_color','Paired')
dlg.Destroy()
newPlot = True
elif event.key == 'u' and (G2frame.Contour or not G2frame.SinglePlot):
if G2frame.Contour:
G2frame.Cmax = min(1.0,G2frame.Cmax*1.2)
elif Page.plotStyle['Offset'][0] < 100.:
Page.plotStyle['Offset'][0] += 1.
elif event.key == 'd' and (G2frame.Contour or not G2frame.SinglePlot):
if G2frame.Contour:
G2frame.Cmax = max(0.0,G2frame.Cmax*0.8)
elif Page.plotStyle['Offset'][0] > -100.:
Page.plotStyle['Offset'][0] -= 1.
elif (event.key == 'u' or event.key == 'd'
) and G2frame.GPXtree.GetItemText(G2frame.PickId) in [
'Index Peak List','Peak List']:
# select the next or previous peak and highlight it
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Index Peak List': grid = G2frame.indxPeaks
elif G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Peak List':
grid = G2frame.reflGrid
selected = grid.GetSelectedRows()
grid.ClearSelection()
if event.key == 'd':
if not selected: selected = [-1,]
r = selected[0]+1
if r >= grid.NumberRows: r = None
else:
if not selected: selected = [grid.NumberRows]
r = selected[0]-1
if r < 0: r = None
if r is not None:
grid.SelectRow(r,True)
grid.MakeCellVisible(r,0)
wx.CallAfter(grid.ForceRefresh)
elif event.key == 'U':
if G2frame.Contour:
G2frame.Cmin += (G2frame.Cmax - G2frame.Cmin)/5.
elif Page.plotStyle['Offset'][0] < 100.:
Page.plotStyle['Offset'][0] += 10.
elif event.key == 'D':
if G2frame.Contour:
G2frame.Cmin -= (G2frame.Cmax - G2frame.Cmin)/5.
elif Page.plotStyle['Offset'][0] > -100.:
Page.plotStyle['Offset'][0] -= 10.
elif event.key == 'g':
mpl.rcParams['axes.grid'] = not mpl.rcParams['axes.grid']
elif event.key == 'l' and not G2frame.SinglePlot:
Page.plotStyle['Offset'][1] -= 1.
elif event.key == 'r' and not G2frame.SinglePlot:
Page.plotStyle['Offset'][1] += 1.
elif event.key in ['L','shift+l']: # controls legend
if G2frame.Contour: return
if not plotOpt['obsInCaption'] and len(PlotList) > 20:
dlg = wx.MessageDialog(G2frame,
f'You have {len(PlotList)} histograms in this plot. Are you sure you want a legend?',
'Confirm legend',wx.YES_NO | wx.ICON_QUESTION)
try:
result = dlg.ShowModal()
finally:
dlg.Destroy()
if result != wx.ID_YES: return
# include the observed, calc,... items in the plot caption (PlotPatterns)
plotOpt['obsInCaption'] = not plotOpt['obsInCaption']
elif event.key in ['o','O','shift+o']: # resets offsets
if G2frame.Contour: return
if not G2frame.SinglePlot: # waterfall: reset the offsets
G2frame.Cmax = 1.0
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
elif event.key == 'c' and 'PWDR' in plottype:
newPlot = True
if not G2frame.Contour:
G2frame.SinglePlot = False
Page.plotStyle['Offset'] = [0.,0.]
G2frame.FixedLimits['cylims'] = ['',''] # reset manual limits
else:
G2frame.SinglePlot = True
G2frame.Contour = not G2frame.Contour
elif (event.key == 'p' and 'PWDR' in plottype and G2frame.SinglePlot):
Page.plotStyle['partials'] = not Page.plotStyle['partials']
elif (event.key == 'e' and 'PWDR' in plottype and G2frame.SinglePlot and ifLimits
and not G2frame.Contour):
Page.excludeMode = not Page.excludeMode
if Page.excludeMode:
try: # fails from key menu
Page.startExclReg = event.xdata
except AttributeError:
G2G.G2MessageBox(G2frame,'To create an excluded region, after clicking on "OK", move to the beginning of the region and press the "e" key. Then move to the end of the region and press "e" again','How to exclude')
return
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
axis.axvline(Page.startExclReg,color='b',dashes=(2,3))
Page.vLine = Plot.axvline(Page.startExclReg,color='b',dashes=(2,3))
SavePlot4animate()
else:
UnsavePlot4animate()
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)
limdat.append([mn,mx])
G2pdG.UpdateLimitsGrid(G2frame,limdat,plottype)
return
elif event.key == 'a' and 'PWDR' in plottype and G2frame.SinglePlot and not (
Page.plotStyle['logPlot'] or Page.plotStyle['sqrtPlot'] or G2frame.Contour):
# add a magnification region
try:
xpos = event.xdata
if xpos is None: return #avoid out of frame mouse position
if 'Magnification' not in Pattern[0]:
Pattern[0]['Magnification'] = []
try:
if Page.plotStyle['qPlot']:
xpos = G2lat.Dsp2pos(Parms,2.0*np.pi/xpos)
elif Page.plotStyle['dPlot']:
xpos = G2lat.Dsp2pos(Parms,xpos)
except ValueError:
return
except AttributeError: # invoked when this is called from dialog rather than key press
xpos = (Pattern[1][0][-1]+Pattern[1][0][0])/2 # set to middle of pattern
if not Pattern[0]['Magnification']:
Pattern[0]['Magnification'] = [[None,1.]]
Pattern[0]['Magnification'] += [[xpos,2.]]
wx.CallAfter(G2gd.UpdatePWHKPlot,G2frame,plottype,G2frame.PatternId)
return
elif event.key == 'q' and not ifLimits:
newPlot = True
if 'PWDR' in plottype:
Page.plotStyle['qPlot'] = not Page.plotStyle['qPlot']
Page.plotStyle['dPlot'] = False
Page.plotStyle['chanPlot'] = False
elif plottype in ['SASD','REFD']:
Page.plotStyle['sqPlot'] = not Page.plotStyle['sqPlot']
elif event.key == 'h' and G2frame.Contour:
newPlot = True
Page.plotStyle['qPlot'] = False
Page.plotStyle['dPlot'] = False
Page.plotStyle['chanPlot'] = not Page.plotStyle['chanPlot']
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
Page.plotStyle['dPlot'] = not Page.plotStyle['dPlot']
Page.plotStyle['qPlot'] = False
Page.plotStyle['chanPlot'] = False
elif event.key == 'm':
if not G2frame.Contour:
G2frame.SinglePlot = not G2frame.SinglePlot
if not G2frame.SinglePlot: plotOpt['obsInCaption'] = False # remove caption from waterfall
G2frame.Contour = False
newPlot = True
elif event.key == 'F' and not G2frame.SinglePlot:
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)
if dlg.ShowModal() == wx.ID_OK:
G2frame.selections = []
select = dlg.GetSelections()
if select and len(select) != len(choices):
for Id in select:
G2frame.selections.append(choices[Id])
else:
G2frame.selections = None
dlg.Destroy()
newPlot = True
elif event.key in ['+','=','shift+=']: # assumes US keyboard
if G2frame.Contour: return
if G2frame.SinglePlot:
G2frame.plusPlot = (G2frame.plusPlot+1)%3
else:
G2frame.plusPlot = (G2frame.plusPlot+1)%4
elif event.key == '/':
Page.plotStyle['Normalize'] = not Page.plotStyle['Normalize']
newPlot = True
elif event.key == 'i' and G2frame.Contour: #for smoothing contour plot
choice = ['nearest','bilinear','bicubic','spline16','spline36','hanning',
'hamming','hermite','kaiser','quadric','catrom','gaussian','bessel',
'mitchell','sinc','lanczos']
dlg = wx.SingleChoiceDialog(G2frame,'Select','Interpolation',choice)
if dlg.ShowModal() == wx.ID_OK:
sel = dlg.GetSelection()
G2frame.Interpolate = choice[sel]
else:
G2frame.Interpolate = 'nearest'
dlg.Destroy()
elif event.key in [KeyItem[0] for KeyItem in extraKeys]:
for KeyItem in extraKeys:
if event.key == KeyItem[0]:
KeyItem[1]()
break
elif event.key == 'v' and 'PWDR' in plottype and G2frame.SinglePlot:
plotOpt['CSVfile'] = G2G.askSaveFile(G2frame,'','.csv',
'Comma separated variable file')
if plotOpt['CSVfile']: plotOpt['saveCSV'] = True
else:
#print('no binding for key',event.key)
return
if G2frame.Contour: newPlot = True # needed or plot disappears, at least on Mac
wx.CallAfter(PlotPatterns,G2frame,newPlot=newPlot,plotType=plottype,extraKeys=extraKeys)
def OnMotion(event):
'''PlotPatterns: respond to motion of the cursor. The status line
will be updated with info based on the mouse position.
Also displays reflection labels as tooltips when mouse is over tickmarks
'''
global PlotList
G2plt.SetCursor(Page)
# excluded region animation
if Page.excludeMode:
if event.xdata is None or G2frame.GPXtree.GetItemText(
G2frame.GPXtree.GetSelection()) != 'Limits': # reset if out of bounds or not on limits
UnsavePlot4animate()
Page.excludeMode = False
wx.CallAfter(PlotPatterns,G2frame,newPlot=False,
plotType=plottype,extraKeys=extraKeys)
return
else:
RestorePlot4animate()
Page.vLine.set_xdata([event.xdata,event.xdata])
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
axis.draw_artist(Page.vLine)
BlitPlot()
return
if event.button and G2frame.Contour and G2frame.TforYaxis:
ytics = imgAx.get_yticks()
ytics = np.where(ytics<len(Temps),ytics,-1)
imgAx.set_yticks(ytics)
ylabs = [np.where(0<=i ,Temps[int(i)],' ') for i in ytics]
imgAx.set_yticklabels(ylabs)
xpos = event.xdata
if xpos is None: return #avoid out of frame mouse position
ypos = event.ydata
try:
Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters')
if not Id: return
Parms,Parms2 = G2frame.GPXtree.GetItemPyData(Id)
limx = Plot.get_xlim()
dT = tolerance = np.fabs(limx[1]-limx[0])/100.
if Page.plotStyle['qPlot'] and 'PWDR' in plottype:
q = xpos
if q <= 0:
G2frame.G2plotNB.status.SetStatusText('Q = %9.5f'%q)
return
try:
dsp = 2.*np.pi/q
xpos = G2lat.Dsp2pos(Parms,2.0*np.pi/q)
except ValueError: #avoid bad value in asin beyond upper limit
G2frame.G2plotNB.status.SetStatusText('Q = %9.5f'%q)
return
if 'T' in Parms['Type'][0]: # TOF
dT = Parms['difC'][1] * 2 * np.pi * tolerance / q**2
elif 'E' in Parms['Type'][0]: # energy dispersive x-rays
pass #for now
else: # 'C' or 'B' in Parms['Type'][0] or 'PKS' in Parms['Type'][0]:
wave = G2mth.getWave(Parms)
dT = tolerance*wave*90./(np.pi**2*cosd(xpos/2))
elif Page.plotStyle['chanPlot'] and G2frame.Contour:
xpos = ma.getdata(X)[min(len(X)-1,int(xpos))]
try:
dsp = G2lat.Pos2dsp(Parms,xpos)
q = 2.*np.pi/dsp
except:
dsp = -1
q = -1
elif plottype in ['SASD','REFD']:
q = xpos
if q <= 0:
G2frame.G2plotNB.status.SetStatusText('Q = %9.5f'%q)
return
dsp = 2.*np.pi/q
elif Page.plotStyle['dPlot']:
dsp = xpos
if dsp <= 0:
G2frame.G2plotNB.status.SetStatusText('d = %9.5f'%dsp)
return
try:
q = 2.*np.pi/dsp
xpos = G2lat.Dsp2pos(Parms,dsp)
except ValueError: #avoid bad value
G2frame.G2plotNB.status.SetStatusText('d = %9.5f'%dsp)
return
dT = tolerance*xpos/dsp
else:
dsp = G2lat.Pos2dsp(Parms,xpos)
q = 2.*np.pi/dsp
statLine = ""
if G2frame.Contour: #PWDR only
try:
pNum = int(ypos+.5)
indx = abs(PlotList[pNum][1][0] - xpos).argmin() # closest point to xpos
val = 'int={:.3g}'.format(ma.getdata(PlotList[pNum][1][1])[indx])
if 'T' in Parms['Type'][0]:
statLine = 'TOF=%.3f d=%.5f Q=%.5f %s pattern ID=%d, %s'%(xpos,dsp,q,val,pNum,PlotList[pNum][-1])
else:
statLine = '2-theta=%.3f d=%.5f Q=%.5f %s pattern ID=%d, %s'%(xpos,dsp,q,val,pNum,PlotList[pNum][-1])
except IndexError:
pass
else:
if 'T' in Parms['Type'][0]:
if Page.plotStyle['sqrtPlot']:
statLine = 'TOF = %9.3f d=%9.5f Q=%9.5f sqrt(Intensity) =%9.2f'%(xpos,dsp,q,ypos)
else:
statLine = 'TOF =%9.3f d=%9.5f Q=%9.5f Intensity =%9.2f'%(xpos,dsp,q,ypos)
elif 'E' in Parms['Type'][0]:
statLine = 'Energy =%9.3f d=%9.5f Q=%9.5f sqrt(Intensity) =%9.2f'%(xpos,dsp,q,ypos)
else:
if 'PWDR' in plottype:
ytmp = ypos
if Page.plotStyle['sqrtPlot']:
ytmp = ypos**2
statLine = '2-theta=%.3f d=%.5f Q=%.4f Intensity=%.2f'%(xpos,dsp,q,ytmp)
elif plottype == 'SASD':
statLine = 'q =%12.5g Intensity =%12.5g d =%9.1f'%(q,ypos,dsp)
elif plottype == 'REFD':
statLine = 'q =%12.5g Reflectivity =%12.5g d =%9.1f'%(q,ypos,dsp)
zoomstat = Page.toolbar.get_zoompan()
if zoomstat:
statLine = "[" + zoomstat + "] " + statLine
G2frame.G2plotNB.status.SetStatusText(statLine + IndxFrom,1)
s = ''
if G2frame.PickId:
pickIdText = G2frame.GPXtree.GetItemText(G2frame.PickId)
else:
pickIdText = '?' # unexpected
tickMarkList = ['Index Peak List','Unit Cells List','Reflection Lists']
if pickIdText in tickMarkList and len(G2frame.HKL):
found = []
indx = -1
if pickIdText in ['Index Peak List','Unit Cells List',]:
indx = -2
# finds reflections within 1% of plot range in units of plot
findx = np.where(np.fabs(np.array(G2frame.HKL).T[indx]-xpos) < dT/2.)
found = G2frame.HKL[findx]
if len(G2frame.Extinct):
G2frame.Extinct = np.array(G2frame.Extinct)
f2 = G2frame.Extinct[np.where(np.fabs(G2frame.Extinct.T[indx]-xpos) < dT/2.)]
found = np.concatenate((found,f2))
if found.shape[0]:
if len(found[0]) > 6: #SS reflections
fmt = "{:.0f},{:.0f},{:.0f},{:.0f}"
n = 4
else:
fmt = "{:.0f},{:.0f},{:.0f}"
n = 3
for i,hkl in enumerate(found):
if i >= 3:
s += '\n...'
break
if s: s += '\n'
s += fmt.format(*hkl[:n])
elif G2frame.itemPicked: # not sure when this will happen
s = '%9.5f'%(xpos)
Page.SetToolTipString(s)
except TypeError:
G2frame.G2plotNB.status.SetStatusText('Select '+plottype+' pattern first',1)
def OnPress(event):
np.seterr(invalid='ignore') #ugh - this removes a matplotlib error for mouse clicks in log plots
if G2frame.ifSetLimitsMode == 3: # start adding an excluded region
savedPlot['excludedPosition'] = event.xdata
Page.excludeMode = True
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
LimitId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits')
limData = G2frame.GPXtree.GetItemPyData(LimitId)
x1 = max(limData[0][0],min(event.xdata,limData[0][1]))
axis.axvline(x1,color='b',dashes=(2,3))
SavePlot4animate()
Page.vLine = Plot.axvline(event.xdata,color='b',dashes=(2,3))
def onMoveDiffCurve(event):
'''Respond to a menu command to move the difference curve.
'''
if not DifLine[0]:
print('No difference curve!')
return
G2frame.itemPicked = DifLine[0]
G2frame.G2plotNB.Parent.Raise()
OnPickPwd(None)
def onMoveTopTick(event):
'''Respond to a menu command to move the tick locations.
'''
if len(Page.phaseList) == 0:
print("there are tick marks (no phases)")
return
G2frame.itemPicked = Page.tickDict[Page.phaseList[0]]
G2frame.G2plotNB.Parent.Raise()
OnPickPwd(None)
def onMoveTickSpace(event):
'''Respond to a menu command to move the tick spacing.
'''
if len(Page.phaseList) == 0:
print("there are tick marks (no phases)")
return
G2frame.itemPicked = Page.tickDict[Page.phaseList[-1]]
G2frame.G2plotNB.Parent.Raise()
OnPickPwd(None)
def onMovePeak(event):
reflGrid = G2frame.reflGrid
selectedPeaks = list(set([row for row,col in reflGrid.GetSelectedCells()] +
reflGrid.GetSelectedRows()))
if len(selectedPeaks) != 1:
tbl = reflGrid.GetTable().data
choices = [f"{i[0]:.2f}" for i in tbl]
dlg = G2G.G2SingleChoiceDialog(G2frame,'Select peak to move',
'select peak',choices)
try:
if dlg.ShowModal() == wx.ID_OK:
selectedPeaks = [dlg.GetSelection()]
finally:
dlg.Destroy()
if len(selectedPeaks) != 1: return
G2frame.itemPicked = G2frame.Lines[selectedPeaks[0]+2] # 1st 2 lines are limits
G2frame.G2plotNB.Parent.Raise()
OnPickPwd(None)
def OnPickPwd(event):
'''Respond to an item being picked. This usually means that the item
will be dragged with the mouse, or sometimes the pick object is used
to create a peak or an excluded region
'''
def OnDragMarker(event):
'''Respond to dragging of a plot Marker
'''
if event.xdata is None or event.ydata is None: return # ignore if cursor out of window
if G2frame.itemPicked is None: return # not sure why this happens, if it does
RestorePlot4animate()
G2frame.itemPicked.set_data([event.xdata], [event.ydata])
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
axis.draw_artist(G2frame.itemPicked)
BlitPlot()
def OnDragLine(event):
'''Respond to dragging of a plot line
'''
if event.xdata is None: return # ignore if cursor out of window
if G2frame.itemPicked is None: return # not sure why this happens
RestorePlot4animate()
coords = G2frame.itemPicked.get_data()
coords[0][0] = coords[0][1] = event.xdata
coords = G2frame.itemPicked.set_data(coords)
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
axis.draw_artist(G2frame.itemPicked)
BlitPlot()
def OnDragLabel(event):
'''Respond to dragging of a HKL label
'''
if event.xdata is None: return # ignore if cursor out of window
if G2frame.itemPicked is None: return # not sure why this happens
try:
coords = list(G2frame.itemPicked.get_position())
coords[1] = event.ydata
data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
data[0]['HKLmarkers'] = data[0].get('HKLmarkers',{})
k1,k2 = G2frame.itemPicked.key
if Page.plotStyle['sqrtPlot']:
data[0]['HKLmarkers'][k1][k2][0] = np.sign(coords[1])*coords[1]**2
else:
data[0]['HKLmarkers'][k1][k2][0] = coords[1]
RestorePlot4animate()
G2frame.itemPicked.set_position(coords)
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
axis.draw_artist(G2frame.itemPicked)
BlitPlot()
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 Page.tickDict is None: return # not sure why this happens, if it does
RestorePlot4animate()
if Page.pickTicknum:
refDelt = -(event.ydata-Page.plotStyle['refOffset'])/Page.pickTicknum
refOffset = Page.plotStyle['refOffset']
else: #1st row of refl ticks
refOffset = event.ydata
refDelt = Page.plotStyle['refDelt']
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
for pId,phase in enumerate(Page.phaseList):
pos = refOffset - pId*refDelt
coords = Page.tickDict[phase].get_data()
coords[1][:] = pos
Page.tickDict[phase].set_data(coords)
axis.draw_artist(Page.tickDict[phase])
BlitPlot()
def OnDragDiffCurve(event):
'''Respond to dragging of the difference curve.
'''
if event.ydata is None: return # ignore if cursor out of window
if G2frame.itemPicked is None: return # not sure why this happens
RestorePlot4animate()
coords = G2frame.itemPicked.get_data()
coords[1][:] += Page.diffOffset + event.ydata
Page.diffOffset = -event.ydata
G2frame.itemPicked.set_data(coords)
Page.figure.gca().draw_artist(G2frame.itemPicked) # Diff curve only found in 1-window plot
BlitPlot()
def DeleteHKLlabel(HKLmarkers,key):
'''Delete an HKL label'''
del HKLmarkers[key[0]][key[1]]
G2frame.itemPicked = None
PlotPatterns(G2frame,plotType=plottype,extraKeys=extraKeys)
####====== start of OnPickPwd
plotNum = G2frame.G2plotNB.plotList.index('Powder Patterns')
inXtraPeakMode = False # Ignore if peak list menubar is not yet created
try:
inXtraPeakMode = G2frame.dataWindow.XtraPeakMode.IsChecked()
except:
pass
global Page
try:
Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
except TypeError:
return
if event is None: # called from a menu command rather than by click on mpl artist
mouse = 1
pick = G2frame.itemPicked
ind = np.array([0])
elif str(event.artist).startswith('Text'): # respond to a right or left click on a HKL Label
if G2frame.itemPicked is not None: # only allow one selection
return
pick = event.artist
xpos,ypos = pick.get_position()
if event.mouseevent.button == 3: # right click, delete HKL label
# but only 1st of the picked items, if multiple
G2frame.itemPicked = pick
data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
data[0]['HKLmarkers'] = data[0].get('HKLmarkers',{})
# finish event processing before deleting the selection, so that
# any other picked items are skipped
wx.CallLater(100,DeleteHKLlabel,data[0]['HKLmarkers'],pick.key)
return
# prepare to drag HKL label (vertical position only)
G2frame.itemPicked = pick
pick.set_alpha(.3) # grey out text
Page = G2frame.G2plotNB.nb.GetPage(plotNum)
SavePlot4animate()
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragLabel)
pick.set_alpha(1.0)
return
else:
if G2frame.itemPicked is not None: return
pick = event.artist
mouse = event.mouseevent
xpos = pick.get_xdata()
ypos = pick.get_ydata()
ind = event.ind
xy = list(list(zip(np.take(xpos,ind),np.take(ypos,ind)))[0])
# convert from plot units
xtick = xy[0] # selected tickmarck pos in 2theta/TOF or d-space (not Q)
if Page.plotStyle['qPlot']: #qplot - convert back to 2-theta/TOF
xy[0] = G2lat.Dsp2pos(Parms,2*np.pi/xy[0])
xtick = xy[0]
elif Page.plotStyle['dPlot']: #dplot - convert back to 2-theta/TOF
xy[0] = G2lat.Dsp2pos(Parms,xy[0])
# if Page.plotStyle['sqrtPlot']:
# xy[1] = xy[1]**2
if G2frame.PickId and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Peak List':
# Peak List: add peaks by clicking on points,
# Or, by dragging: move peaks, limits, diff curve or (XtraPeaks only) tickmarks
phname = ''
try:
phname = str(pick).split('(',1)[1][:-1]
except:
pass
if ind.all() != [0] and ObsLine[0].get_label() in str(pick):
#picked a data point, add a new peak
data = G2frame.GPXtree.GetItemPyData(G2frame.PickId)
XY = G2mth.setPeakparms(Parms,Parms2,xy[0],xy[1],useFit=True)
if inXtraPeakMode:
data['xtraPeaks'] = data.get('xtraPeaks',[])
data['xtraPeaks'].append(XY)
data['sigDict'] = {} #now invalid
else:
data['peaks'].append(XY)
data['sigDict'] = {} #now invalid
G2pdG.UpdatePeakGrid(G2frame,data)
PlotPatterns(G2frame,plotType=plottype,extraKeys=extraKeys)
elif inXtraPeakMode and phname in Page.phaseList:
#picked a tick mark
Page.pickTicknum = Page.phaseList.index(phname)
resetlist = []
for pId,phase in enumerate(Page.phaseList): # set the tickmarks to a lighter color
col = Page.tickDict[phase].get_color()
rgb = mpcls.ColorConverter().to_rgb(col)
rgb_light = [(2 + i)/3. for i in rgb]
resetlist.append((Page.tickDict[phase],rgb))
Page.tickDict[phase].set_color(rgb_light)
Page.tickDict[phase].set_zorder(99) # put on top
SavePlot4animate()
for f,v in resetlist: # reset colors back
f.set_zorder(0)
f.set_color(v) # reset colors back to original values
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragTickmarks)
G2frame.itemPicked = pick
return
elif DifLine[0] is pick:
# drag the difference curve
G2frame.itemPicked = pick
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
SavePlot4animate()
Page.canvas.draw() # save bitmap
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragDiffCurve)
else:
#picked a peak list line, prepare to animate move of line
G2frame.itemPicked = pick
pick.set_linestyle(':') # set line as dotted
Page = G2frame.G2plotNB.nb.GetPage(plotNum)
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
SavePlot4animate()
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragLine)
pick.set_linestyle('--') # back to dashed
elif G2frame.PickId and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Limits':
if len(event.artist.get_data()[0]) != 2 and not G2frame.ifSetLimitsMode:
return # don't select a tickmark to drag. But in Limits/Excluded mode
# could select a point from the pattern here
# Limits: add excluded region or move limits by use of menu command
# and then pick a point
# Or, drag line for limits/excluded region
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])
# point in pattern selected as new upper or lower limit
if G2frame.ifSetLimitsMode == 2: # set upper
limData[1][1] = max(xy[0],limData[1][0])
elif G2frame.ifSetLimitsMode == 1:
limData[1][0] = min(xy[0],limData[1][1]) # set lower
G2frame.ifSetLimitsMode = 0
G2frame.CancelSetLimitsMode.Enable(False)
G2frame.GPXtree.SetItemPyData(LimitId,limData)
G2pdG.UpdateLimitsGrid(G2frame,limData,plottype)
G2frame.GPXtree.SelectItem(LimitId)
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
else: # picked a limit line
# prepare to animate move of line
G2frame.itemPicked = pick
if G2frame.itemPicked in G2frame.MagLines: # don't drag magnification markers here
return
pick.set_linestyle(':') # set line as dotted
Page = G2frame.G2plotNB.nb.GetPage(plotNum)
SavePlot4animate()
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragLine)
pick.set_linestyle('--') # back to dashed
return
elif G2frame.PickId and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Unit Cells List':
# By dragging lines: move limits
if ind.all() == [0]: # picked a limit line
# prepare to animate move of line
G2frame.itemPicked = pick
pick.set_linestyle(':') # set line as dotted
Page = G2frame.G2plotNB.nb.GetPage(plotNum)
SavePlot4animate()
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragLine)
pick.set_linestyle('--') # back to dashed
elif G2frame.PickId and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Models':
if ind.all() != [0]: #picked a data point
LimitId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits')
data = G2frame.GPXtree.GetItemPyData(LimitId)
if mouse.button==1:
data[1][0] = min(xy[0],data[1][1])
if mouse.button==3:
data[1][1] = max(xy[0],data[1][0])
G2frame.GPXtree.SetItemPyData(LimitId,data)
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
else: #picked a limit line
G2frame.itemPicked = pick
elif G2frame.PickId and (
G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Reflection Lists'
or 'PWDR' in G2frame.GPXtree.GetItemText(G2frame.PickId)
):
G2frame.itemPicked = pick
Page = G2frame.G2plotNB.nb.GetPage(plotNum)
if DifLine[0] is G2frame.itemPicked: # pick of difference curve
SavePlot4animate()
Page.diffOffset = Page.plotStyle['delOffset']
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragDiffCurve)
elif G2frame.itemPicked in G2frame.MagLines: # drag of magnification marker
pick.set_dashes((1,4)) # set line as dotted sparse
SavePlot4animate()
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragLine)
pick.set_dashes((1,1)) # back to dotted
else: # pick of plot tick mark (is anything else possible?)
#################################################################
if event is not None and event.mouseevent.button == 3:
data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
font = int(data[0]['HKLconfig'].get('Font','8'))
angle = data[0]['HKLconfig'].get('Orientation',0)
G2frame.itemPicked = None # prevent tickmark repositioning
ph = event.artist.get_label()
if ph not in Phases:
print(f'Tickmark label ({ph}) not in Reflection Lists, very odd')
return
# find column for d-space or 2theta/TOF
Super = 0
if Phases[ph].get('Super',False):
Super = 1
if Page.plotStyle['dPlot']:
indx = 4 + Super
else:
indx = 5 + Super
limx = Plot.get_xlim()
dT = tolerance = np.fabs(limx[1]-limx[0])/100.
if Page.plotStyle['qPlot']:
if 'T' in Parms['Type'][0]: # TOF
q = 2.*np.pi/G2lat.Pos2dsp(Parms,xpos)
dT = Parms['difC'][1] * 2 * np.pi * tolerance / q**2
elif 'E' in Parms['Type'][0]: # energy dispersive x-rays
pass #for now
else: # 'C' or 'B' in Parms['Type'][0] or 'PKS' in Parms['Type'][0]:
wave = G2mth.getWave(Parms)
dT = tolerance*wave*90./(np.pi**2*cosd(xpos/2))
# locate picked tick markers
found_indices = np.where(np.fabs(Phases[ph]['RefList'][:,indx]-xtick) < dT/2.)
if len(found_indices) == 0: return
# get storage location for labeled reflections
data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
data[0]['HKLmarkers'] = data[0].get('HKLmarkers',{})
n = 3
if Super: n = 4
data[0]['HKLmarkers'][ph] = data[0]['HKLmarkers'].get(ph,{})
# position for 1st tick mark
ytick = ypos[0] - 3*(Plot.get_ylim()[1] - Plot.get_ylim()[0])/100
for i,refl in enumerate(Phases[ph]['RefList'][found_indices]):
key = f"{refl[5+Super]:.7g}"
data[0]['HKLmarkers'][ph][key] = data[0][
'HKLmarkers'][ph].get(key,[None,[]])
if Page.plotStyle['sqrtPlot']:
data[0]['HKLmarkers'][ph][key][0] = np.sign(ytick)*ytick**2
else:
data[0]['HKLmarkers'][ph][key][0] = ytick
# add reflection if not already present
for hkl in data[0]['HKLmarkers'][ph][key][1]:
if sum(np.abs(refl[:n] - hkl)) == 0: break
else:
data[0]['HKLmarkers'][ph][key][1].append(tuple(np.rint(refl[:n]).astype(int)))
# offset next tick label position
ytick -= (1+angle)*3*(font/8.)*(Plot.get_ylim()[1] - Plot.get_ylim()[0])/100
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
#################################################################
pick = str(G2frame.itemPicked).split('(',1)[1][:-1]
if pick not in Page.phaseList: # picked something other than a tickmark
return
Page.pickTicknum = Page.phaseList.index(pick)
resetlist = []
for pId,phase in enumerate(Page.phaseList): # set the tickmarks to a lighter color
col = Page.tickDict[phase].get_color()
rgb = mpcls.ColorConverter().to_rgb(col)
rgb_light = [(2 + i)/3. for i in rgb]
resetlist.append((Page.tickDict[phase],rgb))
Page.tickDict[phase].set_color(rgb_light)
Page.tickDict[phase].set_zorder(99) # put on top
SavePlot4animate()
for f,v in resetlist: # reset colors back
f.set_zorder(0)
f.set_color(v) # reset colors back to original values
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragTickmarks)
elif G2frame.PickId and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Background':
# selected a fixed background point. Can move it or delete it.
backPts = G2frame.dataWindow.wxID_BackPts
for mode in backPts: # what menu is selected?
if G2frame.dataWindow.BackMenu.FindItemById(backPts[mode]).IsChecked():
break
# mode will be 'Add' or 'Move' or 'Delete'
if pick.get_marker() == 'D':
# find the closest point
backDict = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Background'))[1]
mag2th = [0]+[x for x,m in magLineList][1:]
magmult = [m for x,m in magLineList]
if magmult:
xy[1] /= magmult[np.searchsorted(mag2th, xy[0], side = 'right')-1]
d2 = [(x-xy[0])**2+(y-xy[1])**2 for x,y in backDict['FixedPoints']]
G2frame.fixPtMarker = d2.index(min(d2))
if mode == 'Move':
# animate move of FixedBkg marker
G2frame.itemPicked = pick
pick.set_marker('|') # change the point appearance
Page = G2frame.G2plotNB.nb.GetPage(plotNum)
SavePlot4animate()
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragMarker)
pick.set_marker('D') # put it back
elif mode == 'Delete':
del backDict['FixedPoints'][G2frame.fixPtMarker]
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
elif ind.all() == [0]: # picked a line
if pick not in G2frame.Lines[0:2]: # select limits only
return
# prepare to animate move of line
G2frame.itemPicked = pick
pick.set_linestyle(':') # set line as dotted
Page = G2frame.G2plotNB.nb.GetPage(plotNum)
SavePlot4animate()
G2frame.cid = Page.canvas.mpl_connect('motion_notify_event', OnDragLine)
pick.set_linestyle('--') # back to dashed
def OnRelease(event):
'''This is called when the mouse button is released when a plot object is dragged
due to an item pick, or when invoked via a menu item (such as in onMoveDiffCurve),
or for background points, which may be added/moved/deleted here.
New peaks are also added here.
'''
plotNum = G2frame.G2plotNB.plotList.index('Powder Patterns')
Page = G2frame.G2plotNB.nb.GetPage(plotNum)
if G2frame.ifSetLimitsMode == 3: # add an excluded region
G2frame.ifSetLimitsMode = 0
Page.excludeMode = False
G2frame.CancelSetLimitsMode.Enable(False)
if savedPlot.get('excludedPosition') is None:
print('Excluded reg. set err: somehow we did not set a starting position')
return
x1 = savedPlot.get('excludedPosition')
x2 = event.xdata
LimitId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits')
limData = G2frame.GPXtree.GetItemPyData(LimitId)
x1 = max(limData[0][0],min(x1,limData[0][1]))
x2 = max(limData[0][0],min(x2,limData[0][1]))
excl = [min(x1,x2),max(x1,x2)]
limData.append(excl)
wx.CallAfter(G2pdG.UpdateLimitsGrid,G2frame,limData,plottype)
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
if G2frame.cid is not None: # if there is a drag connection, delete it
Page.canvas.mpl_disconnect(G2frame.cid)
G2frame.cid = None
UnsavePlot4animate()
if event.xdata is None or event.ydata is None: # ignore drag if cursor is outside of plot
# if GSASIIpath.GetConfigValue('debug'): print('Ignoring drag, invalid pos:',event.xdata,event.ydata)
# wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
if not G2frame.PickId:
if GSASIIpath.GetConfigValue('debug'): print('Ignoring drag, G2frame.PickId is not set')
return
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Background' and event.xdata:
# On Background page, deal with fixed background points or move of limits
if Page.toolbar.AnyActive(): # prevent ops. if a toolbar zoom button pressed
# after any mouse release event (could be a zoom), redraw magnification lines
if magLineList: wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
if G2frame.SubBack or G2frame.Weight or G2frame.Contour or not G2frame.SinglePlot:
return # none of these should be True
backDict = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Background'))[1]
mag2th = [0]+[x for x,m in magLineList][1:]
magmult = [m for x,m in magLineList]
if 'FixedPoints' not in backDict: backDict['FixedPoints'] = []
try:
Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
except TypeError:
return
# unit conversions
xy = [event.xdata,event.ydata]
try:
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])
except:
return
if Page.plotStyle['sqrtPlot']:
xy[1] = xy[1]**2
elif magmult:
mult = magmult[np.searchsorted(mag2th, xy[0], side = 'right')-1]
xy[1] /= mult
# what is mode for Fixed bkg points?
backPts = G2frame.dataWindow.wxID_BackPts
for mode in backPts: # what menu is selected?
if G2frame.dataWindow.BackMenu.FindItemById(backPts[mode]).IsChecked():
break
if mode == 'Add':
backDict['FixedPoints'].append(xy)
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
axis.plot(event.xdata,event.ydata,'rD',clip_on=Clip_on,picker=3.)
Page.canvas.draw()
return
if G2frame.itemPicked is None: return
if G2frame.itemPicked.get_marker() == 'D': # action on fixed background point
# deal with dragging of fixed background points
backDict['FixedPoints'][G2frame.fixPtMarker] = xy
G2frame.itemPicked = None
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
elif G2frame.itemPicked in G2frame.Lines[0:2]: # limit are 1st two lines in list
# here deal with dragging of limits
lineNo = G2frame.Lines.index(G2frame.itemPicked) # 0 (lower limit) or 1 (upper limit)
LimitId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits')
limits = G2frame.GPXtree.GetItemPyData(LimitId)
#Id = lineNo//2+1 # 1 for limits (>1 for excluded regions)
id2 = lineNo%2 # 0 (lower limit) or 1 (upper limit)
limits[1][id2] = xy[0]
#print(f'set limit {id2} to {xy[0]}')
limits[1][0] = min(max(limits[0][0],limits[1][0]),limits[1][1])
limits[1][1] = max(min(limits[0][1],limits[1][1]),limits[1][0])
G2frame.itemPicked = None
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
else: # unexpected oblect was picked
G2frame.itemPicked = None
return
if G2frame.itemPicked is None:
# after any mouse release event (could be a zoom) where nothing is selected,
# redraw magnification lines
if magLineList: wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
if DifLine[0] is G2frame.itemPicked: # respond to dragging of the difference curve
data = G2frame.GPXtree.GetItemPyData(G2frame.PickId)
ypos = event.ydata
Page.plotStyle['delOffset'] = float(-ypos)
G2frame.itemPicked = None
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
return
elif G2frame.itemPicked in G2frame.MagLines: # drag of magnification marker
xpos = event.xdata
try:
if Page.plotStyle['qPlot']: #qplot - convert back to 2-theta
xpos = G2lat.Dsp2pos(Parms,2*np.pi/xpos)
elif Page.plotStyle['dPlot']: #dplot - convert back to 2-theta
xpos = G2lat.Dsp2pos(Parms,xpos)
except:
return
magIndex = G2frame.MagLines.index(G2frame.itemPicked)
data = G2frame.GPXtree.GetItemPyData(G2frame.PickId)
data[0]['Magnification'][magIndex][0] = xpos
wx.CallAfter(G2gd.UpdatePWHKPlot,G2frame,plottype,G2frame.PatternId)
return
Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
xpos = event.xdata
phNum = None
try:
Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId,'Reflection Lists')
pickPhase = str(G2frame.itemPicked).split('(',1)[1][:-1]
phNum = Page.phaseList.index(pickPhase)
except:
pass
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Peak List' and xpos and phNum is not None:
# dragging tickmarks
if phNum:
Page.plotStyle['refDelt'] = -(event.ydata-Page.plotStyle['refOffset'])/phNum
else: #1st row of refl ticks
Page.plotStyle['refOffset'] = event.ydata
elif G2frame.GPXtree.GetItemText(G2frame.PickId) in ['Peak List','Limits','Unit Cells List'] and xpos:
lines = []
for line in G2frame.Lines:
lines.append(line.get_xdata()[0])
try:
lineNo = lines.index(G2frame.itemPicked.get_xdata()[0])
except ValueError:
lineNo = -1
nxcl = len(exclLines)
if lineNo in [0,1] or lineNo in exclLines:
LimitId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits')
limits = G2frame.GPXtree.GetItemPyData(LimitId)
Id = lineNo//2+1
id2 = lineNo%2
if Page.plotStyle['qPlot'] and 'PWDR' in plottype:
limits[Id][id2] = G2lat.Dsp2pos(Parms,2.*np.pi/xpos)
elif Page.plotStyle['dPlot'] and 'PWDR' in plottype:
limits[Id][id2] = G2lat.Dsp2pos(Parms,xpos)
else:
limits[Id][id2] = xpos
if Id > 1 and limits[Id][0] > limits[Id][1]:
limits[Id].reverse()
limits[1][0] = min(max(limits[0][0],limits[1][0]),limits[1][1])
limits[1][1] = max(min(limits[0][1],limits[1][1]),limits[1][0])
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Limits':
G2pdG.UpdateLimitsGrid(G2frame,limits,plottype)
elif lineNo > 1+nxcl:
PeakId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Peak List')
peaks = G2frame.GPXtree.GetItemPyData(PeakId)
inXtraPeakMode = False # Ignore if peak list menubar is not yet created
try:
inXtraPeakMode = G2frame.dataWindow.XtraPeakMode.IsChecked()
except:
pass
if inXtraPeakMode:
tbl = peaks['xtraPeaks']
else:
tbl = peaks['peaks']
if event.button == 3:
del tbl[lineNo-2-nxcl]
else:
if Page.plotStyle['qPlot']:
tbl[lineNo-2-nxcl][0] = G2lat.Dsp2pos(Parms,2.*np.pi/xpos)
elif Page.plotStyle['dPlot']:
tbl[lineNo-2-nxcl][0] = G2lat.Dsp2pos(Parms,xpos)
else:
tbl[lineNo-2-nxcl][0] = xpos
peaks['sigDict'] = {} #no longer valid
G2pdG.UpdatePeakGrid(G2frame,peaks)
elif G2frame.GPXtree.GetItemText(G2frame.PickId) in ['Models',] and xpos:
lines = []
for line in G2frame.Lines:
lines.append(line.get_xdata()[0])
try:
lineNo = lines.index(G2frame.itemPicked.get_xdata()[0])
except ValueError:
lineNo = -1
if lineNo in [0,1]:
LimitId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits')
data = G2frame.GPXtree.GetItemPyData(LimitId)
data[1][lineNo] = xpos
data[1][0] = min(max(data[0][0],data[1][0]),data[1][1])
data[1][1] = max(min(data[0][1],data[1][1]),data[1][0])
elif (G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Reflection Lists'
or 'PWDR' in G2frame.GPXtree.GetItemText(G2frame.PickId)) and xpos:
Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId,'Reflection Lists')
if Id:
pick = str(G2frame.itemPicked).split('(',1)[1][:-1]
if 'line' not in pick: #avoid data points, etc.
if pick in Page.phaseList:
num = Page.phaseList.index(pick)
if num:
Page.plotStyle['refDelt'] = -(event.ydata-Page.plotStyle['refOffset'])/num
else: #1st row of refl ticks
Page.plotStyle['refOffset'] = event.ydata
elif GSASIIpath.GetConfigValue('debug'): # should not happen!
print('How did we get here?')
GSASIIpath.IPyBreak()
wx.CallAfter(PlotPatterns,G2frame,plotType=plottype,extraKeys=extraKeys)
G2frame.itemPicked = None
def onSetPlotLim(event):
'''Specify plot limits manually
'''
def onChecked(event):
try:
i = cbox.index(event.EventObject)
showChecked(i)
except:
pass
def showChecked(i):
checked = cbox[i].GetValue()
if not checked:
# fake out validation to avoid ugly yellow
dbox[i].invalid = False
dbox[i]._IndicateValidity()
else: # reset validation
dbox[i].ChangeValue(dbox[i].GetValue())
dbox[i].Enable(checked)
def applyLims(event):
Page.toolbar.push_current()
# Page.toolbar.set_history_buttons() # this may be needed to update the zoom buttons (needs test)
# Page.canvas.draw_idle() # schedule an MPL update (needs test)
CurLims = {}
CurLims['xlims'] = list(Plot.get_xlim())
if G2frame.Weight:
CurLims['ylims'] = list(Page.figure.axes[1].get_ylim())
CurLims['dylims'] = list(Page.figure.axes[2].get_ylim())
elif G2frame.Contour:
CurLims['ylims'] = list(Plot.get_ylim())
CurLims['cylims'] = list(Page.Img.get_clim())
else:
CurLims['ylims'] = list(Plot.get_ylim())
CurLims['dylims'] = [0,0]
for var in 'xlims','ylims','dylims','cylims':
for i in range(2):
if not G2frame.UseLimits[var][i]: continue
try:
CurLims[var][i] = float(G2frame.FixedLimits[var][i])
CurLims[var][i] = float(G2frame.FixedLimits[var][i])
except:
pass
Plot.set_xlim(CurLims['xlims'])
if G2frame.Weight:
Page.figure.axes[1].set_ylim(CurLims['ylims'])
Page.figure.axes[2].set_ylim(CurLims['dylims'])
elif G2frame.Contour:
Plot.set_ylim(CurLims['ylims'])
Page.Img.set_clim(CurLims['cylims'])
else:
Plot.set_ylim(CurLims['ylims'])
Page.toolbar.push_current()
# Page.toolbar.set_history_buttons() # this may be needed to update the zoom buttons (needs test)
# Page.canvas.draw_idle() # schedule an MPL update (needs test)
Plot.figure.canvas.draw()
# onSetPlotLim starts here
dlg = wx.Dialog(G2frame.plotFrame,
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(wx.StaticText(dlg,wx.ID_ANY,
'Set Plot limits'
),0,wx.ALL)
gsizer = wx.FlexGridSizer(cols=5,hgap=2,vgap=2)
gsizer.Add(wx.StaticText(dlg,wx.ID_ANY,' '),0,wx.ALL)
gsizer.Add(wx.StaticText(dlg,wx.ID_ANY,'use'),0,wx.ALL)
gsizer.Add(wx.StaticText(dlg,wx.ID_ANY,' min'),0,wx.ALL)
gsizer.Add(wx.StaticText(dlg,wx.ID_ANY,'use'),0,wx.ALL)
gsizer.Add(wx.StaticText(dlg,wx.ID_ANY,' max'),0,wx.ALL)
cbox = []
dbox = []
lblkeys = [(' x-axis ','xlims'),(' y-axis ','ylims')]
if G2frame.Weight:
lblkeys += [('(obs-calc)/sig ','dylims')]
elif G2frame.Contour:
lblkeys += [('contour','cylims')]
for lbl,key in lblkeys:
gsizer.Add(wx.StaticText(dlg,wx.ID_ANY,lbl),0,wx.ALL)
for i in range(2):
cbox.append(G2G.G2CheckBox(dlg,'',G2frame.UseLimits[key],i,
OnChange=onChecked))
dbox.append(G2G.ValidatedTxtCtrl(dlg,G2frame.FixedLimits[key],i,
typeHint=float))
gsizer.Add(cbox[-1])
gsizer.Add(dbox[-1])
showChecked(-1)
vbox.Add(gsizer)
vbox.Add((10,10),1,wx.ALL|wx.EXPAND,1)
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add((-1,-1),1,wx.ALL|wx.EXPAND,1)
#btn = wx.Button(dlg, wx.ID_CLOSE)
#btn.Bind(wx.EVT_BUTTON,lambda event:dlg.EndModal(wx.ID_CANCEL))
#hbox.Add(btn)
btn = wx.Button(dlg, wx.ID_ANY, label='Apply')
btn.Bind(wx.EVT_BUTTON,applyLims)
hbox.Add(btn)
OKbtn = wx.Button(dlg, wx.ID_OK)
OKbtn.Bind(wx.EVT_BUTTON,lambda event:dlg.EndModal(wx.ID_OK))
hbox.Add(OKbtn)
hbox.Add((-1,-1),1,wx.ALL|wx.EXPAND,1)
vbox.Add(hbox,1,wx.ALL|wx.EXPAND,1)
dlg.SetSizer(vbox)
vbox.Fit(dlg)
dlg.ShowModal()
dlg.Destroy()
applyLims(None) # apply limits
def onPlotFormat(event):
'''Change the appearance of the current plot'''
changePlotSettings(G2frame,Plot)
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.
'''
if restore:
(G2frame.SinglePlot,G2frame.Contour,G2frame.Weight,
G2frame.plusPlot,G2frame.SubBack,Page.plotStyle['logPlot']) = savedSettings
return
if plottingItem not in Histograms:
histoList = [i for i in Histograms.keys() if i.startswith('PWDR ')]
if len(histoList) == 0:
print('Skipping plot update, no PWDR items!')
return
plotItem = histoList[0]
else:
plotItem = plottingItem
xye = np.array(ma.getdata(Histograms[plotItem]['Data'])) # strips mask
xye0 = Histograms[plotItem]['Data'][0]
limits = Histograms[plotItem]['Limits']
if Page.plotStyle['qPlot']:
X = 2.*np.pi/G2lat.Pos2dsp(Parms,xye0) # might want to consider caching this
Ibeg = np.searchsorted(X,2.*np.pi/G2lat.Pos2dsp(Parms,limits[1][0]))
Ifin = np.searchsorted(X,2.*np.pi/G2lat.Pos2dsp(Parms,limits[1][1]))
elif Page.plotStyle['dPlot']:
X = G2lat.Pos2dsp(Parms,xye0) # might want to consider caching this
Ibeg = np.searchsorted(X,G2lat.Pos2dsp(Parms,limits[1][1]))
Ifin = np.searchsorted(X,G2lat.Pos2dsp(Parms,limits[1][0]))
else:
X = copy.deepcopy(xye0)
Ibeg = np.searchsorted(X,limits[1][0])
Ifin = np.searchsorted(X,limits[1][1])
if Ibeg == Ifin: # if no points are within limits bad things happen
Ibeg,Ifin = 0,None
elif Ibeg > Ifin:
Ifin, Ibeg = Ibeg, Ifin # TOF with order reversed
if Page.plotStyle['sqrtPlot']:
olderr = np.seterr(invalid='ignore') #get around sqrt(-ve) error
Y = np.where(xye[1]>=0.,np.sqrt(xye[1]),-np.sqrt(-xye[1]))
Z = np.where(xye[3]>=0.,np.sqrt(xye[3]),-np.sqrt(-xye[3]))
W = np.where(xye[4]>=0.,np.sqrt(xye[4]),-np.sqrt(-xye[4]))
#D = np.where(xye[5],(Y-Z),0.)-Page.plotStyle['delOffset']
np.seterr(invalid=olderr['invalid'])
else:
Y = copy.copy(xye[1])
Z = copy.copy(xye[3])
W = copy.copy(xye[4])
#D = xye[5]-Page.plotStyle['delOffset'] #powder background
DZ = (xye[1]-xye[3])*np.sqrt(xye[2])
DifLine[0].set_xdata(X[Ibeg:Ifin])
DifLine[0].set_ydata(DZ[Ibeg:Ifin])
try:
lims = [min(DZ[Ibeg:Ifin]),max(DZ[Ibeg:Ifin])]
if all(np.isfinite(lims)): Plot1.set_ylim(lims)
except:
pass
CalcLine[0].set_xdata(X)
ObsLine[0].set_xdata(X)
BackLine[0].set_xdata(X)
CalcLine[0].set_ydata(Z)
ObsLine[0].set_ydata(Y)
BackLine[0].set_ydata(W)
if cycle:
Title = '{} cycle #{}'.format(plotItem,cycle)
else:
Title = plotItem
if Page.plotStyle.get('title',True):
if Page.plotStyle['sqrtPlot']:
Plot.set_title(r'$\sqrt{I}$ for '+Title)
else:
Plot.set_title(Title)
Page.canvas.draw()
wx.GetApp().Yield()
def incCptn(string):
'''Adds a underscore to "hide" a MPL object from the legend if
obsInCaption is False
'''
if plotOpt['obsInCaption']:
return string
else:
return '_'+string
def Replot(*args):
PlotPatterns(G2frame,plotType=plottype,extraKeys=extraKeys)
def onHKLabelConfig(event):
'''Configure all HKL markers in all phases'''
def onDelAll(event):
'''Delete all HKL markers in all phases'''
data[0]['HKLmarkers'] = {}
dlg.EndModal(wx.ID_OK)
Replot()
data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
data[0]['HKLconfig'] = data[0].get('HKLconfig',{})
dlg = wx.Dialog(G2frame,style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(wx.StaticText(dlg,label='Configure Reflection (hkl) Labels'),
0,wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT|wx.BOTTOM,15)
hsizer = wx.FlexGridSizer(cols=2,hgap=2,vgap=2)
sizer.Add(hsizer)
hsizer.Add(wx.StaticText(dlg,label='Label Orientation: '))
data[0]['HKLconfig']['Orientation'] = data[0][
'HKLconfig'].get('Orientation',0)
choice = G2G.G2ChoiceButton(dlg,
['Horizontal','Vertical'],
data[0]['HKLconfig'],'Orientation',
onChoice=Replot)
hsizer.Add(choice)
#
hsizer.Add(wx.StaticText(dlg,label='Font size: '))
data[0]['HKLconfig']['Font'] = data[0][
'HKLconfig'].get('Font','8')
choice = G2G.G2ChoiceButton(dlg,
['6','8','10','12','14','16'],
None,None,
data[0]['HKLconfig'],'Font',
onChoice=Replot)
hsizer.Add(choice)
#
hsizer.Add(wx.StaticText(dlg,label='Box transparency: '))
data[0]['HKLconfig']['alpha'] = data[0][
'HKLconfig'].get('alpha',2)
choice = G2G.G2ChoiceButton(dlg,
['0','25%','50%','75%','100%'],
data[0]['HKLconfig'],'alpha',
onChoice=Replot)
hsizer.Add(choice)
#
btn = wx.Button(dlg, wx.ID_ANY,'Delete all labels')
btn.Bind(wx.EVT_BUTTON, onDelAll)
sizer.Add((-1,10))
sizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5)
btnsizer = wx.StdDialogButtonSizer()
btn = wx.Button(dlg, wx.ID_OK)
btn.SetDefault()
btn.Bind(wx.EVT_BUTTON, lambda x: dlg.EndModal(wx.ID_OK))
btnsizer.AddButton(btn)
btnsizer.Realize()
sizer.Add(btnsizer, 0, wx.EXPAND|wx.ALL, 5)
dlg.SetSizer(sizer)
sizer.Fit(dlg)
dlg.CenterOnParent()
dlg.ShowModal()
return
def onPartialConfig(event):
'''respond to Phase partials config menu command.
Computes partials if needed and then displays a window with options
for each phase. Plot is refreshed each time a setting is changed.
'''
Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls'))
phPartialFile = Controls['PhasePartials']
if phPartialFile is None or not os.path.exists(phPartialFile):
dlg = wx.MessageDialog(G2frame,
'Phase partials (intensity profiles for each individual phase) have not been computed. Do you want to compute them?',
'Confirm compute',wx.YES_NO | wx.ICON_QUESTION)
try:
result = dlg.ShowModal()
finally:
dlg.Destroy()
if result != wx.ID_YES: return
G2frame.OnRefinePartials(None)
if not Page.plotStyle['partials']:
Page.plotStyle['partials'] = True
Replot()
configPartialDisplay(G2frame,Page.phaseColors,Replot)
def SavePlot4animate():
'''Save the region inside the axes box for animation, except on Mac (at least with wx 4.2.3),
where blitting seems broken unless the entire window is used
'''
Page.canvas.draw() # refresh the plot to current state
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
if sys.platform == "darwin":
savedPlot['box'] = Page.figure.bbox
else:
savedPlot['box'] = axis.bbox
# save bitmap
savedPlot['map'] = Page.canvas.copy_from_bbox(savedPlot['box'])
def RestorePlot4animate():
'''reset the plot to the saved version (quick)
'''
if savedPlot.get('map') is None:
pass
else:
Page.canvas.restore_region(savedPlot['map'])
def BlitPlot():
'''quickly update the plot (blit) to animate movement os an artist
'''
Page.canvas.blit(savedPlot['box'])
def UnsavePlot4animate():
'''Done with animation, release the memory used to save
a bitmap of the plot
'''
savedPlot['box'] = savedPlot['map'] = None
#### beginning PlotPatterns execution #####################################
global exclLines,Page
global DifLine
global Ymax
global Pattern,mcolors,Plot,Page,imgAx,Temps
global savedX
global savedPlot
savedPlot = {}
UnsavePlot4animate()
plottype = plotType
inXtraPeakMode = False # Ignore if peak list menubar is not yet created
try:
inXtraPeakMode = G2frame.dataWindow.XtraPeakMode.IsChecked()
except:
pass
# get powder pattern colors from config settings
pwdrCol = {}
for i in 'Obs_color','Calc_color','Diff_color','Bkg_color':
pwdrCol[i] = '#' + GSASIIpath.GetConfigValue(i,getDefault=True)
if not G2frame.PatternId:
return
if 'PKS' in plottype: # This is probably not used anymore; PlotPowderLines seems to be called directly
G2plt.PlotPowderLines(G2frame)
return
if data is None:
data = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
if G2frame.PickId and plottype not in ['SASD','REFD'] and 'PWDR' in G2frame.GPXtree.GetItemText(G2frame.PickId):
publish = PublishPlot
else:
publish = None
new,plotNum,Page,Plot,limits = G2frame.G2plotNB.FindPlotTab('Powder Patterns','mpl',publish=publish)
try:
Selection = G2frame.GPXtree.GetItemText(G2frame.GPXtree.GetSelection())
except:
Selection = None
if G2frame.ifSetLimitsMode and Selection == 'Limits':
# note mode
if G2frame.ifSetLimitsMode == 1:
msg = 'Click on a point to define the location of the lower limit'
elif G2frame.ifSetLimitsMode == 2:
msg = 'Click on a point to define the location of the upper limit'
elif G2frame.ifSetLimitsMode == 3:
msg = 'Click on location to start excluded region,\nthen drag and release at end of region'
Page.figure.text(.02,.93, msg, fontsize=14, fontweight='bold')
elif Selection == 'Background':
backPts = G2frame.dataWindow.wxID_BackPts
for mode in backPts: # what menu is selected?
if G2frame.dataWindow.BackMenu.FindItemById(backPts[mode]).IsChecked():
break
else:
mode = '?'
Page.figure.text(.02,.93, f'Fixed bkg mode: {mode}', fontsize=12, fontweight='bold')
Page.excludeMode = False # True when defining an excluded region
#patch
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),})
#end patch
if 'Normalize' not in Page.plotStyle:
Page.plotStyle['Normalize'] = False
# reset plot when changing between different data types
try:
G2frame.lastPlotType
except:
G2frame.lastPlotType = None
if plotType == 'PWDR':
try:
Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,
G2frame.PatternId, 'Instrument Parameters'))
if G2frame.lastPlotType != Parms['Type'][1]:
if GSASIIpath.GetConfigValue('debug'):
print('triggering newplot from G2frame.lastPlotType')
Ymax = max(data[1][1])
if Page.plotStyle['sqrtPlot']:
Page.plotStyle['delOffset'] = float(.02*np.sqrt(Ymax))
Page.plotStyle['refOffset'] = float(-0.1*np.sqrt(Ymax))
Page.plotStyle['refDelt'] = float(.1*np.sqrt(Ymax))
else:
Page.plotStyle['delOffset'] = float(.02*Ymax)
Page.plotStyle['refOffset'] = float(-0.1*Ymax)
Page.plotStyle['refDelt'] = float(.1*Ymax)
newPlot = True
G2frame.lastPlotType = Parms['Type'][1]
except TypeError: #bad id from GetGPXtreeItemId - skip
pass
try:
G2frame.FixedLimits
except:
G2frame.FixedLimits = {i:['',''] for i in ('xlims','ylims','dylims','cylims')}
try:
G2frame.UseLimits
except:
G2frame.UseLimits = {i:[False,False] for i in ('xlims','ylims','dylims','cylims')}
#=====================================================================================
# code to setup for plotting Rietveld results. Turns off multiplot (contour/waterfall),
# sqrtplot, turn on + and weight plot, but sqrtPlot qPlot and dPlot are not changed.
# Magnification regions are ignored.
# the last-plotted histogram (from G2frame.PatternId) is used for this plotting
# (except in seq. fitting)
# Returns a pointer to refPlotUpdate, which is used to update the plot when this
# returns
if refineMode:
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.SinglePlot = True
G2frame.Contour = False
G2frame.Weight = True
G2frame.plusPlot = 1
G2frame.SubBack = False
Page.plotStyle['logPlot'] = False
# is the selected histogram in the refinement? if not pick the 1st to show
# instead select the first powder pattern and plot it
Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
if plottingItem not in Histograms:
# current plotted item is not in refinement
histoList = [i for i in Histograms.keys() if i.startswith('PWDR ')]
if len(histoList) != 0:
plottingItem = histoList[0]
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)
#=====================================================================================
elif 'PlotDefaults' in data[0] and fromTree: # set style from defaults saved with '!'
#print('setting plot style defaults')
(xlim, ylim, styleDict, G2frame.SinglePlot, G2frame.Contour, G2frame.Weight,
G2frame.plusPlot, G2frame.SubBack) = data[0]['PlotDefaults']
Page.plotStyle = copy.copy(styleDict)
newPlot = True # prevent carrying limits over (may not be needed here)
#=====================================================================================
if not new: # plotting in previously created axes
G2frame.xylim = copy.copy(limits)
else: # 1st time plot is created
if plottype in ['SASD','REFD']:
Page.plotStyle['logPlot'] = True
G2frame.ErrorBars = True
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
try:
for b in Page.bindings:
Page.canvas.mpl_disconnect(b)
except AttributeError:
pass
Page.bindings = []
Page.bindings.append(Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress))
if not G2frame.PickId:
print('No plot, G2frame.PickId,G2frame.PatternId=',G2frame.PickId,G2frame.PatternId)
return
elif 'PWDR' in G2frame.GPXtree.GetItemText(G2frame.PickId):
Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
Phases = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId,'Reflection Lists'))
Page.phaseList = sorted(Phases.keys()) # define an order for phases (once!)
G2frame.Bind(wx.EVT_MENU, onMoveDiffCurve, id=G2frame.dataWindow.moveDiffCurve.GetId())
G2frame.Bind(wx.EVT_MENU, onMoveTopTick, id=G2frame.dataWindow.moveTickLoc.GetId())
G2frame.Bind(wx.EVT_MENU, onMoveTickSpace, id=G2frame.dataWindow.moveTickSpc.GetId())
G2frame.Bind(wx.EVT_MENU, onSetPlotLim, id=G2frame.dataWindow.setPlotLim.GetId())
G2frame.Bind(wx.EVT_MENU, onPlotFormat, id=G2frame.dataWindow.setPlotFmt.GetId())
G2frame.Bind(wx.EVT_MENU, onHKLabelConfig, id=G2G.wxID_CHHKLLBLS)
if len(G2frame.Refine): # extend state for new menus to match main
state = G2frame.Refine[0].IsEnabled()
else:
state = False
G2frame.Bind(wx.EVT_MENU, onPartialConfig, id=G2G.wxID_CHPHPARTIAL)
G2frame.PartialConfig.Enable(state)
G2frame.Bind(wx.EVT_MENU, G2frame.OnSavePartials, id=G2G.wxID_PHPARTIALCSV)
G2frame.PartialCSV.Enable(state) # disabled during sequential fits
G2frame.dataWindow.moveDiffCurve.Enable(False)
G2frame.dataWindow.moveTickLoc.Enable(False)
G2frame.dataWindow.moveTickSpc.Enable(False)
elif plottype in ['SASD','REFD']:
Page.phaseList = Phases = []
elif G2frame.GPXtree.GetItemText(G2frame.PickId) in ['Reflection Lists','Limits']:
# get reflection positions for other places where they are displayed
Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
Phases = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId,'Reflection Lists'))
Page.phaseList = sorted(Phases.keys()) # define an order for phases (once!)
elif G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Peak List':
G2frame.Bind(wx.EVT_MENU, onMovePeak, id=G2frame.dataWindow.movePeak.GetId())
Page.phaseList = Phases = []
if inXtraPeakMode:
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 = []
# assemble a list of validated colors for tickmarks
valid_colors = []
invalid_colors = []
for color in GSASIIpath.GetConfigValue('Ref_Colors',getDefault=True).split():
try:
if mpl.colors.is_color_like(color):
valid_colors.append(color)
else:
invalid_colors.append(color)
except:
pass
if invalid_colors and not hasattr(Page,'phaseColors'): # show error once
print(f'**** bad color code(s): "{", ".join(invalid_colors)}" - redo Preferences/Ref_Colors ****')
if len(valid_colors) < 3:
refColors=['b','r','c','g','m','k']
else:
refColors = valid_colors
if not hasattr(Page,'phaseColors'): Page.phaseColors = {}
for i,p in enumerate(Phases):
Page.phaseColors[p] = Page.phaseColors.get(p,refColors[i%len(refColors)])
# save information needed to reload from tree and redraw
try:
if not refineMode:
kwargs={'PatternName':G2frame.GPXtree.GetItemText(G2frame.PatternId)}
if G2frame.PickId:
kwargs['PickName'] = G2frame.GPXtree.GetItemText(G2frame.PickId)
wx.CallAfter(G2frame.G2plotNB.RegisterRedrawRoutine(G2frame.G2plotNB.lastRaisedPlotTab,ReplotPattern,
(G2frame,newPlot,plotType),kwargs))
except: #skip a C++ error
pass
# now start plotting
G2frame.G2plotNB.status.DestroyChildren() #get rid of special stuff on status bar
G2frame.G2plotNB.status.SetStatusText(IndxFrom,1)
# TODO: figure out why the SetHelpButton creates a second tab line (BHT, Mac, wx4.1)
#G2frame.G2plotNB.SetHelpButton(G2frame.dataWindow.helpKey)
Page.tickDict = {}
DifLine = ['']
ifLimits = False
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Limits':
ifLimits = True
Page.plotStyle['qPlot'] = False
Page.plotStyle['dPlot'] = False
# Setup list of keypress keys in use for the current plot type
# 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
if G2frame.Contour:
Page.Choice = (' key press','b: toggle subtract background',
'd: lower contour max','u: raise contour max',
'D: lower contour min','U: raise contour min',
'o: reset contour limits','g: toggle grid',
'i: interpolation method','S: color scheme','c: contour off',
'e: toggle temperature for y-axis','s: toggle sqrt plot',
'w: toggle w(Yo-Yc) contour plot','h: toggle channel # plot',
'q: toggle Q plot','t: toggle d-spacing plot',
'C: contour plot control window',
)
else:
if 'PWDR' in plottype:
Page.Choice = [' key press',
'a: add magnification region','b: toggle subtract background',
'c: contour on','x: toggle excluded regions','T: toggle plot title',
'f: toggle full-length ticks','g: toggle grid',
'X: toggle cumulative chi^2',
'm: toggle multidata plot','n: toggle log(I)',]
if plotOpt['obsInCaption']:
addrem = 'remove'
else:
addrem = 'add'
if G2frame.SinglePlot:
what = "obs, calc,..."
else:
what = "histogram names"
Page.Choice += [f'L: {addrem} {what} in legend',]
if ifLimits:
Page.Choice += ['e: create excluded region',
's: toggle sqrt plot','w: toggle (Io-Ic)/sig plot',
'+: toggle obs line plot']
else:
Page.Choice += [
'q: toggle Q plot','t: toggle d-spacing plot',
's: toggle sqrt plot','w: toggle (Io-Ic)/sig plot',
'+: toggle obs line plot']
if G2frame.GPXtree.GetItemText(G2frame.PickId) in ['Peak List','Index Peak List']:
Page.Choice += ['d: highlight next peak in list']
Page.Choice += ['u: highlight previous peak in list']
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Background':
Page.Choice += ['k: toggle fixed-background mode (add/move/delete)']
if Page.plotStyle['sqrtPlot'] or Page.plotStyle['logPlot']:
del Page.Choice[1]
del Page.Choice[1]
elif not G2frame.SinglePlot:
del Page.Choice[1]
if not G2frame.SinglePlot:
Page.Choice = Page.Choice+ \
['u/U: offset up/10x','d/D: offset down/10x','l: offset left','r: offset right',
'o: reset offset','F: select data','/: normalize']
else:
Page.Choice = Page.Choice+ ['p: toggle partials (if available)',]
if G2frame.SinglePlot:
Page.Choice += ['v: CSV output of plot']
Page.Choice += ['!: Save settings as default for histogram']
elif plottype in ['SASD','REFD']:
Page.Choice = [' key press',
'b: toggle subtract background file','g: toggle grid',
'm: toggle multidata plot','n: toggle semilog/loglog',
'q: toggle S(q) plot','w: toggle (Io-Ic)/sig plot','+: toggle obs line plot',]
if not G2frame.SinglePlot:
Page.Choice = Page.Choice+ \
['u: offset up','d: offset down','l: offset left',
'r: offset right','o: reset offset',]
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
G2frame.cid = None
Page.keyPress = OnPlotKeyPress
# assemble a list of validated colors (not currently needed)
# valid_colors = []
# invalid_colors = []
# try:
# colors = GSASIIpath.GetConfigValue('Plot_Colors').split()
# for color in colors:
# #if color not in ['k','r','g','b','m','c']:
# if mpl.colors.is_color_like(color):
# valid_colors.append(color)
# else:
# invalid_colors.append(color)
# except:
# pass
# if invalid_colors:
# print(f'**** bad color code(s): "{", ".join(invalid_colors)}" - redo Preferences/Plot Colors ****')
# if len(valid_colors) < 3:
# colors = ['b','g','r','c','m','k']
# else:
# colors = valid_colors
Lines = []
exclLines = []
time0 = time.time()
if G2frame.SinglePlot and G2frame.PatternId:
try:
Pattern = G2frame.GPXtree.GetItemPyData(G2frame.PatternId)
Pattern.append(G2frame.GPXtree.GetItemText(G2frame.PatternId))
PlotList = [Pattern,]
# PId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Background')
# Pattern[0]['BackFile'] = ['',-1.0,False]
# if PId:
# Pattern[0]['BackFile'] = G2frame.GPXtree.GetItemPyData(PId)[1].get('background PWDR',['',-1.0,False])
Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,
G2frame.PatternId, 'Instrument Parameters'))
Sample = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Sample Parameters'))
Limits = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits'))
ParmList = [Parms,]
SampleList = [Sample,]
LimitsList = [Limits,]
Title = Pattern[-1]
if data[0].get('histTitle'): Title = data[0]['histTitle']
except AttributeError:
pass
else: #G2frame.selection
Title = os.path.split(G2frame.GSASprojectfile)[1]
if G2frame.selections is None:
choices = G2gd.GetGPXtreeDataNames(G2frame,plotType)
else:
choices = G2frame.selections
PlotList = []
ParmList = []
SampleList = []
LimitsList = []
Temps = []
# loop through tree looking for matching histograms to plot
Id, cookie = G2frame.GPXtree.GetFirstChild(G2frame.root)
while Id:
name = G2frame.GPXtree.GetItemText(Id)
pid = Id
Id, cookie = G2frame.GPXtree.GetNextChild(G2frame.root, cookie)
if name not in choices: continue
Pattern = G2frame.GPXtree.GetItemPyData(pid)
if len(Pattern) < 3: # put name on end if needed
Pattern.append(G2frame.GPXtree.GetItemText(pid))
if 'Offset' not in Page.plotStyle: #plot offset data
Ymax = max(Pattern[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),})
# PId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Background')
# Pattern[0]['BackFile'] = ['',-1.0,False]
# if PId:
# Pattern[0]['BackFile'] = G2frame.GPXtree.GetItemPyData(PId)[1].get('background PWDR',['',-1.0,False])
PlotList.append(Pattern)
ParmList.append(G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,
pid,'Instrument Parameters'))[0])
SampleList.append(G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,
pid, 'Sample Parameters')))
LimitsList.append(G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,
pid, 'Limits')))
Temps.append('%.1fK'%SampleList[-1]['Temperature'])
if not G2frame.Contour:
PlotList.reverse()
ParmList.reverse()
SampleList.reverse()
LimitsList.reverse()
if timeDebug:
print('plot build time: %.3f for %dx%d patterns'%(time.time()-time0,len(PlotList[0][1][1]),len(PlotList)))
lenX = 0 # length of first histogram, used for contour plots
Ymax = None
for ip,Pattern in enumerate(PlotList):
xye = Pattern[1]
try:
xye = np.nan_to_num(xye)
except ValueError:
print('Error in diffraction pattern',ip,'skipping plot')
continue
if xye[1] is None: continue
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]
if Page.plotStyle['logPlot']:
Title = 'log('+Title+')'
elif Page.plotStyle['sqrtPlot']:
Title = r'$\sqrt{I}$ for '+Title
Ymax = np.sqrt(Ymax)
elif Page.plotStyle.get('WgtDiagnostic',False):
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:
xLabel = r'$Q, \AA^{-1}$'
elif Page.plotStyle['dPlot'] and 'PWDR' in plottype and not ifLimits:
xLabel = r'$d, \AA$'
elif Page.plotStyle['chanPlot'] and G2frame.Contour:
xLabel = 'Channel no.'
else:
if 'T' in ParmList[0]['Type'][0]:
xLabel = r'$TOF, \mathsf{\mu}$s'
elif 'E' in ParmList[0]['Type'][0]:
xLabel = 'E, keV'
else:
xLabel = r'$\mathsf{2\theta}$'
if 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:
Plot,Plot1 = Page.figure.subplots(2,1,sharex=True,gridspec_kw=GS_kw)
# except AttributeError: # figure.Figure.subplots added in MPL 2.2
# 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)
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):
if Page.plotStyle['sqrtPlot']:
Plot.set_ylabel(r'$\sqrt{Normalized\ intensity}$',fontsize=16)
else:
Plot.set_ylabel(r'$Normalized\ intensity$',fontsize=16)
else: #neutron TOF
if 'PWDR' in plottype:
if Page.plotStyle['sqrtPlot']:
Plot.set_ylabel(r'$\sqrt{Intensity}$',fontsize=16)
elif Page.plotStyle.get('WgtDiagnostic',False):
Plot.set_ylabel('Intensity * Weight')
elif G2frame.CumeChi and G2frame.SinglePlot:
Plot.set_ylabel(r'$Intensity, cum('+Gkchisq+')$',fontsize=16)
else:
Plot.set_ylabel(r'$Intensity$',fontsize=16)
elif plottype == 'SASD':
if Page.plotStyle['sqPlot']:
Plot.set_ylabel(r'$S(Q)=I*Q^{4}$',fontsize=16)
else:
Plot.set_ylabel(r'$Intensity,\ cm^{-1}$',fontsize=16)
elif plottype == 'REFD':
if Page.plotStyle['sqPlot']:
Plot.set_ylabel(r'$S(Q)=R*Q^{4}$',fontsize=16)
else:
Plot.set_ylabel(r'$Reflectivity$',fontsize=16)
mpl.rcParams['image.cmap'] = G2frame.ContourColor
mcolors = mpl.cm.ScalarMappable() #wants only default as defined in previous line!!
mcolors.set_array([]) # needed for MPL <=3.0.x
if G2frame.Contour:
ContourZ = []
ContourY = []
ContourX = None
Xlist = []
X0 = None
Nseq = 0
Nmax = len(PlotList)-1
time0 = time.time()
Plot.figure.subplots_adjust(right=.95)
if G2frame.Contour and G2frame.TforYaxis:
Plot.set_ylabel('Temperature',fontsize=14)
elif G2frame.Contour:
Plot.set_ylabel('Data sequence',fontsize=14)
unequalArrays = False # set to True for contour plots with unequal pixels
avgStep = None
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:
X = 2.*np.pi/G2lat.Pos2dsp(Parms,xye[0])
elif Page.plotStyle['dPlot'] and 'PWDR' in plottype and not ifLimits:
X = G2lat.Pos2dsp(Parms,xye[0])
else:
X = copy.deepcopy(xye[0])
if not X0:
X0 = X[0] # save 1st point in 1st pattern
elif abs(X0 - X[0]) > 0.05 * X0:
unequalArrays = True
if Page.plotStyle['qPlot'] or Page.plotStyle['dPlot']: # not in original units
unequalArrays = True
elif 'T' in ParmList[0]['Type'][0] and not Page.plotStyle['chanPlot']: # assume TOF is non-linear steps
unequalArrays = True
# check to see if the average step size changes across the selected patterns
elif avgStep is None and not unequalArrays:
avgStep = (X[-1]-X[0])/(len(X)-1)
elif not unequalArrays and abs(avgStep - (X[-1]-X[0])/(len(X)-1)) > 0.05 * avgStep:
unequalArrays = True
ExMask = []
for N,Pattern in enumerate(PlotList):
Parms = ParmList[N]
Sample = SampleList[N]
limits = np.array(LimitsList[N])
ifpicked = False
NoffY = offsetY*(Nmax-N)
if Pattern[1] is None: continue # skip over uncomputed simulations
xye = np.array(ma.getdata(Pattern[1])) # strips mask = X,Yo,W,Yc,Yb,Yd
ExMask.append(np.full(len(xye[0]),False))
if G2frame.PickId: # when is this not true?
ifpicked = Pattern[2] == G2frame.GPXtree.GetItemText(G2frame.PatternId)
# recompute mask from excluded regions, in case they have changed
xye0 = xye[0] # no mask in case there are no limits
for excl in limits[2:]:
xye0 = ma.masked_inside(xye[0],excl[0],excl[1],copy=False) #excluded region mask
if unequalArrays:
xye0 = ma.masked_outside(xye[0],limits[1][0],limits[1][1],copy=False) #now mask for limits
Lmask = ma.getmask(xye0) # limits applied
ExMask[N] = ExMask[N][~Lmask] # drop points outside limits
elif not G2frame.Contour:
xye0 = ma.masked_outside(xye0,limits[1][0],limits[1][1],copy=False) #now mask for limits
else:
xye0 = Pattern[1][0] # keeps mask
Lmask = Emask = np.full(len(xye0),False)
if G2frame.Contour:
xye0 = xye[0] # drop mask for contouring
# convert all X values and then reapply mask if xye0 is a masked array
mask = None
if hasattr(xye0,'mask'):
mask = xye0.mask
X = xye0.data
else:
mask = None
X = xye0
if Page.plotStyle['qPlot'] and 'PWDR' in plottype and not ifLimits:
X = ma.array(2.*np.pi/G2lat.Pos2dsp(Parms,X),mask=mask)
elif Page.plotStyle['dPlot'] and 'PWDR' in plottype and not ifLimits:
X = ma.array(G2lat.Pos2dsp(Parms,X),mask=mask)
else:
X = copy.deepcopy(xye0)
if ifpicked and not G2frame.Contour:
savedX = copy.deepcopy(X)
if not lenX:
lenX = len(X)
# show plot magnification factors
magMarkers = []
Plot.magLbls = []
multArray = np.ones_like(Pattern[1][0])
if 'PWDR' in plottype and G2frame.SinglePlot and not (
Page.plotStyle['logPlot'] or Page.plotStyle['sqrtPlot'] or G2frame.Contour):
if not refineMode:
magLineList = data[0].get('Magnification',[])
if ('C' in ParmList[0]['Type'][0] and Page.plotStyle['dPlot']) or (
'B' in ParmList[0]['Type'][0] and Page.plotStyle['dPlot']) or (
'E' in ParmList[0]['Type'][0] and Page.plotStyle['dPlot']) or (
'T' in ParmList[0]['Type'][0] and Page.plotStyle['qPlot']): # reversed regions relative to data order
tcorner = 1
tpos = 1.0
halign = 'right'
else:
tcorner = 0
tpos = 1.0
halign = 'left'
ml0 = None
for x,m in magLineList:
ml = m
if int(m) == m:
ml = int(m)
if x is None:
magMarkers.append(None)
multArray *= m
ml0 = ml
continue
multArray[Pattern[1][0]>x] = m
if Page.plotStyle['qPlot']:
x = 2.*np.pi/G2lat.Pos2dsp(Parms,x)
elif Page.plotStyle['dPlot']:
x = G2lat.Pos2dsp(Parms,x)
# is range in displayed range (defined after newplot)?
if not newPlot:
(xmin,xmax),ylim = G2frame.xylim
if x < xmin:
ml0 = ml
continue
if x > xmax:
continue
# magnification region marker
magMarkers.append(Plot.axvline(x,color='0.5',dashes=(1,1),picker=2.,label='_magline'))
lbl = Plot.annotate("x{}".format(ml), xy=(x, tpos), xycoords=("data", "axes fraction"),
verticalalignment='bottom',horizontalalignment=halign,label='_maglbl')
Plot.magLbls.append(lbl)
if ml0:
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
if G2frame.SubBack:
YI -= xye[4] #background
if Page.plotStyle['sqrtPlot']:
olderr = np.seterr(invalid='ignore') #get around sqrt(-ve) error
Y = np.where(YI>=0.,np.sqrt(YI),-np.sqrt(-YI))+NoffY*Ymax/100.0
np.seterr(invalid=olderr['invalid'])
elif Page.plotStyle.get('WgtDiagnostic',False):
Y = xye[1]*xye[2] #Y-obs*wt
elif 'PWDR' in plottype and G2frame.SinglePlot and not (
Page.plotStyle['logPlot'] or Page.plotStyle['sqrtPlot'] or G2frame.Contour):
Y = YI*multArray+NoffY*Ymax/100.0
else:
Y = YI+NoffY*Ymax/100.0
elif plottype in ['SASD','REFD']:
if plottype == 'SASD':
B = xye[5] #Yo - Yc
else:
B = np.zeros_like(xye[5])
if Page.plotStyle['sqPlot']:
Y = xye[1]*Sample['Scale'][0]*(1.05)**NoffY*X**4
else:
Y = xye[1]*Sample['Scale'][0]*(1.05)**NoffY
if Page.plotStyle['exclude']:
Y = ma.array(Y,mask=ma.getmask(X))
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:
lims = 2.*np.pi/G2lat.Pos2dsp(Parms,lims)
elif Page.plotStyle['dPlot'] and 'PWDR' in plottype and not ifLimits:
lims = G2lat.Pos2dsp(Parms,lims)
# limit lines
Lines.append(Plot.axvline(lims[0][0],color='g',dashes=(5,5),picker=3.))
Lines.append(Plot.axvline(lims[0][1],color='r',dashes=(5,5),picker=3.))
# excluded region lines
for i,item in enumerate(lims[1:]):
Lines.append(Plot.axvline(item[0],color='m',dashes=(6,3),picker=3.))
Lines.append(Plot.axvline(item[1],color='m',dashes=(6,3),picker=3.))
exclLines += [2*i+2,2*i+3]
if G2frame.Contour:
if Page.plotStyle['chanPlot']:
if unequalArrays:
X = np.array(range(len(X)),float)
else:
X = np.array(range(lenX),float)
Lmask = Emask = np.full(len(X),False)
if G2frame.Weight:
Ytmp = (xye[1]-xye[3])*np.sqrt(xye[2])
else:
Ytmp = Y
# pad or truncate arrays when plotting with mpl.imshow
if unequalArrays:
ContourZ.append(ma.MaskedArray(Ytmp,Lmask).compressed())
elif len(Y) < lenX:
Yext = np.ones(lenX)*Ytmp[-1]
Yext[:len(X)] = Ytmp
ContourZ.append(Yext)
elif len(Y) > lenX:
ContourZ.append(Ytmp[:lenX])
else:
ContourZ.append(Ytmp)
#if unequalArrays and G2frame.TforYaxis:
# TODO: could set this to temperature and then plot
# against temperature, but this only works if patterns are sorted by T
ContourY.append(N)
if unequalArrays:
Xlist.append(ma.MaskedArray(X,Lmask).compressed())
elif ContourX is None:
ContourX = X
Nseq += 1
else: # not contour plot
if not G2frame.plusPlot:
pP = ''
lW = 1.5
elif G2frame.plusPlot == 1:
pP = '+'
lW = 0
elif G2frame.plusPlot == 2: # same as 0 for multiplot, TODO: rethink
pP = ''
lW = 1.5
else:
pP = '+'
lW = 1.5
if plottype in ['SASD','REFD'] and Page.plotStyle['logPlot']:
X *= (1.01)**(offsetX*N)
else:
xlim = Plot.get_xlim()
DX = xlim[1]-xlim[0]
X += 0.002*offsetX*DX*N
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Limits':
Xum = ma.getdata(X) # unmasked version of X, use for data limits (only)
else:
Xum = X[:]
if ifpicked: # plotting of "master" pattern (histogram selected in data tree)
ZI = copy.copy(xye[3]) #Yc
if Page.plotStyle['sqrtPlot']:
olderr = np.seterr(invalid='ignore') #get around sqrt(-ve) error
Z = np.where(ZI>=0.,np.sqrt(ZI),-np.sqrt(-ZI))
np.seterr(invalid=olderr['invalid'])
else:
if 'PWDR' in plottype and G2frame.SinglePlot and not (
Page.plotStyle['logPlot'] or Page.plotStyle['sqrtPlot'] or G2frame.Contour):
Z = ZI*multArray+NoffY*Ymax/100.0 #yc
else:
Z = ZI+NoffY*Ymax/100.0 #yc
if 'PWDR' in plottype:
if Page.plotStyle['sqrtPlot']:
olderr = np.seterr(invalid='ignore') #get around sqrt(-ve) error
W = np.where(xye[4]>=0.,np.sqrt(xye[4]),-np.sqrt(-xye[4])) #yb
np.seterr(invalid=olderr['invalid'])
D = np.where(xye[5],(Y-Z),0.)-Page.plotStyle['delOffset']
elif Page.plotStyle.get('WgtDiagnostic',False):
Z = D = W = np.zeros_like(Y)
elif G2frame.SinglePlot and not (
Page.plotStyle['logPlot'] or Page.plotStyle['sqrtPlot'] or G2frame.Contour):
W = xye[4]*multArray+NoffY*Ymax/100.0 #yb
D = multArray*xye[5]-Page.plotStyle['delOffset'] #Yo-Yc
else:
W = xye[4]+NoffY*Ymax/100.0 #yb
D = xye[5]-Page.plotStyle['delOffset'] #Yo-Yc
elif plottype in ['SASD','REFD']:
if Page.plotStyle['sqPlot']:
W = xye[4]*X**4 #Yb
Z = xye[3]*X**4 #Yc
B = B*X**4 #(yo-Yc)*x**4
else:
W = xye[4] #Yb
if G2frame.SubBack:
YB = Y-B
ZB = Z
else:
YB = Y
ZB = Z+B
try:
Plot.set_yscale("log",nonpositive='mask') # >=3.3
except:
Plot.set_yscale("log",nonpositive='mask')
if np.any(W>0.):
lims = [np.min(np.trim_zeros(W))/2.,np.max(Y)*2.]
else:
lims = [np.min(np.trim_zeros(YB))/2.,np.max(Y)*2.]
if all(np.isfinite(lims)):
Plot.set_ylim(bottom=lims[0],top=lims[1])
# Matplotlib artist lists used for refPlotUpdate
ObsLine = None
CalcLine = None
BackLine = None
DifLine = [None]
if 'PWDR' in plottype and len(limits[2:]): # compute mask for excluded regions
Emask = copy.deepcopy(ma.getmask(X))
for excl in limits[2:]:
Emask += ma.getmask(ma.masked_inside(xye[0],excl[0],excl[1],copy=False))
if Page.plotStyle['exclude']: # optionally apply mask
Xum = ma.array(Xum,mask=Emask)
X = ma.array(X,mask=Emask)
Y = ma.array(Y,mask=Emask)
Z = ma.array(Z,mask=Emask)
W = ma.array(W,mask=Emask)
D = ma.array(D,mask=Emask) # difference plot is always masked
if G2frame.Weight:
Plot1.set_yscale("linear")
wtFactor = Pattern[0]['wtFactor']
if plottype in ['SASD','REFD']:
DZ = (Y-B-Z)*np.sqrt(wtFactor*xye[2])
else:
DZ = (xye[1]-xye[3])*np.sqrt(wtFactor*xye[2])
if 'PWDR' in plottype and len(limits[2:]):
DZ = ma.array(DZ,mask=Emask) # weighted difference is always masked
DifLine = Plot1.plot(X,DZ,pwdrCol['Diff_color'],picker=1.,label=incCptn('diff')) #(Io-Ic)/sig(Io)
Plot1.tick_params(labelsize=14)
Plot1.axhline(0.,color='k')
if Page.plotStyle['logPlot']:
if 'PWDR' in plottype:
try:
Plot.set_yscale("log",nonpositive='mask') # >=3.3
except:
Plot.set_yscale("log",nonpositive='mask')
Plot.plot(X,Y,marker=pP,color=pwdrCol['Obs_color'],linewidth=lW,picker=3.,
clip_on=Clip_on,label=incCptn('obs'))
if G2frame.SinglePlot or G2frame.plusPlot == 1 or G2frame.plusPlot == 2:
Plot.plot(X,Z,pwdrCol['Calc_color'],label=incCptn('calc'),linewidth=1.5)
if G2frame.plusPlot:
Plot.plot(X,W,pwdrCol['Bkg_color'],label=incCptn('bkg'),linewidth=1.5) #background
elif plottype in ['SASD','REFD']:
try:
Plot.set_xscale("log",nonpositive='mask') # >=3.3
Plot.set_yscale("log",nonpositive='mask')
except:
Plot.set_xscale("log",nonpositive='mask')
Plot.set_yscale("log",nonpositive='mask')
if G2frame.ErrorBars:
if Page.plotStyle['sqPlot']:
Plot.errorbar(X,YB,yerr=X**4*Sample['Scale'][0]*np.sqrt(1./(Pattern[0]['wtFactor']*xye[2])),
ecolor=pwdrCol['Obs_color'],picker=3.,clip_on=Clip_on)
else:
Plot.errorbar(X,YB,yerr=Sample['Scale'][0]*np.sqrt(1./(Pattern[0]['wtFactor']*xye[2])),
ecolor=pwdrCol['Obs_color'],picker=3.,clip_on=Clip_on,label=incCptn('obs'))
else:
Plot.plot(X,YB,marker=pP,color=pwdrCol['Obs_color'],linewidth=lW,
picker=3.,clip_on=Clip_on,label=incCptn('obs'))
Plot.plot(X,W,pwdrCol['Calc_color'],label=incCptn('bkg'),linewidth=1.5) #const. background
Plot.plot(X,ZB,pwdrCol['Bkg_color'],label=incCptn('calc'),linewidth=1.5)
else: # not logPlot
ymax = 1.
if Page.plotStyle['Normalize'] and Y.max() != 0 and not G2frame.SinglePlot:
ymax = Y.max()
if G2frame.SubBack:
if 'PWDR' in plottype:
ObsLine = Plot.plot(Xum,Y/ymax,color=pwdrCol['Obs_color'],marker=pP,linewidth=lW,
clip_on=Clip_on,label=incCptn('obs-bkg')) #Io-Ib
if np.any(Z): #only if there is a calc pattern
CalcLine = Plot.plot(X,(Z-W)/ymax,pwdrCol['Calc_color'],
label=incCptn('calc-bkg'),linewidth=1.5) #Ic-Ib
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'],label=incCptn('calc'),linewidth=1.5)
else:
if 'PWDR' in plottype:
if G2frame.plusPlot != 3:
ObsLine = Plot.plot(Xum,Y/ymax,color=pwdrCol['Obs_color'],marker=pP,linewidth=lW,
picker=3.,clip_on=Clip_on,label=incCptn('obs')) #Io
CalcLine = Plot.plot(X,Z/ymax,pwdrCol['Calc_color'],
label=incCptn('calc'),linewidth=1.5) #Ic
else: # waterfall mode=3: plot 1st pattern like others, name in legend?
name = Pattern[2]
if Pattern[0].get('histTitle'): name = Pattern[0]['histTitle']
ObsLine = Plot.plot(Xum,Y/ymax,color=pwdrCol['Obs_color'],marker='',linewidth=1.5,
clip_on=Clip_on,label=incCptn(name)) #Io
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)
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
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
Plot.axhline(0.,color='k',label='_zero')
Plot.tick_params(labelsize=14)
# write a .csv file; not fully tested, but probably works where allowed
if 'PWDR' in plottype and G2frame.SinglePlot and plotOpt['saveCSV']:
plotOpt['saveCSV'] = False
fp = open(plotOpt['CSVfile'],'w')
G2plt.Write2csv(fp,['"limits"',lims[0][0],lims[0][1]])
l = []
PeakId = G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Peak List')
peaks = G2frame.GPXtree.GetItemPyData(PeakId)
if inXtraPeakMode:
tbl = peaks['xtraPeaks']
else:
tbl = peaks['peaks']
for i,item in enumerate(tbl):
if type(item) is dict: continue
pos = item[0]
if Page.plotStyle['qPlot']:
l.append(2.*np.pi/G2lat.Pos2dsp(Parms,pos))
elif Page.plotStyle['dPlot']:
l.append(G2lat.Pos2dsp(Parms,pos))
else:
l.append(pos)
if l: G2plt.Write2csv(fp,['"peaks"']+l)
peaks['LaueFringe'] = peaks.get('LaueFringe',{})
l = []
for pos in peaks['LaueFringe'].get('satellites',[]):
if Page.plotStyle['qPlot']:
l.append(2.*np.pi/G2lat.Pos2dsp(Parms,pos))
elif Page.plotStyle['dPlot']:
l.append(G2lat.Pos2dsp(Parms,pos))
else:
l.append(pos)
if l: G2plt.Write2csv(fp,['"satellites"']+l)
G2plt.Write2csv(fp,['masked X','X','obs','calc','bkg','diff'],header=True)
for i in range(len(X)):
if hasattr(X,'mask'):
G2plt.Write2csv(fp,[X[i],X.data[i],Y[i],Z[i],W[i],D[i]],header=False)
else:
G2plt.Write2csv(fp,[X[i],X[i],Y[i],Z[i],W[i],D[i]],header=False)
fp.close()
print('file',plotOpt['CSVfile'],'written')
Page.SetToolTipString('')
if G2frame.PickId:
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Peak List':
tip = 'On data point: Pick peak - L or R MB. On line: L-move, R-delete'
Page.SetToolTipString(tip)
peaks = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
if inXtraPeakMode:
peaks['xtraPeaks'] = peaks.get('xtraPeaks',[])
tbl = peaks['xtraPeaks']
color = 'r'
else:
tbl = peaks['peaks']
color = 'b'
try:
# find any peak rows that are selected
selectedPeaks = list(set(
[row for row,col in G2frame.reflGrid.GetSelectedCells()] +
G2frame.reflGrid.GetSelectedRows()))
# G2frame.dataWindow.movePeak.Enable(len(selectedPeaks) == 1) # allow peak move from table when one peak is selected
for i,item in enumerate(tbl):
if type(item) is dict: continue
if i in selectedPeaks:
#Ni = N+1
plotVline(Page,Plot,Lines,Parms,item[0],'yellow',0,'-')
Lines[-1].set_lw(Lines[-1].get_lw()+1)
plotVline(Page,Plot,Lines,Parms,item[0],color,2)
Lines[-1].set_lw(Lines[-1].get_lw()+1)
else:
#Ni = N
plotVline(Page,Plot,Lines,Parms,item[0],color,2)
except:
pass
peaks['LaueFringe'] = peaks.get('LaueFringe',{})
SatLines = []
for pos in peaks['LaueFringe'].get('satellites',[]):
plotVline(Page,Plot,SatLines,Parms,pos,'k',2)
# for pos in peaks['xtraPeaks']:
# plotVline(Page,Plot,Lines,Parms,pos[0],'r',0)
if G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Limits':
tip = 'On data point: Lower limit - L MB; Upper limit - R MB. On limit: MB down to move'
Page.SetToolTipString(tip)
limits = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Limits')) # used anywhere?
else: #not picked
ymax = 1.
if Page.plotStyle['Normalize'] and Y.max() != 0:
ymax = Y.max()
icolor = 256*N//len(PlotList)
if Page.plotStyle['logPlot']:
if 'PWDR' in plottype:
try: # >=3.3
Plot.semilogy(X,Y,color=mcolors.cmap(icolor),nonpositive='mask',linewidth=1.5)
except:
Plot.semilogy(X,Y,color=mcolors.cmap(icolor),nonpositive='mask')
elif plottype in ['SASD','REFD']:
try:
Plot.semilogy(X,Y,color=mcolors.cmap(icolor),nonpositive='mask',linewidth=1.5)
except:
Plot.semilogy(X,Y,color=mcolors.cmap(icolor),nonpositive='mask')
else:
if 'PWDR' in plottype:
# 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))
elif plottype in ['SASD','REFD']:
try:
Plot.loglog(X,Y,mcolors.cmap(icolor),nonpositive='mask',linewidth=1.5)
except:
Plot.loglog(X,Y,mcolors.cmap(icolor),nonpositive='mask')
Plot.set_ylim(bottom=np.min(np.trim_zeros(Y))/2.,top=np.max(Y)*2.)
if Page.plotStyle['logPlot'] and 'PWDR' in plottype:
Plot.set_ylim(bottom=np.min(np.trim_zeros(Y))/2.,top=np.max(Y)*2.)
#============================================================
# plot HKL labels
data[0]['HKLconfig'] = data[0].get('HKLconfig',{})
alpha = data[0]['HKLconfig'].get('alpha',2)
font = int(data[0]['HKLconfig'].get('Font','8'))
angle = int(90 * data[0]['HKLconfig'].get('Orientation',0))
props = dict(boxstyle='round,pad=0.15', facecolor='#ccc',
alpha=(4 - alpha)/4., ec='#ccc')
markHKLs = (G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Reflection Lists' or
'PWDR' in G2frame.GPXtree.GetItemText(G2frame.PickId) or refineMode
or (inXtraPeakMode and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Peak List'))
for ph,markerlist in data[0].get('HKLmarkers',{}).items():
if Page.plotStyle['logPlot'] or not markHKLs: continue
if ph not in Page.phaseColors: continue
color = Page.phaseColors[ph]
for key,(ypos,hkls) in markerlist.items():
if len(hkls) == 0: continue
comma = False # are commas needed?
for hkl in hkls:
if np.any([True for i in hkl if abs(i) > 9]):
comma = True
break
lbl = ''
for hkl in hkls:
hkllbl = ''
if lbl: lbl += '\n'
for i in hkl:
if hkllbl and comma: hkllbl += ','
if i < 0:
lbl += r'$\overline{' + f'{-i}' + r'}$'
else:
lbl += f'{i}'
xpos = float(key)
if Page.plotStyle['qPlot']:
xpos = 2.*np.pi/G2lat.Pos2dsp(Parms,xpos)
elif Page.plotStyle['dPlot']:
xpos = G2lat.Pos2dsp(Parms,xpos)
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)
artist.key = (ph,key)
#============================================================
if timeDebug:
print('plot fill time: %.3f'%(time.time()-time0))
if Page.plotStyle.get('title',True) and not magLineList:
Plot.set_title(Title)
if G2frame.PickId and not G2frame.Contour:
Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
orange = [255/256.,128/256.,0.]
if 'PWDR' in plottype and G2frame.SinglePlot and G2frame.CumeChi:
CY = np.cumsum(W**2*(Y-Z)**2)
scale = np.max(CY)/np.max(Y)
CY /= scale
Plot.plot(X,CY,'k',label='cum('+Gkchisq+')')
selectedPeaks = []
if G2frame.GPXtree.GetItemText(G2frame.PickId) in ['Index Peak List']:
# find any peak rows that are selected
selectedPeaks = list(set(
[row for row,col in G2frame.indxPeaks.GetSelectedCells()] +
G2frame.indxPeaks.GetSelectedRows()))
if G2frame.GPXtree.GetItemText(G2frame.PickId) in ['Index Peak List','Unit Cells List']:
peaks = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
if len(peaks): # are there any peaks?
for i,peak in enumerate(peaks[0]):
if Page.plotStyle['qPlot']:
x = 2.*np.pi/G2lat.Pos2dsp(Parms,peak[0])
elif Page.plotStyle['dPlot']:
x = G2lat.Pos2dsp(Parms,peak[0])
else:
x = peak[0]
if i in selectedPeaks:
Plot.axvline(x,color='yellow',lw=2)
if peak[2]:
if i in selectedPeaks:
Plot.axvline(x,color='yellow',lw=2)
Plot.axvline(x,color='b',lw=2,ls='dotted')
else:
Plot.axvline(x,color='b')
for hkl in G2frame.HKL:
clr = orange
dash = (3,3)
if len(hkl) > 6 and hkl[3]:
clr = 'g'
hklind = G2frame.PlotOpts.get('hklHighlight',0)
if hklind != 0: # highlight selected classes of reflections
if hkl[hklind-1] != 0:
clr = 'b'
dash = (5,2)
if Page.plotStyle['qPlot']:
Plot.axvline(2.*np.pi/G2lat.Pos2dsp(Parms,hkl[-2]),color=clr,dashes=dash,lw=1.5)
elif Page.plotStyle['dPlot']:
Plot.axvline(G2lat.Pos2dsp(Parms,hkl[-2]),color=clr,dashes=dash,lw=1.5)
else:
Plot.axvline(hkl[-2],color=clr,dashes=dash,lw=1.5)
for hkl in G2frame.Extinct: # plot extinct reflections
clr = 'g'
if Page.plotStyle['qPlot']:
Plot.axvline(2.*np.pi/G2lat.Pos2dsp(Parms,hkl[-2]),color=clr,dashes=(3,3),lw=2)
elif Page.plotStyle['dPlot']:
Plot.axvline(G2lat.Pos2dsp(Parms,hkl[-2]),color=clr,dashes=(3,3),lw=2)
else:
Plot.axvline(hkl[-2],color=clr,dashes=(3,3),lw=2)
elif Page.plotStyle.get('WgtDiagnostic',False):
pass # skip reflection markers
elif (G2frame.GPXtree.GetItemText(G2frame.PickId) in ['Reflection Lists','Limits']
or 'PWDR' in G2frame.GPXtree.GetItemText(G2frame.PickId)
or refineMode
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)
handles,legends = Plot.get_legend_handles_labels()
if handles:
labels = dict(zip(legends,handles)) # remove duplicate phase entries
handles = [labels[item] for item in labels]
legends = list(labels.keys())
if len(Phases) and plotOpt['obsInCaption'] and Page.plotStyle.get('flTicks',0) != 2:
msg = 'Data'
elif len(Phases) and plotOpt['obsInCaption']:
msg = 'Phases & Data'
else:
msg = 'Phases'
siz = None
if len(legends) > 50: # make an attempt to make legend contents fit
siz = 4
elif len(legends) > 25:
siz = 6
elif len(legends) > 15:
siz = 8
Plot.legend(handles,legends,title=msg,loc='best',
fontsize=siz)
if G2frame.Contour:
time0 = time.time()
acolor = G2plt.GetColorMap(G2frame.ContourColor)
Vmin = Ymax*G2frame.Cmin
Vmax = Ymax*G2frame.Cmax
if unequalArrays:
if G2frame.Weight:
#Vmin = min([i.min() for i in ContourZ])
Vmin = min([ma.array(i,mask=m).min() for i,m in zip(ContourZ,ExMask)]) # don't count excluded points in limits
#Vmax = max([i.max() for i in ContourZ])
Vmax = max([ma.array(i,mask=m).max() for i,m in zip(ContourZ,ExMask)])
if G2frame.TforYaxis:
imgLbls = Temps
else:
imgLbls = []
uneqImgShow(Plot.figure,Plot,Xlist,ContourZ,cmap=acolor,
vmin=Vmin,vmax=Vmax,Ylbls=imgLbls)
Page.Img = None # don't have an overall image
if G2frame.TforYaxis:
Plot.yaxis.set_label_coords(-.1, .5)
else:
Plot.yaxis.set_label_coords(-.05, .5)
Plot.xaxis.set_label_coords(0.5, -.07)
else:
if G2frame.Weight:
Vmin = np.min(ContourZ)
Vmax = np.max(ContourZ)
Page.Img = Plot.imshow(ContourZ,cmap=acolor,vmin=Vmin,vmax=Vmax,
interpolation=G2frame.Interpolate,extent=[ContourX[0],ContourX[-1],ContourY[0]-.5,ContourY[-1]+.5],
aspect='auto',origin='lower')
if G2frame.TforYaxis:
imgAx = Page.Img.axes
ytics = imgAx.get_yticks()
# ytics = np.where(ytics<len(Temps),ytics,-1)
# imgAx.set_yticks(ytics)
ylabs = [Temps[int(i)] for i in ytics[:-1]]
imgAx.set_yticklabels(ylabs)
Page.figure.colorbar(Page.Img)
if timeDebug:
print('Contour display time: %.3f'%(time.time()-time0))
else:
G2frame.Lines = Lines
G2frame.MagLines = magMarkers
if G2frame.PickId and G2frame.GPXtree.GetItemText(G2frame.PickId) == 'Background':
mag2th = [0]+[x for x,m in data[0].get('Magnification',[])][1:]
magmult = [m for x,m in data[0].get('Magnification',[])]
# plot fixed background points
backDict = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Background'))[1]
try:
Parms,Parms2 = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
except TypeError:
Parms = None
for x,y in backDict.get('FixedPoints',[]):
if magmult:
mult = magmult[np.searchsorted(mag2th, x, side = 'right')-1]
else:
mult = 1.
if G2frame.Weight:
axis = Page.figure.axes[1]
else:
axis = Page.figure.gca()
# "normal" intensity modes only!
if G2frame.SubBack or G2frame.Weight or G2frame.Contour or not G2frame.SinglePlot:
break
if y < 0 and (Page.plotStyle['sqrtPlot'] or Page.plotStyle['logPlot']):
y = axis.get_ylim()[0] # put out of range point at bottom of plot
elif Page.plotStyle['sqrtPlot']:
y = math.sqrt(y)
if Page.plotStyle['qPlot']: #Q - convert from 2-theta
if Parms:
x = 2*np.pi/G2lat.Pos2dsp(Parms,x)
else:
break
elif Page.plotStyle['dPlot']: #d - convert from 2-theta
if Parms:
x = G2lat.Dsp2pos(Parms,x)
else:
break
Plot.plot(x,y*mult,'rD',clip_on=Clip_on,picker=10.)
# plot the partials
plotOpt['lineList'] = ['obs','calc','bkg','zero','diff']
if 'PWDR' in plottype and G2frame.SinglePlot and Page.plotStyle['partials'] and 'hId' in data[0]:
initPartialOpts(Page.phaseColors)
x, yb, ypList = G2frame.LoadPartial(data[0]['hId'])
if x is not None and len(ypList) > 1:
if Page.plotStyle['qPlot']:
x = 2.*np.pi/G2lat.Pos2dsp(Parms,x)
elif Page.plotStyle['dPlot']:
x = G2lat.Pos2dsp(Parms,x)
olderr = np.seterr(invalid='ignore') #get around sqrt(-ve) error
for ph in ypList:
if not partialOpts[ph]['Show']: continue
pcolor = partialOpts[ph]['color']
pwidth = partialOpts[ph]['width']
pLinStyl = partialOpts[ph]['MPLstyle']
if G2frame.SubBack:
y = ypList[ph]
else:
y = ypList[ph]+yb
if Page.plotStyle['sqrtPlot']:
y = np.where(y>=0.,np.sqrt(y),-np.sqrt(-y))
Plot.plot(x,y,pcolor,label=ph,linewidth=pwidth,linestyle=pLinStyl)
if 'PlotDefaults' in data[0] and fromTree: # set plot limists from defaults saved with '!'
#print('setting plot defaults')
(xlim, ylim, styleDict, G2frame.SinglePlot, G2frame.Contour, G2frame.Weight,
G2frame.plusPlot, G2frame.SubBack) = data[0]['PlotDefaults']
Page.toolbar.push_current()
# Page.toolbar.set_history_buttons() # this may be needed to update the zoom buttons (needs test)
# Page.canvas.draw_idle() # schedule an MPL update (needs test)
Plot.set_xlim((xlim[0],xlim[1]))
Plot.set_ylim((ylim[0],ylim[1]))
Page.toolbar.push_current() # why two?
# Page.toolbar.set_history_buttons() # this may be needed to update the zoom buttons (needs test)
# Page.canvas.draw_idle() # schedule an MPL update (needs test)
newPlot = True # prevent carrying limits over from other histograms
if not newPlot:
# this restores previous plot limits (but I'm not sure why there are two .push_current calls)
Page.toolbar.push_current()
# Page.toolbar.set_history_buttons() # this may be needed to update the zoom buttons (needs test)
# Page.canvas.draw_idle() # schedule an MPL update (needs test)
if G2frame.Contour: # for contour plots expand y-axis to include all histograms
G2frame.xylim = (G2frame.xylim[0], (-0.5,len(PlotList)-0.5))
if 'PWDR' in plottype:
Plot.set_xlim(G2frame.xylim[0])
Plot.set_ylim(G2frame.xylim[1])
Page.toolbar.push_current()
# Page.toolbar.set_history_buttons() # this may be needed to update the zoom buttons (needs test)
# Page.canvas.draw_idle() # schedule an MPL update (needs test)
Page.ToolBarDraw()
else:
G2frame.xylim = Plot.get_xlim(),Plot.get_ylim()
Page.canvas.draw()
if G2frame.Contour: # for contour plots remove non-integer yaxis labels as they are a distraction
labels = []
vals = []
for item in Plot.get_yticklabels():
lbl = item.get_text()
try:
val = float(lbl.replace('\u2212', '-'))
if int(val) != val:
continue
elif val < 0 or val > G2frame.xylim[1][1]: # out of range labels not needed
continue
else:
vals.append(val)
labels.append(str(int(val)))
except:
pass
Plot.yaxis.set_ticks(vals,labels)
Page.canvas.draw()
olderr = np.seterr(invalid='ignore') #ugh - this removes a matplotlib error for mouse clicks in log plots
# and sqrt(-ve) in np.where usage
if 'PWDR' in G2frame.GPXtree.GetItemText(G2frame.PickId):
if len(Page.tickDict.keys()) == 1:
G2frame.dataWindow.moveTickLoc.Enable(True)
elif len(Page.tickDict.keys()) > 1:
G2frame.dataWindow.moveTickLoc.Enable(True)
G2frame.dataWindow.moveTickSpc.Enable(True)
if DifLine[0]:
G2frame.dataWindow.moveDiffCurve.Enable(True)
if refineMode: return refPlotUpdate
[docs]
def PublishRietveldPlot(G2frame,Pattern,Plot,Page,reuse=None):
'''Creates a window to show a customizable "Rietveld" plot. Exports that
plot as a publication-quality file. Will only work only when a single
pattern is displayed.
:param wx.Frame G2Frame: the main GSAS-II window
:param list Pattern: list of np.array items with obs, calc (etc.) diffraction pattern
:param mpl.axes Plot: axes of the graph in plot window
:param wx.Panel Page: tabbed panel containing the plot
'''
def Init_fmts():
figure = mplfig.Figure(dpi=200,figsize=(6,8))
canvas = hcCanvas(figure)
fmtDict = canvas.get_supported_filetypes()
plotWidgets['fmtChoices'] = [fmtDict[j]+', '+j for j in sorted(fmtDict)]
plotWidgets['fmtChoices'].append('Data file with plot elements, csv')
plotWidgets['fmtChoices'].append('Grace input file, agr')
plotWidgets['fmtChoices'].append('Igor Pro input file, itx')
if sys.platform == "win32":
plotWidgets['fmtChoices'].append('OriginPro connection')
def Initialize():
'''Set up initial values in plotOpt
'''
plotOpt['initNeeded'] = False
# create a temporary hard-copy figure to get output options
figure = mplfig.Figure(dpi=200,figsize=(6,8))
canvas = hcCanvas(figure)
figure.clear()
fmtDict = canvas.get_supported_filetypes()
if plotOpt['format'] is None:
if 'pdf' in fmtDict:
plotOpt['format'] = fmtDict['pdf'] + ', pdf'
else:
plotOpt['format'] = plotWidgets['fmtChoices'][0]
plotOpt['lineWid'] = '1'
plotOpt['tickSiz'] = '6'
plotOpt['tickWid'] = '1'
plotOpt['markerWid'] = '1'
plotOpt['markerSiz'] = '8'
plotOpt['markerSym'] = '+'
lims = {}
lims['xmin'],lims['xmax'] = Plot.get_xlim()
lims['ymin'],lims['ymax'] = Plot.get_ylim()
for key in 'xmin','xmax','ymin','ymax':
if not plotOpt[key+'_use']: plotOpt[key] = lims[key]
#if mpl.__version__.split('.')[0] == '1':
# G2G.G2MessageBox(G2frame.plotFrame,
# ('You are using an older version of Matplotlib ({}). '.format(mpl.__version__) +
# '\nPlot quality will be improved by updating (use conda update matplotlib)'),
# 'Old matplotlib')
def GetColors():
'''Set up initial values in plotOpt for colors and legend. Also catalog phases.
'''
if hasattr(mpcls,'to_rgba'):
MPL2rgba = mpcls.to_rgba
else:
MPL2rgba = mpcls.ColorConverter().to_rgba
for i,l in enumerate(Plot.lines):
lbl = l.get_label()
if 'magline' in lbl:
pass
elif lbl[1:] in plotOpt['lineList']: # item not in legend
if lbl[1:] in plotOpt['colors']: continue
plotOpt['colors'][lbl[1:]] = MPL2rgba(l.get_color())
plotOpt['legend'][lbl[1:]] = False
elif lbl in plotOpt['lineList']:
if lbl in plotOpt['colors']: continue
plotOpt['colors'][lbl] = MPL2rgba(l.get_color())
plotOpt['legend'][lbl] = True
plotWidgets['phaseList'].clear()
for ph,l in Page.tickDict.items():
plotWidgets['phaseList'].append(ph)
if lbl in plotOpt['colors']: continue
plotOpt['colors'][ph] = MPL2rgba(l.get_color())
plotOpt['legend'][ph] = True
return
def RefreshPlot(*args,**kwargs):
'''Update the plot on the dialog
'''
figure.clear()
CopyRietveldPlot(G2frame,Pattern,Plot,Page,figure,plotWidgets['phaseList'])
figure.canvas.draw()
def CopyRietveld2Grace(Pattern,Plot,Page,plotOpt,filename):
'''Copy the contents of the Rietveld graph from the plot window to
a Grace input file (tested with QtGrace). Uses values from Pattern
to also generate a delta/sigma plot below.
'''
def ClosestColorNumber(color):
'''Convert a RGB value to the closest default Grace color
'''
import matplotlib.colors as mpcls
colorlist = ('white','black','red','green','blue','yellow','brown',
'gray','purple','cyan','magenta','orange') # ordered by grace's #
if not hasattr(mpcls,'to_rgba'): mpcls = mpcls.ColorConverter()
return (np.sum(([np.array(mpcls.to_rgb(c)) for c in colorlist] -
np.array(color[:3]))**2,axis=1)).argmin()
# blocks of code used in grace .agr files
linedef = '''@{0} legend "{1}"
@{0} line color {2}
@{0} errorbar color {2}
@{0} symbol color {2}
@{0} symbol {3}
@{0} symbol fill color {2}
@{0} linewidth {4}
@{0} symbol linewidth {6}
@{0} line type {7}
@{0} symbol size {5}
@{0} symbol char 46
@{0} symbol fill pattern 1
@{0} hidden false
@{0} errorbar off\n'''
linedef1 = '''@{0} legend "{1}"
@{0} line color {2}
@{0} errorbar color {2}
@{0} symbol color {2}
@{0} symbol fill color {2}
@{0} symbol 11
@{0} linewidth 0
@{0} linestyle 0
@{0} symbol size {3}
@{0} symbol linewidth {4}
@{0} symbol char 124
@{0} symbol fill pattern 1
@{0} hidden false\n'''
linedef2 = '''@{0} legend "{1}"
@{0} line color {2}
@{0} errorbar color {2}
@{0} symbol color {2}
@{0} symbol fill color {2}
@{0} symbol 0
@{0} linewidth 0
@{0} linestyle 0
@{0} symbol size 1
@{0} symbol linewidth 0
@{0} symbol char 124
@{0} symbol fill pattern 1
@{0} hidden false
@{0} errorbar on
@{0} errorbar size 0
@{0} errorbar riser linewidth {3}\n'''
linedef3 = '''@{0} legend "{1}"
@{0} line color {2}
@{0} errorbar color {2}
@{0} symbol color {2}
@{0} symbol {3}
@{0} symbol fill color {2}
@{0} linewidth {4}
@{0} symbol linewidth {6}
@{0} line type {7}
@{0} symbol size {5}
@{0} symbol char 46
@{0} symbol fill pattern 1
@{0} hidden false
@{0} errorbar off\n'''
grace_symbols = {"":0, "o":1 ,"s":2, "D":3, "^":4, "3":5, 'v':6,
"4": 7, "+":8, "P":8, "x":9, "X":9, "*":10, ".":11}
fp = open(filename,'w')
fp.write("# Grace project file\n#\n@version 50010\n")
# size of plots on page
xmar = (.15,1.2)
ymar = (.15,.9)
top2bottom = 4. # 4 to 1 spacing for top to bottom boxes
# scaling for top box
fp.write('@g{0} hidden false\n@with g{0}\n@legend {1}\n'.format(0,"on"))
fp.write('@legend {}, {}\n'.format(xmar[1]-.2,ymar[1]-.05))
fp.write('@world xmin {}\n@world xmax {}\n'.format(Plot.get_xlim()[0],Plot.get_xlim()[1]))
fp.write('@world ymin {}\n@world ymax {}\n'.format(Plot.get_ylim()[0],Plot.get_ylim()[1]))
fp.write('@view xmin {}\n@view xmax {}\n'.format(xmar[0],xmar[1]))
fp.write('@view ymin {}\n@view ymax {}\n'.format((1./top2bottom)*(ymar[1]-ymar[0])+ymar[0],ymar[1]))
xticks = Plot.get_xaxis().get_majorticklocs()
fp.write('@{}axis tick major {}\n'.format('x',xticks[1]-xticks[0]))
yticks = Plot.get_yaxis().get_majorticklocs()
fp.write('@{}axis tick major {}\n'.format('y',yticks[1]-yticks[0]))
fp.write('@{}axis ticklabel char size {}\n'.format('x',0)) # turns off axis labels
if 'sqrt' in Plot.yaxis.get_label().get_text():
#ylbl = 'sqrt(Intensity)' # perhaps there is a way to get the symbol in xmgrace but I did not find it
ylbl = r'\x\#{d6}\f{}\oIntensity\O' # from Carlo Segre
else:
ylbl = 'Intensity'
fp.write('@{0}axis label "{1}"\n@{0}axis label char size {2}\n'.format(
'y',ylbl,float(plotOpt['labelSize'])/8.))
fp.write('@{0}axis label place spec\n@{0}axis label place {1}, {2}\n'.format('y',0.0,0.1))
# ======================================================================
# plot magnification lines and labels (first, so "under" data)
for i,l in enumerate(Plot.lines):
lbl = l.get_label()
if 'magline' not in lbl: continue
#ax0.axvline(l.get_data()[0][0],color='0.5',dashes=(1,1))
# vertical line
s = '@with line\n@ line on\n@ line loctype world\n@ line g0\n'
fp.write(s)
s = '@ line {0}, {1}, {0}, {2}\n'
fp.write(s.format(
l.get_data()[0][0],Plot.get_ylim()[0],Plot.get_ylim()[1]))
s = '@ line linewidth 2\n@ line linestyle 2\n@ line color 1\n@ line arrow 0\n@line def\n'
fp.write(s)
for l in Plot.texts:
if 'magline' not in l.get_label(): continue
if l.xycoords[0] == 'data':
xpos = l.get_position()[0]
elif l.get_position()[0] == 0:
xpos = Plot.get_xlim()[0]
else:
xpos = Plot.get_xlim()[1]*.95
s = '@with string\n@ string on\n@ string loctype world\n'
fp.write(s)
s = '@ string g{0}\n@ string {1}, {2}\n@ string color 1\n'
fp.write(s.format(0,xpos,Plot.get_ylim()[1]))
s = '@ string rot 0\n@ string font 0\n@ string just 4\n'
fp.write(s)
s = '@ string char size {1}\n@ string def "{0}"\n'
fp.write(s.format(l.get_text(),float(plotOpt['labelSize'])/8.))
datnum = -1
# ======================================================================
# plot data
for l in Plot.lines:
if l.get_label() in ('obs','calc','bkg','zero','diff'):
lbl = l.get_label()
elif l.get_label()[1:] in ('obs','calc','bkg','zero','diff'):
lbl = l.get_label()[1:]
else:
continue
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
gc = ClosestColorNumber(c)
if sum(c) == 4.0: # white on white, skip
continue
marker = l.get_marker()
lineWid = l.get_lw()
siz = l.get_markersize()
mkwid = l.get_mew()
glinetyp = 1
if lbl == 'obs':
gsiz = float(plotOpt['markerSiz'])/8.
marker = plotOpt['markerSym']
gmw = float(plotOpt['markerWid'])
gsym = grace_symbols.get(marker,5)
glinetyp = 0
else:
gsym = 0
gsiz = 0
gmw = 0
lineWid = float(plotOpt['lineWid'])
if not plotOpt['Show'].get(lbl,True): continue
if plotOpt['legend'].get(lbl):
glbl = lbl
else:
glbl = ""
datnum += 1
fp.write("@type xy\n")
if lbl == 'zero':
fp.write("{} {}\n".format(Plot.get_xlim()[0],0))
fp.write("{} {}\n".format(Plot.get_xlim()[1],0))
elif not ma.any(l.get_xdata().mask):
for x,y in zip(l.get_xdata(),l.get_ydata()):
fp.write("{} {}\n".format(x,y))
else:
for x,y,m in zip(l.get_xdata(),l.get_ydata(),l.get_xdata().mask):
if not m: fp.write("{} {}\n".format(x,y))
fp.write("&\n")
fp.write(linedef.format("s"+str(datnum),glbl,gc,gsym,lineWid,gsiz,gmw,glinetyp))
#======================================================================
# reflection markers. Create a single hidden entry for the legend
# and use error bars for the vertical lines
for l in Plot.lines:
glbl = lbl = l.get_label()
if l not in Page.tickDict.values(): continue
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
gc = ClosestColorNumber(c)
siz = float(plotOpt['tickSiz'])*(Plot.get_ylim()[1] - Plot.get_ylim()[0])/(100*6) # 1% for siz=6
mkwid = float(plotOpt['tickWid'])
if sum(c) == 4.0: continue # white: ignore
if not plotOpt['Show'].get(lbl,True): continue
if plotOpt['legend'].get(lbl):
# invisible data point for
datnum += 1
fp.write("@type xy\n")
# fp.write("-1 -1\n".format(x,y))
fp.write("-1 -1\n")
fp.write(linedef1.format(
"s"+str(datnum),glbl,gc,float(plotOpt['tickSiz'])/8.,mkwid))
# plot values with error bars
datnum += 1
fp.write("@type xydy\n")
for x,y in zip(l.get_xdata(),l.get_ydata()):
fp.write("{} {} {}\n".format(x,y,siz))
fp.write("&\n")
fp.write(linedef2.format("s"+str(datnum),'',gc,mkwid))
#======================================================================
# Start (obs-cal)/sigma plot
wtFactor = Pattern[0]['wtFactor']
ysig = (Pattern[1][1]-Pattern[1][3])*np.sqrt(wtFactor*Pattern[1][2])
fp.write("@type xy\n")
# scaling for bottom box
fp.write('@g{0} hidden false\n@with g{0}\n@legend {1}\n'.format(1,"off"))
fp.write('@world xmin {}\n@world xmax {}\n'.format(Plot.get_xlim()[0],Plot.get_xlim()[1]))
fp.write('@world ymin {}\n@world ymax {}\n'.format(ysig.min(),ysig.max()))
fp.write('@view xmin {}\n@view xmax {}\n'.format(xmar[0],xmar[1]))
fp.write('@view ymin {}\n@view ymax {}\n'.format(
ymar[0],(1./top2bottom)*(ymar[1]-ymar[0])+ymar[0]))
if 'theta' in Plot.get_xlabel():
xlbl = r'2\f{Symbol}q'
elif 'TOF' in Plot.get_xlabel():
xlbl = r'TOF, \f{Symbol}m\f{}s'
else:
xlbl = Plot.get_xlabel().replace('$','')
fp.write('@{0}axis label "{1}"\n@{0}axis label char size {2}\n'.format(
'x',xlbl,float(plotOpt['labelSize'])/8.))
fp.write('@{0}axis label "{1}"\n@{0}axis label char size {2}\n'.format(
'y',r'\f{Symbol}D/s',float(plotOpt['labelSize'])/8.))
xticks = Plot.get_xaxis().get_majorticklocs()
# come up with a "nice" tick interval for (o-c)/sig, since I am not sure
# if this can be defaulted
ytick = (ysig.max()-ysig.min())/5.
l10 = np.log10(ytick)
if l10 < 0:
yti = int(10**(1 + l10 - int(l10)))
# r = -0.5
else:
yti = int(10**(l10 - int(l10)))
# r = 0.5
if yti == 3:
yti = 2
elif yti > 5:
yti = 5
ytick = yti * 10**int(np.log10(ytick/yti)+.5)
fp.write('@{}axis tick major {}\n'.format('x',xticks[1]-xticks[0]))
fp.write('@{}axis tick major {}\n'.format('y',ytick))
fp.write("@type xy\n")
try: # new behavior: .mask can return a single np.False_ value
savedX_mask = savedX.mask
len(savedX_mask)
except TypeError:
savedX_mask = len(savedX)*[False]
for x,y,m in zip(savedX,ysig,savedX_mask):
if not m: fp.write("{} {}\n".format(x,y))
fp.write("&\n")
fp.write(linedef3.format("s1",'',1,0,1.0,0,0,1))
fp.close()
print('file',filename,'written')
def CopyRietveld2Origin(Pattern,Plot,Page,plotOpt,G2frame):
# Exports plot to Origin. This function was written by Conrad Gillard (conrad.gillard@gmail.com).
def origin_shutdown_exception_hook(exctype, value, tracebk):
'''Ensures Origin gets shut down if an uncaught exception'''
try:
op.exit()
except:
pass
print('\n****OriginPro error****')
import traceback
traceback.print_exception(exctype, value, tracebk)
G2G.G2MessageBox(G2frame,
'Failed to connect to OriginPro. Is it installed?\nSee console window for more info.')
#sys.__excepthook__(exctype, value, tracebk)
# Function to increase line width, for later use
def increase_line_width(plot):
layr = op.GLayer(plot.layer)
pindex = plot.index()
pname = layr.obj.GetStrProp('plot{}.name'.format(pindex+1))
layr.lt_exec('set {} -w 1000'.format(pname))
#import itertools # delay this since not commonly called or needed
try:
import originpro as op
except:
note1,note2 = '',''
# get pip location
pyPath = os.path.split(os.path.realpath(sys.executable))[0]
import shutil
if shutil.which('pip'):
pip = shutil.which('pip')
elif os.path.exists(os.path.join(pyPath,'pip.exe')):
pip = os.path.join(pyPath,'pip.exe')
elif os.path.exists(os.path.join(pyPath,'Scripts','pip.exe')):
pip = os.path.join(pyPath,'Scripts','pip.exe')
else:
note1 = "\nNote pip not found, you may need to install that too\n"
pip = 'pip'
try:
import win32clipboard
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText('{} install originpro'.format(pip))
win32clipboard.CloseClipboard()
note2 = "\nNote: command copied to clipboard (use control-V to paste in cmd.exe window)"
except:
pass
msg = """Use of the OriginPro exporter requires that OriginPro be
installed on your computer as well as a communication
module (originpro) via pip.
{}
Use command
\t{} install originpro
in a cmd.exe window to do this.
{}""".format(note1,pip,note2)
G2G.G2MessageBox(G2frame,msg)
return
lblList = []
valueList = []
lblList.append('Axis-limits')
valueList.append(list(Plot.get_xlim())+list(Plot.get_ylim()))
tickpos = {}
for i,l in enumerate(Plot.lines):
lbl = l.get_label()
if lbl[1:] in ('obs','calc','bkg','zero','diff'):
lbl = lbl[1:]
if 'magline' in lbl:
pass
elif lbl in ('obs','calc','bkg','zero','diff'):
if lbl == 'obs':
lblList.append('x')
valueList.append(l.get_xdata())
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
if sum(c) == 4.0: continue
lblList.append(lbl)
valueList.append(l.get_ydata())
elif l in Page.tickDict.values():
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
if sum(c) == 4.0: continue
tickpos[lbl] = l.get_ydata()[0]
lblList.append(lbl)
valueList.append(l.get_xdata())
if tickpos:
lblList.append('tick-pos')
valueList.append([])
for i in tickpos:
valueList[-1].append(i)
valueList[-1].append(tickpos[i])
# add (obs-calc)/sigma [=(obs-calc)*sqrt(weight)]
lblList.append('diff/sigma')
valueList.append(Pattern[1][5]*np.sqrt(Pattern[1][2]))
if sum(Pattern[1][0].mask): # are there are excluded points? If so, add them too
lblList.append('excluded')
valueList.append(1*Pattern[1][0].mask)
# magnifcation values
for l in Plot.texts:
lbl = l.get_label()
if 'magline' not in lbl: continue
if l.xycoords == 'axes fraction':
lbl = 'initial-mag'
lblList.append(lbl)
valueList.append([l.get_text()])
else:
lbl = 'mag'
lblList.append(lbl)
valueList.append([l.get_text(),l.get_position()[0]])
# Start Origin instance
if op and op.oext:
sys.excepthook = origin_shutdown_exception_hook
# Set Origin instance visibility
if op.oext:
op.set_show(True)
op.new()
# Create folder to hold data and graph
refinementName = G2frame.Label
refinementName = refinementName[17:-4]
fldr = op.po.RootFolder.Folders.Add(refinementName)
fldr.Activate()
# Create worksheet to hold refinement data
dest_wks = op.new_sheet('w', lname='Refinement Data')
dest_wks.cols = 5
# Import refinement data
colNamesList =["x", "Observed", 'Calculated','Background','(Obs-Calc)']
for i in range(1, 6):
dest_wks.from_list(col=i-1, data=valueList[i].tolist(), lname=colNamesList[i-1])
# Create graph object, to which data will be added
template = os.path.join(GSASIIpath.path2GSAS2,'inputs','OriginTemplate2.otpu')
if not os.path.exists(template): # patch 3/2024 for svn dir organization
template = os.path.join(GSASIIpath.path2GSAS2,'OriginTemplate2.otpu')
if not os.path.exists(template):
print('Error: OriginTemplate2.otpu not found')
return
graph = op.new_graph(template=template)
graph.lname = refinementName + "_G"
gl = graph[0]
# Plot observed as scatter
plot = gl.add_plot(dest_wks, coly=1, colx=0, type='scatter')
plot.symbol_size = 10
plot.symbol_kind = 7
plot.colormap = 'Classic'
plot.color = 1
# Plot calculated, background and difference as line
for i in range(2, 5):
plot = gl.add_plot(dest_wks, coly=i, colx=0, type='line')
plot.colormap = 'Classic'
plot.color = i
increase_line_width(plot)
# Import reflection data for each phase
tickPosIdx = lblList.index("tick-pos")
# Initialise counters for colour index and number of phases
j = 1
k = 1
refLegendText = ""
for i in range(7, tickPosIdx):
# Create worksheet to hold reflections data
dest_wks = op.new_sheet('w', lname=lblList[i] + " Reflections")
dest_wks.cols = 2
# Generate lists of tick positions
tickPosList = valueList[i].tolist()
# Generate lists of tick intensities
refIntens = valueList[tickPosIdx][(i - 6) * 2 - 1]
refIntens = float(refIntens)
refIntensList = [refIntens] * len(tickPosList)
# Import tick positions and intensities to worksheet
dest_wks.from_list(col=0, data=tickPosList, lname="Tick Position")
dest_wks.from_list(col=1, data=refIntensList, lname="Tick Intensity")
# Add reflections to plot
plot = gl.add_plot(dest_wks, coly=1, colx=0, type='scatter')
plot.symbol_size = 10
plot.symbol_kind = 10
plot.color = 4 + j
refLegendText = refLegendText + "\\l(" + str(4 + k) + ") " + lblList[i] + " "
# Increment phase counter
k += 1
# increment colour index, skipping yellow because it cannot be seen
if j == 2:
j += 2
else:
j += 1
# # Set axis limits
xmin = Plot.get_xlim()[0]
if Plot.dataLim.x0 > xmin:
xmin = Plot.dataLim.x0 + 0.1
xmax = Plot.get_xlim()[1]
if Plot.dataLim.x1 < xmax:
xmax = Plot.dataLim.x1 + 0.1
gl.set_xlim(xmin, xmax)
ymin = Plot.get_ylim()[0]
ymax = Plot.get_ylim()[1]
gl.set_ylim(ymin, ymax)
# Change graph titles
gl.axis(ax="x").title = "2θ (°)"
gl.axis(ax="y").title = "Intensity (Arbitrary units)"
# Set up legend
label = gl.label('Legend')
label.text = '\\l(1) %(1)\\l(2) %(2)\\l(3) %(3)\\l(4) %(4) %(CRLF)' + refLegendText
def CopyRietveld2Igor(Pattern,Plot,Page,plotOpt,filename,G2frame):
'''Copy the contents of the Rietveld graph from the plot window to
a Igor Pro input file (tested with v7.05). Uses values from Pattern
to also generate a delta/sigma plot below.
Coded with lots of help from Jan Ilavsky.
'''
import itertools # delay this until called, since not commonly needed
InameDict = {'obs':'Intensity', 'calc':'FitIntensity',
'bkg':'Background','diff':'Difference',
'omcos':'NormResidual','zero':'Zero'}
igor_symbols = {"o":19, "s":18, "D":29, "^":17, "3":46, 'v':23,
"4":49, "+":1, "P":60, "x":0, "X":62, "*":2}
def Write2cols(fil,dataItems):
'''Write a line to a file in space-separated columns.
Skips masked items.
:param object fil: file object
:param list dataItems: items to write as row in file
'''
line = ''
for item in dataItems:
if ma.is_masked(item): return
if line: line += ' '
item = str(item)
if ' ' in item:
line += '"'+item+'"'
else:
line += item
fil.write(line+'\n')
proj = os.path.splitext(G2frame.GSASprojectfile)[0]
if not proj: proj = 'GSASIIproject'
proj = proj.replace(' ','')
valueList = []
markerSettings = []
Icolor = {}
legends = []
zerovals = None
fontsize = 18*float(plotOpt['labelSize'])/12.
for i,l in enumerate(Plot.lines):
lbl = l.get_label()
if not plotOpt['Show'].get(lbl[1:],True): continue
if plotOpt['legend'].get(lbl[1:]):
legends.append((InameDict[lbl[1:]],lbl[1:]))
if l.get_label()[1:] in ('obs','calc','bkg','zero','diff'):
lbl = l.get_label()[1:]
if plotOpt['legend'].get(lbl) and lbl in InameDict:
legends.append((InameDict[lbl],lbl))
if lbl == 'obs':
x = l.get_xdata()
valueList.append(x)
zerovals = (x.min(),x.max())
gsiz = 5*float(plotOpt['markerSiz'])/8.
marker = plotOpt['markerSym']
gsym = igor_symbols.get(marker,12)
gmw = float(plotOpt['markerWid'])
markerSettings.append(
'mode({0})=3,marker({0})={1},msize({0})={2},mrkThick({0})={3}'
.format('Intensity',gsym,gsiz,gmw))
elif lbl in ('calc','bkg','zero','diff'):
markerSettings.append(
'mode({0})=0, lsize({0})={1}'
.format(InameDict[lbl],plotOpt['lineWid']))
else:
continue
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
Icolor[InameDict[lbl]] = [j*65535 for j in c[0:3]]
if lbl != 'zero':
valueList.append(l.get_ydata())
valueList.append(Pattern[1][5]*np.sqrt(Pattern[1][2]))
fp = open(filename,'w')
fp.write('''IGOR
X setDataFolder root:
X // *** Replace GSAS2Data with name of current project in GSAS.
X // *** this name will get "order" number (0,1,2...) to be unique and data will be stored there.
X // *** and the graph will also be named using this base name.
X NewDataFolder/O/S $(UniqueName(CleanupName("{}",0),11, 0))
X string GSAXSProjectName = GetDataFolder(0)
WAVES /D/O TwoTheta, Intensity, FitIntensity, Background, Difference, NormResidual
BEGIN
'''.format(proj))
# invert lists into columns, use iterator for all values
for row in itertools.zip_longest(*valueList,fillvalue=' '):
Write2cols(fp,row)
fp.write('''END
X // *** static part of the code, NB reflection tickmarks later ****
X SetScale d 0,0, "degree", TwoTheta
X // *** this is where graph is created and data added
X string G_Name=CleanupName(GSAXSProjectName,0)
X Display/K=1/W=(50,40,850,640) Intensity vs twoTheta; DoWindow/C $(G_Name)
X DoWindow/T $(G_Name), G_Name
X AppendToGraph FitIntensity vs TwoTheta
X AppendToGraph Background vs TwoTheta
X AppendToGraph Difference vs TwoTheta
X AppendToGraph/L=Res_left/B=Res_bot NormResidual vs TwoTheta
X // *** Here we have modification of the four axes used in the graph
X ModifyGraph mode=2,lsize=5, mirror=2
X SetAxis/A/E=2 Res_left
X ModifyGraph freePos(Res_left)={0,kwFraction}
X ModifyGraph freePos(Res_bot)={0.2,kwFraction}
X ModifyGraph standoff(bottom)=0
X ModifyGraph axisEnab(left)={0.2,1}
X ModifyGraph axisEnab(Res_left)={0,0.2}
X ModifyGraph lblPosMode(Res_left)=1, mirror(Res_bot)=0
X ModifyGraph tickUnit(bottom)=1,manTick=0,manMinor(bottom)={0,50}
X ModifyGraph tick(Res_bot)=1,noLabel(Res_bot)=2,standoff(Res_bot)=0
X ModifyGraph manMinor(Res_bot)={0,50},tick(Res_bot)=2
X ModifyGraph axThick=2
X ModifyGraph mirror(Res_bot)=0,nticks(Res_left)=3,highTrip(left)=1e+06,manTick(bottom)=0
X ModifyGraph btLen=5
''')
fp.write('X ModifyGraph gfSize={}\n'.format(int(fontsize+.5)))
# line at zero
if not zerovals:
zerovals = (Plot.get_xlim()[0],Plot.get_xlim()[1])
fp.write('X // *** add line at y=zero\n')
fp.write('WAVES /D/O ZeroX, Zero\nBEGIN\n')
fp.write(' {0} 0.0\n {1} 0.0\n'.format(*zerovals))
fp.write('END\nX AppendToGraph Zero vs ZeroX\n')
if 'sqrt' in Plot.yaxis.get_label().get_text():
ylabel = '\u221AIntensity'
else:
ylabel = 'Intensity'
fp.write('''X // *** add axis labels and position them
X Label left "{1}"
X Label Res_left "{2}"
X Label bottom "{0}"
X ModifyGraph lblPosMode=0,lblPos(Res_left)=84
'''.format("2Θ",ylabel,"∆/σ"))
fp.write('''X // *** set display limits.
X SetAxis left {2}, {3}
X SetAxis bottom {0}, {1}
X SetAxis Res_bot {0}, {1}
'''
.format(Plot.get_xlim()[0],Plot.get_xlim()[1],
Plot.get_ylim()[0],Plot.get_ylim()[1]))
fp.write('X // *** modify how data are displayed ****\n')
# fp.write(
# '''X // *** here starts mostly static part of the code, here we modify how data are displayed ****
# X ModifyGraph mode(FitIntensity)=0,rgb(FitIntensity)=(1,39321,19939), lsize(FitIntensity)=1
# X ModifyGraph mode(Background)=0,lsize(Background)=2, rgb(Background)=(65535,0,0)
# X ModifyGraph mode(Difference)=0,lsize(Difference)=2,rgb(Difference)=(0,65535,65535)
# X // *** modifications for the bottom graph, here we modify how data are displayed ****
# X ModifyGraph mode(NormResidual)=0,lsize(NormResidual)=1,rgb(NormResidual)=(0,0,0)
# X // *** end of modifications for the main data in graph
# ''')
for m in markerSettings:
fp.write('X ModifyGraph {}\n'.format(m))
for lbl in Icolor:
fp.write('X ModifyGraph rgb({})=({:.0f},{:.0f},{:.0f})\n'
.format(lbl,*Icolor[lbl]))
fp.write('X ModifyGraph mode(NormResidual)=0,lsize(NormResidual)=1,rgb(NormResidual)=(0,0,0)\n')
fp.write('X // *** End modify how data are displayed ****\n')
# loop over reflections
ticknum = 0
for i,l in enumerate(Plot.lines):
lbl = l.get_label()
if not plotOpt['Show'].get(lbl,True): continue
if l in Page.tickDict.values():
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
if sum(c) == 4.0: continue # white is invisible
ticknum += 1
phasename = 'tick{}'.format(ticknum)
if plotOpt['legend'].get(lbl):
legends.append((phasename,plotOpt['phaseLabels'].get(lbl,lbl)))
tickpos = l.get_ydata()[0]
fp.write(
'''X // reflection tickmark for phase {1}
WAVES /D/O {0}X, {0}
BEGIN
'''.format(phasename,lbl))
for x in l.get_xdata():
fp.write('{} {}\n'.format(x,tickpos))
fp.write('''END
X // *** controls for {1} reflection tickmarks
X AppendToGraph {0} vs {0}X
X ModifyGraph mode({0})=3,mrkThick({0})=2,gaps({0})=0
X ModifyGraph marker({0})=10,rgb({0})=({2},{3},{4})
'''.format(phasename,lbl,*[j*65535 for j in c[0:3]]))
# plot magnification lines and labels
j = 0
for i,l in enumerate(Plot.lines):
lbl = l.get_label()
if 'magline' not in lbl: continue
j += 1
fp.write('WAVES /D/O mag{0}X, mag{0}\nBEGIN\n'.format(j))
fp.write(' {0} {1}\n {0} {2}\n'.format(
l.get_data()[0][0],Plot.get_ylim()[0],Plot.get_ylim()[1]))
fp.write('END\nX AppendToGraph mag{0} vs mag{0}X\n'.format(j))
fp.write('X ModifyGraph lstyle(mag{0})=3,rgb(mag{0})=(0,0,0)\n'.format(j))
for l in Plot.texts:
if 'magline' not in l.get_label(): continue
if l.xycoords[0] == 'data':
xpos = l.get_position()[0]
elif l.get_position()[0] == 0:
xpos = Plot.get_xlim()[0]
else:
xpos = Plot.get_xlim()[1]*.95
fp.write('X SetDrawEnv xcoord=bottom, ycoord= abs,textyjust=2,fsize={}\n'.format(fontsize))
fp.write('X DrawText {0},2,"{1}"\n'.format(xpos,l.get_text()))
# legend
s = ""
for nam,txt in legends:
if s: s += r'\r'
s += r'\\s({}) {}'.format(nam,txt)
fp.write('X Legend/C/N=text0/J "{}"\n'.format(s))
fp.close()
print('file',filename,'written')
def CopyRietveld2csv(Pattern,Plot,Page,filename):
'''Copy the contents of the Rietveld graph from the plot window to
.csv file
'''
import itertools # delay this since not commonly called or needed
lblList = []
valueList = []
tickpos = {}
lblList.append('used')
try:
valueList.append([0 if i else 1 for i in savedX.mask])
except:
pass
if 'TOF' in Plot.xaxis.get_label_text():
lblList.append('x, TOF (msec)')
elif 'Q,' in Plot.xaxis.get_label_text():
lblList.append('x, Q (A-1)')
elif 'd,' in Plot.xaxis.get_label_text():
lblList.append('x, d-space (A)')
elif 'E,' in Plot.xaxis.get_label_text():
lblList.append('x, E (keV)')
elif 'theta' in Plot.xaxis.get_label_text():
lblList.append('x, 2theta (deg)')
else:
lblList.append('x, ?')
valueList.append(savedX.data)
for i,l in enumerate(Plot.lines):
lbl = l.get_label()
if lbl[1:] in ('obs','calc','bkg','zero','diff'):
lbl = l.get_label()[1:]
if 'magline' in lbl:
pass
elif lbl in ('obs','calc','bkg','zero','diff'):
c = plotOpt['colors'].get(lbl,l.get_color())
if sum(c) == 4.0: continue #skip over any "white" entries
if lbl == 'zero': continue
if lbl == 'obs': # include all observed data
lblList.append('obs')
valueList.append(Pattern[1][1].data)
continue
lblList.append(lbl)
valueList.append(l.get_ydata())
elif l in Page.tickDict.values():
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
if sum(c) == 4.0: continue
tickpos[lbl] = l.get_ydata()[0]
lblList.append(lbl)
valueList.append(l.get_xdata())
if tickpos:
lblList.append('tick-pos')
valueList.append([])
for i in tickpos:
valueList[-1].append(i)
valueList[-1].append(tickpos[i])
# add (obs-calc)/sigma [=(obs-calc)*sqrt(weight)]
lblList.append('diff/sigma')
wtFactor = Pattern[0]['wtFactor']
DZ = (Pattern[1][1]-Pattern[1][3])*np.sqrt(wtFactor*Pattern[1][2])
valueList.append(DZ)
if hasattr(Pattern[1][0],'mask') and sum(Pattern[1][0].mask): # are there are excluded points? If so, add them too
lblList.append('excluded')
valueList.append(1*Pattern[1][0].mask)
lblList.append('Axis-limits')
valueList.append(list(Plot.get_xlim())+list(Plot.get_ylim()))
# magnification values
for l in Plot.texts:
lbl = l.get_label()
if 'magline' not in lbl: continue
if l.xycoords == 'axes fraction':
lbl = 'initial-mag'
lblList.append(lbl)
valueList.append([l.get_text()])
else:
lbl = 'mag'
lblList.append(lbl)
valueList.append([l.get_text(),l.get_position()[0]])
fp = open(filename,'w')
G2plt.Write2csv(fp,lblList,header=True)
# invert lists into columns, use iterator for all values
for row in itertools.zip_longest(*valueList,fillvalue=' '):
G2plt.Write2csv(fp,row)
fp.close()
def onSave(event):
'''Write the current plot to a file
'''
hcfigure = mplfig.Figure(dpi=plotOpt['dpi'],figsize=(plotOpt['width'],plotOpt['height']))
CopyRietveldPlot(G2frame,Pattern,Plot,Page,hcfigure,plotWidgets['phaseList'])
if 'OriginPro' in plotOpt['format']:
CopyRietveld2Origin(Pattern,Plot,Page,plotOpt,G2frame)
dlg.EndModal(wx.ID_OK)
return
longFormatName,typ = plotOpt['format'].split(',')
fil = G2G.askSaveFile(G2frame,'','.'+typ.strip(),longFormatName)
if 'csv' in typ and fil:
CopyRietveld2csv(Pattern,Plot,Page,fil)
elif 'agr' in typ and fil:
CopyRietveld2Grace(Pattern,Plot,Page,plotOpt,fil)
elif 'itx' in typ and fil:
CopyRietveld2Igor(Pattern,Plot,Page,plotOpt,fil,G2frame)
elif fil:
if hcfigure.canvas is None:
if GSASIIpath.GetConfigValue('debug'): print('creating canvas')
hcCanvas(hcfigure)
hcfigure.savefig(fil,format=typ.strip())
dlg.EndModal(wx.ID_OK)
def OnSelectColour(event):
'''Respond to a change in color
'''
# lbl = plotOpt['colorButtons'].get(list(event.GetEventObject())[:3])
if event.GetEventObject() not in plotWidgets['colorButtons']:
print('Unexpected button',str(event.GetEventObject()))
return
lbl = plotWidgets['colorButtons'][event.GetEventObject()]
c = event.GetValue()
plotOpt['colors'][lbl] = (c.Red()/255.,c.Green()/255.,c.Blue()/255.,c.alpha/255.)
RefreshPlot()
def OnSavePlotOpt(event):
'Save current "publish" settings to a JSON file with extension .pltopts'
import json
filroot = os.path.splitext(G2frame.GSASprojectfile)[0]+'.pltopts'
saveFile = G2G.askSaveFile(G2frame,filroot,'.pltopts',
'Saved plot options')
if saveFile:
json.dump(plotOpt,open(saveFile,'w'))
print(f'Plot options written to {saveFile!r}')
def OnLoadPlotOpt(event):
'Set current "publish" settings from saved settings in a JSON file (extension .pltopts)'
import json
filroot = os.path.splitext(G2frame.GSASprojectfile)[0]+'.pltopts'
fdlg = wx.FileDialog(dlg, 'Choose saved plot options file',
filroot,
style=wx.FD_OPEN, wildcard='plot options file(*.pltopts)|*.pltopts')
if fdlg.ShowModal() == wx.ID_OK:
filroot = fdlg.GetPath()
plotOpt.update(json.load(open(filroot,'r')))
wx.CallAfter(PublishRietveldPlot,G2frame,Pattern,Plot,Page,reuse=dlg)
fdlg.Destroy()
#### start of PublishRietveldPlot
plotWidgets = {}
plotWidgets['phaseList'] = []
Init_fmts()
if reuse:
dlg = reuse
vbox = dlg.GetSizer()
vbox.Clear()
else:
if plotOpt['initNeeded']: Initialize()
GetColors()
dlg = wx.Dialog(G2frame.plotFrame,title="Publication plot creation",
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
vbox = wx.BoxSizer(wx.VERTICAL)
# size choices
symChoices = ('+','x','.','o','^','v','*','|')
txtChoices = [str(i) for i in range (8,26)]
sizChoices = [str(i) for i in range (2,21)]
lwidChoices = ('0.5','0.7','1','1.5','2','2.5','3','4')
sizebox = wx.BoxSizer(wx.HORIZONTAL)
sizebox.Add(wx.StaticText(dlg,wx.ID_ANY,'Text size'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,txtChoices,None,None,plotOpt,'labelSize',RefreshPlot,
size=(50,-1))
sizebox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
sizebox.Add((1,1),1,wx.EXPAND,1)
sizebox.Add(wx.StaticText(dlg,wx.ID_ANY,' Obs type'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,symChoices,None,None,plotOpt,'markerSym',RefreshPlot,
size=(40,-1))
sizebox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
sizebox.Add(wx.StaticText(dlg,wx.ID_ANY,' size'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,sizChoices,None,None,plotOpt,'markerSiz',RefreshPlot,
size=(50,-1))
sizebox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
sizebox.Add(wx.StaticText(dlg,wx.ID_ANY,' width'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,lwidChoices,None,None,plotOpt,'markerWid',RefreshPlot,
size=(50,-1))
sizebox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
sizebox.Add((1,1),1,wx.EXPAND,1)
sizebox.Add(wx.StaticText(dlg,wx.ID_ANY,' Line widths'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,lwidChoices,None,None,plotOpt,'lineWid',RefreshPlot,
size=(50,-1))
sizebox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
sizebox.Add((1,1),1,wx.EXPAND,1)
sizebox.Add(wx.StaticText(dlg,wx.ID_ANY,' Tick size'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,sizChoices,None,None,plotOpt,'tickSiz',RefreshPlot,
size=(50,-1))
sizebox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
sizebox.Add(wx.StaticText(dlg,wx.ID_ANY,' width'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,lwidChoices,None,None,plotOpt,'tickWid',RefreshPlot,
size=(50,-1))
sizebox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
sizebox.Add((1,1),1,wx.EXPAND,1)
helpinfo = '''---- Help on creating hard copy ----
Select options such as the size of text and colors for plot contents here.
Tricks:
* Use a color of pure white to remove an element from the plot (light
gray is plotted)
* LaTeX-like coding can be used for phase labels such as
$\\rm FeO_2$ (for a subscript 2) or $\\gamma$-Ti for a Greek "gamma"
Note that the dpi value is ignored for svg and pdf files, which are
drawn with vector graphics (infinite resolution). Likewise, the agr and
itx options create input files for programs Grace (QtGrace) and Igor
Pro, that largely duplicate the displayed plot. Once read into Grace
or Igor the graphs can then be customized.
'''
if sys.platform == "win32":
helpinfo += '''
Note that the OriginPro connection export requires Origin 2021 or later.'''
hlp = G2G.HelpButton(dlg,helpinfo)
sizebox.Add(hlp,0,wx.ALL)
vbox.Add(sizebox,0,wx.ALL|wx.EXPAND)
# table of colors and legend options
cols = 1+len(plotOpt['lineList']) + len(plotWidgets['phaseList'] )
import wx.lib.scrolledpanel as wxscroll
gpanel = wxscroll.ScrolledPanel(dlg,size=(600,105))
gsizer = wx.FlexGridSizer(cols=cols,hgap=2,vgap=2)
gsizer.Add((-1,-1))
for lbl in plotOpt['lineList']:
gsizer.Add(wx.StaticText(gpanel,wx.ID_ANY,lbl),0,wx.ALL)
for lbl in plotWidgets['phaseList']:
if lbl not in plotOpt['phaseLabels']: plotOpt['phaseLabels'][lbl] = lbl
val = G2G.ValidatedTxtCtrl(gpanel,plotOpt['phaseLabels'],lbl,size=(110,-1),
style=wx.TE_CENTRE,OnLeave=RefreshPlot)
gsizer.Add(val,0,wx.ALL)
gsizer.Add(wx.StaticText(gpanel,wx.ID_ANY,'Show'),0,wx.ALL)
for lbl in list(plotOpt['lineList']) + list(plotWidgets['phaseList'] ):
if lbl not in plotOpt['Show']:
plotOpt['Show'][lbl] = True
ch = G2G.G2CheckBox(gpanel,'',plotOpt['Show'],lbl,RefreshPlot)
gsizer.Add(ch,0,wx.ALL|wx.ALIGN_CENTER)
gsizer.Add(wx.StaticText(gpanel,wx.ID_ANY,'Include in legend'),0,wx.ALL)
for lbl in list(plotOpt['lineList']) + list(plotWidgets['phaseList'] ):
if lbl not in plotOpt['legend']:
plotOpt['legend'][lbl] = False
ch = G2G.G2CheckBox(gpanel,'',plotOpt['legend'],lbl,RefreshPlot)
gsizer.Add(ch,0,wx.ALL|wx.ALIGN_CENTER)
gsizer.Add(wx.StaticText(gpanel,wx.ID_ANY,'Color'),0,wx.ALL)
plotWidgets['colorButtons'] = {}
for lbl in list(plotOpt['lineList']) + list(plotWidgets['phaseList']):
import wx.lib.colourselect as csel
if lbl not in plotOpt['colors']:
plotOpt['colors'][lbl] = (0.5, 0.5, 0.5, 1)
color = wx.Colour(*[int(255*i) for i in plotOpt['colors'][lbl]])
b = csel.ColourSelect(gpanel, -1, '', color)
b.Bind(csel.EVT_COLOURSELECT, OnSelectColour)
plotWidgets['colorButtons'][b] = lbl
gsizer.Add(b,0,wx.ALL|wx.ALIGN_CENTER)
# plot limits
vlbox = wx.BoxSizer(wx.VERTICAL)
vlbox.Add(wx.StaticText(dlg,wx.ID_ANY,'plot limit overrides'),0,wx.TOP|wx.ALIGN_CENTER,5)
limsizer = wx.FlexGridSizer(cols=3,hgap=2,vgap=2)
for xy in 'x','y':
for minmax in 'min','max':
key = f'{xy}{minmax}'
txt = wx.StaticText(dlg,wx.ID_ANY,key)
limsizer.Add(txt,0,wx.ALIGN_RIGHT)
ch = G2G.G2CheckBox(dlg,'',plotOpt,key+'_use',RefreshPlot)
limsizer.Add(ch,0,wx.ALL|wx.ALIGN_CENTER)
val = G2G.ValidatedTxtCtrl(dlg,plotOpt,key,size=(90,-1),
style=wx.TE_CENTRE,OnLeave=RefreshPlot)
limsizer.Add(val,0,wx.ALL)
vlbox.Add(limsizer,0,wx.BOTTOM,5)
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add((5,-1))
hbox.Add(vlbox,0,wx.ALL|wx.ALIGN_CENTER_VERTICAL)
# assemble controls box
hbox.Add((10,-1))
hbox.Add((-1,-1),1,wx.EXPAND,0)
gpanel.SetSizer(gsizer)
gpanel.SetAutoLayout(1)
gpanel.SetupScrolling()
hbox.Add(gpanel,0,wx.ALIGN_CENTER)
hbox.Add((-1,-1),1,wx.EXPAND,0)
vbox.Add(hbox,0,wx.ALL|wx.EXPAND)
# hard copy options
hbox = wx.BoxSizer(wx.HORIZONTAL)
txt = wx.StaticText(dlg,wx.ID_ANY,'Hard copy ')
hbox.Add(txt,0,wx.ALL|wx.ALIGN_CENTER_VERTICAL)
txt = wx.StaticText(dlg,wx.ID_ANY,' Width (in):')
hbox.Add(txt,0,wx.ALL|wx.ALIGN_CENTER_VERTICAL)
val = G2G.ValidatedTxtCtrl(dlg,plotOpt,'width',xmin=3.,xmax=20.,nDig=(5,1),size=(45,-1))
hbox.Add(val,0,wx.ALL)
txt = wx.StaticText(dlg,wx.ID_ANY,' Height (in):')
hbox.Add(txt,0,wx.ALL|wx.ALIGN_CENTER_VERTICAL)
val = G2G.ValidatedTxtCtrl(dlg,plotOpt,'height',xmin=3.,xmax=20.,nDig=(5,1),size=(45,-1))
hbox.Add(val,0,wx.ALL)
txt = wx.StaticText(dlg,wx.ID_ANY,'File format:')
hbox.Add(txt,0,wx.ALL|wx.ALIGN_CENTER_VERTICAL)
fmtval = G2G.EnumSelector(dlg,plotOpt,'format',plotWidgets['fmtChoices'])
hbox.Add(fmtval,0,wx.ALL)
# TODO: would be nice to gray this out when format will ignore this
ptxt = wx.StaticText(dlg,wx.ID_ANY,'Pixels/inch:')
pval = G2G.ValidatedTxtCtrl(dlg,plotOpt,'dpi',xmin=60,xmax=1600,
size=(40,-1))
hbox.Add(ptxt,0,wx.ALL|wx.ALIGN_CENTER_VERTICAL)
hbox.Add(pval,0,wx.ALL)
vbox.Add(hbox,0,wx.ALL|wx.ALIGN_CENTER)
# screen preview
figure = mplfig.Figure(figsize=(plotOpt['width'],plotOpt['height']))
canvas = Canvas(dlg,-1,figure)
vbox.Add(canvas,1,wx.ALL|wx.EXPAND,1)
# buttons at bottom
btnsizer = wx.BoxSizer(wx.HORIZONTAL)
btnsizer.Add((5,-1))
btn = wx.Button(dlg, wx.ID_ANY,'save\nsettings',size=(80,-1))
btn.Bind(wx.EVT_BUTTON,OnSavePlotOpt)
btnsizer.Add(btn)
btnsizer.Add((5,-1))
btn = wx.Button(dlg, wx.ID_ANY,'load\nsettings',size=(80,-1))
btn.Bind(wx.EVT_BUTTON,OnLoadPlotOpt)
btnsizer.Add(btn)
btnsizer.Add((-1,-1),1,wx.EXPAND)
btn = wx.Button(dlg, wx.ID_CANCEL)
btnsizer.Add(btn,0,wx.ALIGN_CENTER_VERTICAL)
btnsizer.Add((5,-1))
btn = wx.Button(dlg, wx.ID_SAVE)
btn.Bind(wx.EVT_BUTTON,onSave)
btnsizer.Add(btn,0,wx.ALIGN_CENTER_VERTICAL)
btnsizer.Add((-1,-1),1,wx.EXPAND)
btnsizer.Add((170,-1),1,wx.EXPAND) # empty box to center buttons
vbox.Add(btnsizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM,4)
dlg.SetSizer(vbox)
vbox.Fit(dlg)
dlg.Layout()
dlg.CenterOnParent()
CopyRietveldPlot(G2frame,Pattern,Plot,Page,figure,plotWidgets['phaseList']) # preview plot
figure.canvas.draw()
if not reuse:
dlg.ShowModal()
dlg.Destroy()
fmtval.SetFocus() # move focus off from pixel size
return
[docs]
def CopyRietveldPlot(G2frame,Pattern,Plot,Page,figure,phaseList):
'''Copy the contents of the Rietveld graph from the plot window to another
mpl figure which can be on screen or can be a file for hard copy.
Uses values from Pattern to also generate a delta/sigma plot below the
main figure, since the weights are not available from the plot.
:param list Pattern: histogram object from data tree
:param mpl.axes Plot: The axes object from the Rietveld plot
:param wx.Panel Page: The tabbed panel for the Rietveld plot
:param matplotlib.figure.Figure figure: The figure object from the Rietveld plot
'''
# set up axes
gs = mpl.gridspec.GridSpec(2, 1, height_ratios=[4, 1])
ax0 = figure.add_subplot(gs[0])
ax1 = figure.add_subplot(gs[1])
figure.subplots_adjust(left=int(plotOpt['labelSize'])/100.,bottom=int(plotOpt['labelSize'])/150.,
right=.98,top=1.-int(plotOpt['labelSize'])/200.,hspace=0.0)
ax0.tick_params('x',direction='in',labelbottom=False)
ax0.tick_params(labelsize=plotOpt['labelSize'])
ax1.tick_params(labelsize=plotOpt['labelSize'])
if mpl.__version__.split('.')[0] == '1': # deal with older matplotlib, which puts too many ticks
ax1.yaxis.set_major_locator(mpl.ticker.MaxNLocator(nbins=2))
ax1.yaxis.set_minor_locator(mpl.ticker.MaxNLocator(nbins=4))
ax1.set_xlabel(Plot.get_xlabel(),fontsize=plotOpt['labelSize'])
ax0.set_ylabel(Plot.get_ylabel(),fontsize=plotOpt['labelSize'])
ax1.set_ylabel(r'$\Delta/\sigma$',fontsize=plotOpt['labelSize'])
# set axes ranges, get ranges from display
lims = {}
lims['xmin'],lims['xmax'] = Plot.get_xlim()
lims['ymin'],lims['ymax'] = Plot.get_ylim()
for key in 'xmin','xmax','ymin','ymax': # apply limit overrides where use flag is set
if plotOpt[key+'_use']: lims[key] = plotOpt[key]
ax0.set_xlim((lims['xmin'],lims['xmax']))
ax1.set_xlim((lims['xmin'],lims['xmax']))
ax0.set_ylim((lims['ymin'],lims['ymax']))
legLbl = []
legLine = []
# get the obs/calc... & magnification lines and xfer them
for i,l in enumerate(Plot.lines):
lbl = l.get_label()
if lbl[1:] in ('obs','calc','bkg','zero','diff'):
lbl = lbl[1:]
if 'magline' in lbl: # magnification lines
ax0.axvline(l.get_data()[0][0],color='0.5',dashes=(1,1))
elif lbl in ('obs','calc','bkg','zero','diff'): # data segments
if not plotOpt['Show'].get(lbl,True): continue
marker = l.get_marker()
lineWid = l.get_lw()
siz = l.get_markersize()
mew = l.get_mew()
if lbl == 'obs':
siz = float(plotOpt['markerSiz'])
marker = plotOpt['markerSym']
mew = float(plotOpt['markerWid'])
else:
lineWid = float(plotOpt['lineWid'])
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
if sum(c) == 4.0: continue
if plotOpt['legend'].get(lbl):
uselbl = lbl
else:
uselbl = '_'+lbl
if lbl == 'zero':
art = [ax0.axhline(0.,color=c,
lw=lineWid,label=uselbl,ls=l.get_ls(),
marker=marker,ms=siz,mew=mew)]
else:
art = ax0.plot(l.get_xdata(),l.get_ydata(),color=c,
lw=lineWid,label=uselbl,ls=l.get_ls(),
marker=marker,ms=siz,mew=mew,
)
if plotOpt['legend'].get(lbl):
legLbl.append(uselbl)
legLine.append(art[0])
elif l in Page.tickDict.values(): # reflection tickmarks
if not plotOpt['Show'].get(lbl,True): continue
c = plotOpt['colors'].get(lbl,mpl.colors.to_rgba(l.get_color()))
#siz = l.get_markersize()
siz = float(plotOpt['tickSiz'])
#mew = l.get_mew()
mew = float(plotOpt['tickWid'])
if sum(c) == 4.0: continue
if not plotOpt['legend'].get(lbl):
uselbl = '_'+lbl
else:
uselbl = plotOpt['phaseLabels'].get(lbl,lbl)
art = ax0.plot(l.get_xdata(),l.get_ydata(),color=c,
lw=l.get_lw(),ls=l.get_ls(),label=uselbl,
marker=l.get_marker(),ms=siz,mew=mew,
)
if plotOpt['legend'].get(lbl):
legLbl.append(uselbl)
legLine.append(art[0])
elif '_FLT_' in lbl: # full-length vertical reflection markers
ph = lbl[5:]
c = plotOpt['colors'][ph]
ax0.axvline(l.get_xdata()[0],color=c,lw=float(plotOpt['tickWid']))
elif lbl in plotOpt['colors']: # draw phase partials
if l.get_marker() != 'None': continue # ignore 2nd tickmark artist
if not plotOpt['Show'].get(lbl,True): continue # remove partial w/tickmarks
c = plotOpt['colors'][lbl]
lineWid = float(plotOpt['lineWid'])
# xfer the phase partials to the new plot, overriding the phase color and line width
ax0.plot(l.get_xdata(),l.get_ydata(),color=c,
linewidth=lineWid,
linestyle=l.get_ls())
# elif GSASIIpath.GetConfigValue('debug'):
# print('other line:',lbl)
# copy text items: magnification labels and reflection markers
for l in Plot.texts:
lbl = l.get_label()
if lbl[1:] in phaseList: # reflection markers
if not plotOpt['Show'].get(lbl[1:],True): continue # remove marker w/tickmarks
p = l.get_bbox_patch()
props = {'facecolor':p.get_facecolor(),
'edgecolor':p.get_facecolor(),
'alpha':p.get_alpha(),
'boxstyle':p.get_boxstyle()}
c = plotOpt['colors'][lbl[1:]]
ax0.text(l.get_position()[0],l.get_position()[1],
l.get_text(),
fontsize=float(plotOpt['labelSize']),
c=c,
ha='center',
va='top',
bbox=props,
rotation=l.get_rotation())
elif 'maglbl' in lbl: # label on a magnification region
ax0.annotate(l.get_text(),
xy=(l.get_position()), xycoords=l.xycoords,
verticalalignment='bottom',
horizontalalignment=l.get_horizontalalignment(),
fontsize=float(plotOpt['labelSize']))
# elif GSASIIpath.GetConfigValue('debug'):
# print('other text:',l.get_label())
# generate the (obs-calc)/sigma values and plot them
wtFactor = Pattern[0]['wtFactor']
DZ = (Pattern[1][1]-Pattern[1][3])*np.sqrt(wtFactor*Pattern[1][2])
ax1.plot(savedX,DZ,color='k')
# show the legend, if anything is in it (list legLine)
if legLine:
ax0.legend(legLine,legLbl,loc='best',prop={'size':plotOpt['labelSize']})
[docs]
def changePlotSettings(G2frame,Plot):
'''Code in development to allow changes to plot settings
prior to export of plot with "floppy disk" button
'''
def RefreshPlot(*args,**kwargs):
'''Apply settings to the plot
'''
Plot.figure.subplots_adjust(left=int(plotOpt['labelSize'])/100.,
bottom=int(plotOpt['labelSize'])/150.,
right=.98,
top=1.-int(plotOpt['labelSize'])/200.,
hspace=0.0)
for P in Plot.figure.axes:
P.get_xaxis().get_label().set_fontsize(plotOpt['labelSize'])
P.get_yaxis().get_label().set_fontsize(plotOpt['labelSize'])
for l in P.get_xaxis().get_ticklabels():
l.set_fontsize(plotOpt['labelSize'])
for l in P.get_yaxis().get_ticklabels():
l.set_fontsize(plotOpt['labelSize'])
for l in P.lines:
l.set_linewidth(float(plotOpt['lineWid']))
P.get_xaxis().set_tick_params(width=float(plotOpt['lineWid']))
P.get_yaxis().set_tick_params(width=float(plotOpt['lineWid']))
for l in P.spines.values():
l.set_linewidth(float(plotOpt['lineWid']))
if Page.plotStyle.get('title',True):
Plot.set_title(plotOpt['title'],fontsize=plotOpt['labelSize'])
for i,P in enumerate(Plot.figure.axes):
if not P.get_visible(): continue
if i == 0:
lbl = ''
else:
lbl = str(i)
P.get_xaxis().set_label_text(plotOpt['xtitle'+lbl])
P.get_yaxis().set_label_text(plotOpt['ytitle'+lbl])
Plot.figure.canvas.draw()
txtChoices = [str(i) for i in range (8,26)]
lwidChoices = ('0.5','0.7','1','1.5','2','2.5','3','4')
dlg = wx.Dialog(G2frame.plotFrame,style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(wx.StaticText(dlg,wx.ID_ANY,'Text size'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,txtChoices,None,None,plotOpt,'labelSize',RefreshPlot,
size=(50,-1))
hbox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
vbox.Add(hbox,0,wx.ALL|wx.EXPAND)
vbox.Add((1,5))
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(wx.StaticText(dlg,wx.ID_ANY,' Line widths'),0,wx.ALL)
w = G2G.G2ChoiceButton(dlg,lwidChoices,None,None,plotOpt,'lineWid',RefreshPlot,
size=(50,-1))
hbox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
vbox.Add(hbox,0,wx.ALL|wx.EXPAND)
vbox.Add((1,5))
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(wx.StaticText(dlg,wx.ID_ANY,' Title'),0,wx.ALL)
plotOpt['title'] = Plot.get_title()
w = G2G.ValidatedTxtCtrl(dlg,plotOpt,'title',OnLeave=RefreshPlot,
size=(200,-1),notBlank=False)
hbox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
vbox.Add(hbox,0,wx.ALL|wx.EXPAND)
for i,P in enumerate(Plot.figure.axes):
if not P.get_visible(): continue
if i == 0:
lbl = ''
else:
lbl = str(i)
vbox.Add((1,5))
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(wx.StaticText(dlg,wx.ID_ANY,' x label '+lbl),0,wx.ALL)
plotOpt['xtitle'+lbl] = P.get_xaxis().get_label_text()
w = G2G.ValidatedTxtCtrl(dlg,plotOpt,'xtitle'+lbl,OnLeave=RefreshPlot,
size=(200,-1),notBlank=False)
hbox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
vbox.Add(hbox,0,wx.ALL|wx.EXPAND)
vbox.Add((1,5))
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(wx.StaticText(dlg,wx.ID_ANY,' y label '+lbl),0,wx.ALL)
plotOpt['ytitle'+lbl] = P.get_yaxis().get_label_text()
w = G2G.ValidatedTxtCtrl(dlg,plotOpt,'ytitle'+lbl,OnLeave=RefreshPlot,
size=(200,-1),notBlank=False)
hbox.Add(w,0,wx.ALL|wx.ALIGN_CENTER)
vbox.Add(hbox,0,wx.ALL|wx.EXPAND)
vbox.Add((1,10),1,wx.ALL|wx.EXPAND,1)
hbox = wx.BoxSizer(wx.HORIZONTAL)
OKbtn = wx.Button(dlg, wx.ID_OK)
OKbtn.Bind(wx.EVT_BUTTON,lambda event:dlg.EndModal(wx.ID_OK))
hbox.Add((-1,-1),1,wx.ALL|wx.EXPAND,1)
hbox.Add(OKbtn)
hbox.Add((-1,-1),1,wx.ALL|wx.EXPAND,1)
vbox.Add(hbox,1,wx.ALL|wx.EXPAND,1)
dlg.SetSizer(vbox)
vbox.Fit(dlg)
#dlg.Show()
RefreshPlot()
dlg.ShowModal()
[docs]
def uneqImgShow(figure,ax,Xlist,Ylist,cmap,vmin,vmax,Ylbls=[]):
'''Plots a contour plot where point spacing varies within a dataset
and where the X values may differ between histograms. Note that
the length of Xlist and Ylist must be the same and will be the number
of histograms to be plotted
:param matplotlib.figure figure:
The figure where the plot will be placed.
:param matplotlib.axes ax:
The axes where the plot will be made.
:param list Xlist:
A list of X values for each histogram.
:param list Ylist:
A list of intensities for each histogram.
:param matplotlib.colormap cmap:
The colormap used for shading intensities.
:param float vmin:
Minimum intensity.
:param float vmax: float
Maximum intensity.
:param list Ylbls: Optional.
Label to place on each histogram. The default is [] where the axes
are labeled normally with the first histogram numbered starting at 0.
'''
def midPoints(x):
'''Return the pixel corners for a series of steps
For the series [1,2,3,5] this will be [0.5,1.5,2.5,4,6]
Note that n+1 points are returned for input of n points
'''
return np.concatenate( [[1.5*x[0] - x[1]/2], (x[:-1]+x[1:])/2, [1.5*x[-1] - x[-2]/2]] )
lenX = len(Xlist)
if lenX != len(Ylist):
raise Exception("uneqImgShow error: unequal list lengths")
figure.subplots_adjust(right=.85)
#print('vmin,vmax',vmin,vmax)
meshlist = []
for i,(X,Y) in enumerate(zip(Xlist,Ylist)):
#print(i,'X',min(X),max(X),'Y',min(Y),max(Y))
meshlist.append(
ax.pcolormesh(midPoints(X), [i-0.5,i+0.5], Y[np.newaxis,:],
cmap=cmap,vmin=vmin,vmax=vmax))
# label y axis with provided labels
if lenX == len(Ylbls):
pos = np.arange(lenX)
ax.set_yticks(pos,Ylbls)
# add the colorbar
ax1 = figure.add_axes([0.87, 0.1, 0.04, 0.8])
mpl.colorbar.ColorbarBase(ax1, cmap=cmap, norm=mpl.colors.Normalize(vmin,vmax))
# does not plot grid lines at present
# if mpl.rcParams['axes.grid']
[docs]
def initPartialOpts(phaseColors):
'''Make sure that the options for display of partials are all defined
'''
for p in phaseColors:
partialOpts[p] = partialOpts.get(p,{})
partialOpts[p]['Show'] = partialOpts[p].get('Show',True)
partialOpts[p]['color'] = partialOpts[p].get('color',phaseColors[p])
partialOpts[p]['width'] = partialOpts[p].get('width','1')
partialOpts[p]['style'] = partialOpts[p].get('style',2) # index in ltypeChoices/ltypeMPLname (see below)
partialOpts[p]['MPLstyle'] = partialOpts[p].get('MPLstyle','--')
[docs]
def configPartialDisplay(G2frame,phaseColors,RefreshPlot):
'''Select which phase are diplayed with phase partials and how they are
displayed
'''
def OnSelectColor(event):
'''Respond to a change in color
'''
p = event.GetEventObject().phase
c = event.GetValue()
# convert wx.Colour to mpl color string
partialOpts[p]['color'] = mpl.colors.to_hex(np.array(c.Get())/255)
phaseColors[p] = partialOpts[p]['color']
RefreshPlot()
def StyleChange(*args):
'define MPL line style from line style index'
for p in partialOpts:
try:
partialOpts[p]['MPLstyle'] = ltypeMPLname[partialOpts[p]['style']]
except:
partialOpts[p]['MPLstyle'] = '-'
RefreshPlot()
import wx.lib.colourselect as csel
dlg = wx.Dialog(G2frame,
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
mainSizer = wx.BoxSizer(wx.VERTICAL)
mainSizer.Add(
wx.StaticText(dlg,wx.ID_ANY,'Set options for display of Phase partials\n(profiles for each phase)',
style=wx.ALIGN_CENTER),
0,wx.ALIGN_CENTER)
mainSizer.Add((-1,10))
headers = ['phase name ',' Show ',' Color ','Width','Line type']
gsizer = wx.FlexGridSizer(cols=len(headers),hgap=2,vgap=2)
for h in headers:
txt = wx.StaticText(dlg,wx.ID_ANY,h)
txt.Wrap(150)
gsizer.Add(txt,0,wx.ALIGN_CENTER|wx.BOTTOM,6)
initPartialOpts(phaseColors)
for p in phaseColors:
txt = wx.StaticText(dlg,wx.ID_ANY,p)
txt.Wrap(150)
gsizer.Add(txt,0,wx.ALIGN_LEFT)
#
ch = G2G.G2CheckBox(dlg,'',partialOpts[p],'Show',RefreshPlot)
gsizer.Add(ch,0,wx.ALIGN_CENTER)
#
c = wx.Colour(mpl.colors.to_hex(partialOpts[p]['color']))
b = csel.ColourSelect(dlg, -1, '', c)
b.phase = p
b.Bind(csel.EVT_COLOURSELECT, OnSelectColor)
gsizer.Add(b,0,wx.ALL|wx.ALIGN_CENTER,3)
#
lwidChoices = ('0.5','0.7','1','1.5','2','2.5','3','4')
ch = G2G.G2ChoiceButton(dlg,lwidChoices,None,None,
partialOpts[p],'width',RefreshPlot,
size=(50,-1))
gsizer.Add(ch,0,wx.ALIGN_CENTER)
#
ltypeChoices = ('solid','dotted','dashed','dash-dot','dense dashed','dense dashdotted')
ltypeMPLname = ('-', ':', '--', '-.', (0, (5, 1)), (0, (3, 1, 1, 1)))
ch = G2G.G2ChoiceButton(dlg,ltypeChoices,
partialOpts[p],'style',
None,None,StyleChange)
gsizer.Add(ch,0,wx.ALIGN_CENTER)
mainSizer.Add(gsizer)
# OK/Cancel buttons
btnsizer = wx.StdDialogButtonSizer()
OKbtn = wx.Button(dlg, wx.ID_OK)
OKbtn.SetDefault()
btnsizer.AddButton(OKbtn)
btnsizer.Realize()
mainSizer.Add(btnsizer,5,wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER,0)
mainSizer.Layout()
dlg.SetSizer(mainSizer)
mainSizer.Fit(dlg)
dlg.ShowModal()
StyleChange()