ReplicatePythonCallback
This page gives an example of using Python callbacks. It tries to keep the state of plots and operators in a two window configuration to be consistent. That is, if a plot or operator is added, deleted, or modified in either window, it attempts to make the same change in the other window.
Issues:
- By making a change in the other window, you are generating more actions, meaning your callbacks will get called again! This script has infrastructure for this.
- There appears to be a weird Python bug where global variables cannot be used with the comparison operator (==). That is coded around here.
- It only works for some of the RPCs and can probably be easily defeated if you try...
Here is the Python code:
# Script: replicate.py
# Purpose: This script will causing actions happening in each of two windows
# to be mirrored to the other window.
#
# Note: This script uses VisIt's Python Callback mechanism. This mechanism
# can be tricky to use, because actions done from within the script
# can cause more callbacks to be executed. For example, suppose the
# user adds a plot in window 1. This will call a callback in this script.
# And the callback will add the same plot in window 2. But this new
# add plot call will be interpreted as a new event. So the callback
# will be called again. But we really don't want it to be. So we
# detect this case and avoid the second invocation of the callback.
#
# Programmer: Hank Childs
# Creation: May 6, 2008
#
#
import time
print "Starting replicate script..."
activeWindow = 1
numberOfSetActiveWindowsToIgnore = 0
numberToIgnore = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
def IssueMessage(s):
ClientMethod("MessageBoxOk", str(s))
def SetOppositeWindowAsActive():
global activeWindow
# Python objects to using activeWindow directly when coming
# from DeleteActivePlotsCallback. Appears to be a Python bug
t=int(str(activeWindow))
if t == 1:
SetActiveWindow(2)
else:
SetActiveWindow(1)
global numberOfSetActiveWindowsToIgnore
numberOfSetActiveWindowsToIgnore += 1
def RestoreActiveWindow():
global activeWindow
# Python objects to using activeWindow directly when coming
# from DeleteActivePlotsCallback. Appears to be a Python bug
t=int(str(activeWindow))
SetActiveWindow(t)
global numberOfSetActiveWindowsToIgnore
numberOfSetActiveWindowsToIgnore += 1
def MapCallbackToIndex(s):
if s == "AddPlot":
return 0
elif s == "AddOperator":
return 1
elif s == "DrawPlots":
return 2
elif s == "SetOperatorOptions":
return 9
elif s == "SetPlotOptions":
return 4
elif s == "ChangeActivePlotsVar":
return 5
elif s == "RemoveLastOperator":
return 6
elif s == "RemoveAllOperators":
return 7
elif s == "RemoveOperator":
return 8
elif s == "DeleteActivePlots":
return 3
elif s == "SetActivePlots":
return 10
else:
return -1
def StartCallback(s):
idx = MapCallbackToIndex(s)
global numberToIgnore
if numberToIgnore[idx] > 0:
numberToIgnore[idx] -= 1
return 1
else:
numberToIgnore[idx] += 1
SetOppositeWindowAsActive()
return 0
def EndCallback(s):
RestoreActiveWindow()
def AddPlotCallback(type, var):
if StartCallback("AddPlot") != 0:
return
AddPlot(PlotPlugins()[type], var)
EndCallback("AddPlot")
def AddOperatorCallback(type, fromDefault):
if StartCallback("AddOperator") != 0:
return
AddOperator(OperatorPlugins()[type])
EndCallback("AddOperator")
def DrawPlotsCallback(drawAllPlots):
if StartCallback("DrawPlots") != 0:
return
DrawPlots()
EndCallback("DrawPlots")
def SetPlotOptionsCallback(type):
pl = GetPlotList()
gotOne = 0
nplots = pl.GetNumPlots()
for i in range(nplots):
plot = pl.GetPlots(i)
if plot.activeFlag:
atts = GetPlotOptions()
gotOne = 1
if StartCallback("SetOperatorOptions") != 0:
return
if gotOne == 1:
SetPlotOptions(atts)
else:
print "Could not find the plot atts to set"
EndCallback("SetOperatorOptions")
def SetOperatorOptionsCallback(type):
# Note: probably won't work if there are multiple
# operators of the same type in a plot.
pl = GetPlotList()
gotOne = 0
nplots = pl.GetNumPlots()
for i in range(nplots):
plot = pl.GetPlots(i)
if plot.activeFlag:
noperators = len(plot.operators)
for j in range(noperators):
if plot.operators[j] == type:
atts = GetOperatorOptions(j)
gotOne = 1
if StartCallback("SetOperatorOptions") != 0:
return
if gotOne == 1:
SetOperatorOptions(atts)
else:
print "Could not find the operator atts to set"
EndCallback("SetOperatorOptions")
def SetActivePlotsCallback(plots, activeOp):
if StartCallback("SetActivePlots") != 0:
return
SetActivePlots(plots)
EndCallback("SetActivePlots")
def RemoveLastOperatorCallback():
if StartCallback("RemoveLastOperator") != 0:
return
RemoveLastOperator()
EndCallback("RemoveLastOperator")
def RemoveOperatorCallback(idx):
if StartCallback("RemoveOperator") != 0:
return
RemoveLastOperator(idx)
EndCallback("RemoveOperator")
def RemoveAllOperatorsCallback():
if StartCallback("RemoveAllOperators") != 0:
return
RemoveAllOperators()
EndCallback("RemoveAllOperators")
def DeleteActivePlotsCallback():
if StartCallback("DeleteActivePlots") != 0:
return
DeleteActivePlots()
EndCallback("DeleteActivePlots")
def ChangeActivePlotsVarCallback(var):
if StartCallback("ChangeActivePlotsVar") != 0:
return
pl = GetPlotList()
nplots = pl.GetNumPlots()
for i in range(nplots):
plot = pl.GetPlots(i)
if plot.activeFlag:
ChangeActivePlotsVar(var)
EndCallback("ChangeActivePlotsVar")
def SetActiveWindowCallback(id):
global numberOfSetActiveWindowsToIgnore
if numberOfSetActiveWindowsToIgnore > 0:
numberOfSetActiveWindowsToIgnore -= 1
return
global activeWindow
activeWindow = id
RegisterCallback("AddPlotRPC", AddPlotCallback)
RegisterCallback("DeleteActivePlotsRPC", DeleteActivePlotsCallback)
RegisterCallback("AddOperatorRPC", AddOperatorCallback)
RegisterCallback("DrawPlotsRPC", DrawPlotsCallback)
RegisterCallback("SetOperatorOptionsRPC", SetOperatorOptionsCallback)
RegisterCallback("SetPlotOptionsRPC", SetPlotOptionsCallback)
RegisterCallback("ChangeActivePlotsVarRPC", ChangeActivePlotsVarCallback)
RegisterCallback("RemoveAllOperatorsRPC", RemoveAllOperatorsCallback)
RegisterCallback("RemoveLastOperatorRPC", RemoveLastOperatorCallback)
RegisterCallback("RemoveOperatorRPC", RemoveOperatorCallback)
RegisterCallback("SetActivePlotsRPC", SetActivePlotsCallback)
RegisterCallback("SetActiveWindowRPC", SetActiveWindowCallback)
SetWindowLayout(2)
SetActiveWindow(1)
OpenGUI()
time.sleep(3)
IssueMessage("You are using the replicate script, which ensures "
"that plots from two windows are kept in synch. Before making "
"plots, open a file, activate window 2, and then open another file.")