Digital Micrograph에서 dm-script와 python간에 통신하는 방법
Digital Micrograph에서 실행되는 dm-script
코드와 python
코드를 어떻게 구분합니까 ?
내 특정한 경우에는 복잡한 대화 상자가 있습니다. 대화 상자는에서 지원되지 python
않지만에서는에서 dm-script
대화를 작성했습니다 dm-script
. 이제 문제는 대화 상자에서 파이썬 코드로 전달하는 것입니다.
다음 예를 고려하십시오.
import DigitalMicrograph as DM
script = """string field_value = "";
class ButtonDialog : UIFrame{
void field_changed(object self, TagGroup field){
field_value = field.DLGGetStringValue();
}
object init(object self){
TagGroup dlg, dlg_items, field;
dlg = DLGCreateDialog("Type in a number", dlg_items);
dlg.DLGAddElement(DLGCreateLabel("Number:"));
field = DLGCreateIntegerField(0, 10, "field_changed");
dlg.DLGAddElement(field);
self.super.init(dlg);
return self;
}
}
object dialog = alloc(ButtonDialog).init();
dialog.pose();
"""
DM.ExecuteScriptString(script)
# how do I get this?
field_value = ""
답변
Python 스크립트를 호출하는 DM 스크립트
이 답변은 Python과 DM 스크립트 간의 일부 통신을 보여 주지만 반대편을 형성합니다. 또한 영구 tagGroup을 전송 프록시로 사용합니다.
DM 스크립트에서 Python 안팎으로 간단한 값 전달
// //////////////////////////////////////////////////
// Helper methods
// Build the DM-String representing the PythonScript
// which is then called
// //////////////////////////////////////////////////
string AddPythonValueIN( number val, string valName, string valType )
{
string py
py += "\n#Get value DM->Python via global tags" + "\n"
py += "success, " + valName + " = DM.GetPersistentTagGroup().GetTagAs" + valType + "('Python_temp:in:" + valName + "')" + "\n"
py += "if False == success:" + "\n"
py += " print( 'Error. No value passed in by DM-script sucessfully.' )" + "\n"
py += " exit(0)" + "\n"
return py
}
string AddPythonValueIN( string val, string valName, string valType )
{
string py
py += "\n#Get value DM->Python via global tags" + "\n"
py += "success, " + valName + " = DM.GetPersistentTagGroup().GetTagAs" + valType + "('Python_temp:in:" + valName + "')" + "\n"
py += "if False == success:" + "\n"
py += " print( 'Error. No value passed in by DM-script sucessfully.' )" + "\n"
py += " exit(0)" + "\n"
return py
}
string AddPythonValueOut( string valName, string valType )
{
string py
py += "\n#Get value Python->DM via global tags" + "\n"
py += "DM.GetPersistentTagGroup().SetTagAs" + valType + "('Python_temp:out:" + valName + "'," + valName + ")" + "\n"
return py
}
string AddPythonPrintModifyPrint()
{
string py
py += "\n#Print InValue, modify, print OutValue" + "\n"
py += "print('InValue',InValue)"+ "\n"
py += "OutValue = InValue * 2" + "\n"
py += "print('OutValue',OutValue)"+ "\n"
return py
}
// //////////////////////////////////////////////////
// Example calls
// Demonstrating value passing from DM script to a
// called Python snippet. TagTypes need to be
// explicit in Python.
// //////////////////////////////////////////////////
void PythonValueInAndOut_Float()
{
number value = 13.2
GetPersistentTagGroup().TagGroupSetTagAsFloat("Python_temp:in:InValue",value)
Result( " DM-Script passed value in: " + value + "\n")
string py = "#Script to demonstrate value passing in Hybrid scripts. DM calling Python." + "\n"
py += AddPythonValueIN( value, "InValue", "Float" )
py += AddPythonPrintModifyPrint()
py += AddPythonValueOut( "OutValue", "Float" )
Result( "\n PYTHON CODE EXECUTES\n --------------------- \n\n" )
ExecutePythonScriptString( py, 1 )
Result( "\n --------------------- \n PYTHON CODE FINISHED \n\n" )
if ( !GetPersistentTagGroup().TagGroupGetTagAsFloat("Python_temp:out:OutValue",value))
Throw("Python value passed out not found.")
Result( "DM-Script received value: " + value + "\n")
GetPersistentTagGroup().TagGroupDeleteTagWithLabel("Python_temp")
}
void PythonValueInAndOut_Double()
{
number value = 13.2
GetPersistentTagGroup().TagGroupSetTagAsDouble("Python_temp:in:InValue",value)
Result( " DM-Script passed value in: " + value + "\n")
string py = "#Script to demonstrate value passing in Hybrid scripts. DM calling Python." + "\n"
py += AddPythonValueIN( value, "InValue", "Double" )
py += AddPythonPrintModifyPrint()
py += AddPythonValueOut( "OutValue", "Double" )
Result( "\n PYTHON CODE EXECUTES\n --------------------- \n\n" )
ExecutePythonScriptString( py, 1 )
Result( "\n --------------------- \n PYTHON CODE FINISHED \n\n" )
if ( !GetPersistentTagGroup().TagGroupGetTagAsDouble("Python_temp:out:OutValue",value))
Throw("Python value passed out not found.")
Result( "DM-Script received value: " + value + "\n")
GetPersistentTagGroup().TagGroupDeleteTagWithLabel("Python_temp")
}
void PythonValueInAndOut_String()
{
string value = "hallo"
GetPersistentTagGroup().TagGroupSetTagAsString("Python_temp:in:InValue",value)
Result( " DM-Script passed value in: " + value + "\n")
string py = "#Script to demonstrate value passing in Hybrid scripts. DM calling Python." + "\n"
py += AddPythonValueIN( value, "InValue", "String" )
py += AddPythonPrintModifyPrint()
py += AddPythonValueOut( "OutValue", "String" )
Result( "\n PYTHON CODE EXECUTES\n --------------------- \n\n" )
ExecutePythonScriptString( py, 1 )
Result( "\n --------------------- \n PYTHON CODE FINISHED \n\n" )
if ( !GetPersistentTagGroup().TagGroupGetTagAsString("Python_temp:out:OutValue",value))
Throw("Python value passed out not found.")
Result( "DM-Script received value: " + value + "\n")
GetPersistentTagGroup().TagGroupDeleteTagWithLabel("Python_temp")
}
ClearResults()
PythonValueInAndOut_float()
PythonValueInAndOut_double()
PythonValueInAndOut_string()
DM 스크립트에서 Python 안팎으로 이미지 데이터 전달
// Images and other objects which are in memory can be most easily passed
// by passing their ID value and then finding them by ID.
// However, this does not work if the object would go out of scope at the
// end of a script (like an image which is not displayed)
//
// To pass a NumpyArray out of Python without showing an image, one can
// instead write the array to the global tags directly, together with the
// information needed to read the tags out into a DM-image
void PythonImageInOut( )
{
image img := RealImage("test",4,5,5)
img = icol
Result( " DM-Script passed image ["+img.ImageGetLabel()+"] in.\n")
string py
py += "\n#Get image DM->Python via imageLabel" + "\n"
py += "img = DM.FindImageByID("+ img.ImageGetID()+")" + "\n"
py += "if None == img:" + "\n"
py += " print( 'Error.No image passed in by DM-script sucessfully.' )" + "\n"
py += " exit(0)" + "\n"
py += "\n"
py += "print('Image from DM: Label = ', img.GetLabel())" + "\n"
py += "print('Image from DM: Name = ', img.GetName())" + "\n"
py += "print('Image from DM: Value = \\n', img.GetNumArray())" + "\n"
py += "del img #ALWAYS delete DM objects in Python scripts" + "\n"
py += "\n"
py += "\n#Create DM image in Python and pass out as ID via global tags" + "\n"
py += "import numpy as np" + "\n"
py += "data = np.arange(48).reshape(6,8)" + "\n"
py += "outImg = DM.CreateImage(data.copy(order='C'))" + "\n"
py += "DM.GetPersistentTagGroup().SetTagAsLong('Python_temp:out:ID',outImg.GetID())" + "\n"
py += "print('Create new image with ID:',outImg.GetID())"+"\n"
py += "outImg.ShowImage() #Image needs to be shown or it will not stay in memory" + "\n"
py += "del outImg #ALWAYS delete DM objects in Python scripts" + "\n"
Result( "\n PYTHON CODE EXECUTES\n --------------------- \n\n" )
ExecutePythonScriptString( py, 1 )
Result( "\n --------------------- \n PYTHON CODE FINISHED \n\n" )
number imgID
if ( !GetPersistentTagGroup().TagGroupGetTagAsLong("Python_temp:out:ID",imgID))
Throw("Python imageID value passed out not found.")
image outImg := FindImageByID(imgID)
if ( !outImg.ImageIsValid() )
Throw("Python imageID value passed out but no matching image found.")
Result( "DM-Script received image: " + outImg.ImageGetLabel()+ "\n")
GetPersistentTagGroup().TagGroupDeleteTagWithLabel("Python_temp")
}
void PythonArrayOut( )
{
string py
py += "#Passing Numpy array values via global tags" + "\n"
py += "import numpy as np" + "\n"
py += "data = np.arange(6*8*3).reshape(6,8,3)" + "\n"
py += "outImg = DM.CreateImage(data.copy(order='C'))" + "\n"
py += "DM.GetPersistentTagGroup().SetTagAsArray('Python_temp:out:array',outImg)" + "\n"
py += "DM.GetPersistentTagGroup().SetTagAsLong('Python_temp:out:type',outImg.GetDataType())" + "\n"
py += "for i in range(data.ndim,0,-1):" + "\n"
py += " DM.GetPersistentTagGroup().SetTagAsLong('Python_temp:out:dim:' + str(i-1),data.shape[i-1])" + "\n"
py += "\n"
py += "del outImg #ALWAYS delete DM objects in Python scripts" + "\n"
Result( "\n PYTHON CODE EXECUTES\n --------------------- \n\n" )
ExecutePythonScriptString( py, 1 )
Result( "\n --------------------- \n PYTHON CODE FINISHED \n\n" )
number dataType
if ( !GetPersistentTagGroup().TagGroupGetTagAsLong("Python_temp:out:type",dataType))
Throw("Python dataType value passed out not found.")
TagGroup dimTG
if ( !GetPersistentTagGroup().TagGroupGetTagAsTagGroup("Python_temp:out:dim",dimTG))
Throw("Python dimensions passed out not found.")
number nDim = dimTG.TagGroupCountTags()
number n0, n1, n2, n3, n4
dimTG.TagGroupGetIndexedTagAsLong(0,n0)
dimTG.TagGroupGetIndexedTagAsLong(1,n1)
dimTG.TagGroupGetIndexedTagAsLong(2,n2)
dimTG.TagGroupGetIndexedTagAsLong(3,n3)
dimTG.TagGroupGetIndexedTagAsLong(4,n4)
image outImg
if ( 1 == nDim )
outImg := NewImage("Test", dataType, n0 )
else if ( 2 == nDim )
outImg := NewImage("Test", dataType, n0, n1 )
else if ( 3 == nDim )
outImg := NewImage("Test", dataType, n0, n1, n2 )
else if ( 4 == nDim )
outImg := NewImage("Test", dataType, n0, n1, n2, n3 )
else if ( 5 == nDim )
outImg := NewImage("Test", dataType, n0, n1, n2, n3, n4 )
if ( !GetPersistentTagGroup().TagGroupGetTagAsArray("Python_temp:out:array",outImg))
Throw("Python array data passed out not found.")
Result("\n DM recreated image from array values: " + outImg.ImageGetLabel()+ "\n")
GetPersistentTagGroup().TagGroupDeleteTagWithLabel("Python_temp")
}
clearresults()
Result("\n\nEXAMPLE Python<->DM image passing\n")
PythonImageInOut()
Result("\n\nEXAMPLE Python-->DM array passing\n")
PythonArrayOut( )
둘 다 동일한 인스턴스에서 실행되는 동안 dm-script
및 python
둘 다에서 데이터를 동기화하려면 (이 예제의 스레드는 다른 스레드에 대해서도 수정 가능) 영구 태그를 사용할 수 있습니다 .
는 dm-script
영구 태그를 설정하는 것입니다. python
그런 다음 영구 태그를 다시 읽을 수 있습니다.
업데이트 : Python 모듈
아래에 언급 된 제한 사항과 엄청나게 증가하고 읽을 수없는 코드 때문에이를 위해 자체 파이썬 모듈을 작성하기로 결정했습니다. 으로 execdmscript한 디지털 현미경 사진에서 아주 쉽게 변수 동기화 DM-스크립트 코드를 실행할 수 있습니다.
다음 예를 확인하십시오.
from execdmscript import exec_dmscript
# some script to execute
dmscript = """
number input;
number s = GetNumber("Enter a number between " + min + " and " + max + ".", init, input);"
"""
# variables that will be defined for the dm-scripts (and readable later on in python)
sv = {"min": 1, "max": 10, "init": 2}
# variables the dm-script defines and that should be readable in the python file
rv = {"input": "number", "s": "number"}
with exec_dmscript(dmscript, readvars=rv, setvars=sv) as script:
if script["s"]:
print(script["input"])
else:
print("User pressed cancel.")
이것은 모든 dm-script 관련 저장 및 문제 (아래에 언급)를 숨 깁니다. 그것은 사용할 수 있습니다 list
및 dict
S와 기본 유형이 좋아 bool
, str
, int
와 float
. 모든 유형과 값은 dm-script 유형에 대해 신경 쓸 필요없이 파이썬 방식으로 사용할 수 있습니다. dm-script는 코드를 더 정리하기 위해 별도의 파일로 이동할 수 있습니다.
디버깅 exec_dmscript(debug=True, debug_file="path/to/file")
을 위해 지정된 .NET Framework에 코드를 저장 하는 스위치가 debug_file
있습니다. 이 파일은 오류를 표시하는 GMS에서 수동으로 실행할 수 있습니다.
면책 조항 : 언급했듯이 나는 execdmscript모듈 의 저자입니다 . 그래도 이것이이 경우에 가장 좋은 해결책이라고 생각합니다. 사실이 질문이 제가 모듈을 작성한 이유였습니다.
기본 데이터 유형
기본 데이터 유형의 경우처럼 string
, 그리고 number
하나 만들고 손으로 코드를 추가 할 수 있습니다. 다음 예는 아이디어를 보여줍니다.
import DigitalMicrograph as DM
import time
sync_id = "sync-{}".format(int(time.time() * 100))
dmscript = """
number input;
number s = GetNumber("Enter a number between {min} and {max}.", {init}, input);
TagGroup p = GetPersistentTagGroup();
p.TagGroupSetTagAsBoolean("{id}-success", s);
p.TagGroupSetTagAsLong("{id}-input", input);
"""
DM.ExecuteScriptString(dmscript.format(min=1, max=10, init=2, id=sync_id))
# cannot save TagGroups to variables, check below
s, success = DM.GetPersistentTagGroup().GetTagAsBoolean("{}-success".format(sync_id))
if s and success:
# cannot save TagGroups to variables, check below
s, input = DM.GetPersistentTagGroup().GetTagAsLong("{}-input".format(sync_id))
if s:
print(input)
else:
print("Did not find 'input' in persistent tags.")
elif not s:
print("Did not find 'success' in persistent tags.")
else:
print("User clicked cancel.")
# cannot save TagGroups to variables, check below
# delete tag, otherwise the persistent tags gets filled with garbage
DM.GetPersistentTagGroup().DeleteTagWithLabel("{}-success".format(sync_id))
DM.GetPersistentTagGroup().DeleteTagWithLabel("{}-input".format(sync_id))
이 방법의 몇 가지 단점을 볼 수 있습니다. 하나의 숫자를 입력하기위한 설정 및 동기화를 생성하는 많은 코드가 있습니다. 이것은 코드를 지저분하게 만듭니다. 또한 Python 파일 열기를 추가하는 별도의 파일에 dm-script 코드를 저장하고 싶을 수도 있습니다. 이 코드에서도 dm-script 코드를 디버깅하는 것은 어렵습니다. 그리고 마지막으로 TagGroup이 파이썬 측으로 이동하는 데 제한이 있습니다 (아래 확인).
한계
업데이트 : 아래 언급 된 python 모듈은 TagGrou
s와 TagList
s를 선형화하고 별도의 키와 유형으로 저장하기 때문에 다룰 수 있습니다.
참고 것을 TagGroup
들 동기화하기가 매우 어렵습니다. TagGroup
는 변수에 할당되지 않아야합니다. 사용하면 더 이상 사용할 수 없습니다. 이것은 다음과 같은 매우 쉬운 코드로 설명 할 수 있습니다.
import DigitalMicrograph as DM
# create group for the example
group1 = DM.NewTagGroup()
group1.SetTagAsString("test-string", "test content")
print("Group 1 valid:", group1.IsValid(), "(type:", type(group1), ")")
# save to persistent tags
DM.GetPersistentTagGroup().SetTagAsTagGroup("test", group1)
# get the group without assigning to a variable, works
s, group2 = DM.GetPersistentTagGroup().GetTagAsTagGroup("test")
print("Group 2 success:", s, ", valid:", group2.IsValid(), "(type:", type(group2), ")")
# assign one parent group to a variable, doesn't work
tags = DM.GetPersistentTagGroup()
s, group3 = tags.GetTagAsTagGroup("test")
print("Group 3 success:", s, ", valid:", group3.IsValid(), "(type:", type(group3), ")")
이 코드는 출력을 생성합니다.
Group 1 valid: True (type: <class 'DigitalMicrograph.Py_TagGroup'> )
Group 2 success: True , valid: True (type: <class 'DigitalMicrograph.Py_TagGroup'> )
Group 3 success: True , valid: False (type: <class 'DigitalMicrograph.Py_TagGroup'> )
이것은 TagGroup
파이썬 변수에 s를 할당 할 수 없음을 보여줍니다 .
비동기 아이디어
이것은 비동기 애플리케이션을 위해 확장 될 수 있습니다. dm-script
과 python
구현은 지속적 태그를 관찰 스레드를 설정할 수 있습니다. ( TagGroup
를 사용하여 s를 수정 된 것으로 표시 할 수 있습니다 TagGroupMarkAsChanged()
.), 아마도 다른 태그입니다. 그런 다음 둘 다 명령 및 / 또는 데이터를 태그에 추가 할 수 있습니다. 다른 "인스턴스"는이를 읽고 처리 할 수 있습니다.
수동으로 코딩해야합니다. 이것은 (현재) execdmscript
모듈에 포함되어 있지 않습니다 .