<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Using ipzCaptureWindow and ipzCaptureWindow2 for embedding graphic analysis windows into notebook
<img src="https
Step1:  Load a lens file
Step2:  Perform a quick-focus
Step3:  Example of a Layout plot
Using ipzCaptureWindow to directly embed a Layout plot into the notebook.
Step4:  Why do we need to set gamma? 
 Is there one gamma value good for all analysis window rendering? 
Upto Zemax13 there was no way to control othe thickness of the lines produced by ZEMAX for the metafiles. Generally the lines produced were very thin and the rescaled version would be too light to be visible. One way in which this problem was addressed is to lowpass filter the original image, rescale and then use a gamma value less than one during the conversion from metafile to PNG. This is probably not the optimal solution. One obvious side effect is that the black text becomes very thick and ugly.
Instead of embedding the figure directly, we can also get a pixel array using PyZDDE. Plotting the returned array using matplotlib may allow more control and annotation options as shown below
Step5:  Now that we have the pixel array, we can either use the convenience function provided in PyZDDE to make a quick plot, or make our own figure and plot as we want it.
Let's first see how we can use the convenience function, imshow(), provided by PyZDDE to make a cropped plot. The functions takes as input the pixel array, a tuple indicating the number of pixels to crop from the left, right, top, bottom sides of the pixel array, a tuple indicating the matplotlib figure size (optional), and a title string (optional).
Step6:  Next, we will create a figure and direct PyZDDE to render the Layout plot in the provided figure and axes. We can then annotate the figure as we like.
But first we will get some first-order properties of the lens
Step7:  Example of Ray Fan plot
Step8:  Example of Spot diagram
Step9:  Examples of using ipzCaptureWindowLQ() function in Zemax 13.2 or earlier
ipzCaptureWindowLQ() is useful for quickly capturing a graphic window, and embedding into an IPython notebook or QtConsole.
In order to use this function, please copy the ZPL macros from "PyZDDE\ZPLMacros" to the macro directory where Zemax is expecting the ZPL macros to be (i.e. the folder set in Zemax->Preference->Folders->ZPL).
For this particular example, the macro folder path is set to "C
Step10:  Note that the above command didn't work, because we need to push the lens from the DDE server to the Zemax main window first. Then we also need to open each window.
Step11:  Now open the layout analysis window in Zemax. Assuming that this is the first analysis window that has been open, Zemax would have assigned the number 1 to it.
Step12:  Open the MTF analysis window in Zemax now.
Step13:  Examples of using ipzCaptureWindowLQ() function in Zemax 14 or later (OpticStudio)
In order to do this experiment, a new instance of Zemax 15 was opened, and new link created.
Step14:  Now open the layout analysis window in OpticStudio as before.
Step15:  Open FFT MTF analysis window
Step16:  Next, the FFT PSF analysis window was opened
Step17:  A few others .... just for show
<ASSISTANT_TASK:>
Python Code:
import os
import matplotlib.pyplot as plt
import pyzdde.zdde as pyz
%matplotlib inline
l = pyz.createLink() # create a DDE link object for communication
Explanation: Using ipzCaptureWindow and ipzCaptureWindow2 for embedding graphic analysis windows into notebook
<img src="https://raw.githubusercontent.com/indranilsinharoy/PyZDDE/master/Doc/Images/articleBanner_01_ipzcapturewindow.png" height="230">
Please feel free to e-mail any corrections, comments and suggestions to the author (Indranil Sinharoy)  
Last updated: 12/27/2015
License: Creative Commons Attribution 4.0 International
<font color='red'>NOTE:</font>
The current version of OpticStudio doesn't support function the function ipzCaptureWindow(). This is because the dataitem GetMetaFile has been deprecated. However, the function ipzCaptureWindowLQ() works fine as it uses ZPL macro to grap a snapshot of an open graphics window.
Both functions works just fine in Zemax version 13.2 and earlier.
Why are there two functions for doing the same thing?
In this notebook we explore the different use cases of the functions ipzCaptureWindow() and ipzCaptureWindowLQ().
<font color='red'>ipzCaptureWindowLQ()</font>
ipzCaptureWindowLQ(), which takes as input a window number, uses ZPL macros to retrieve a "screenshot" from Zemax main application (note the window open in the main application is retrieved and not in the DDE server). The number is assigned by Zemax when an analysis window is opened in Zemax, and is not tied to any specific analysis. The quality of the rendered image is dependent on the quality of the JPEG image provided by Zemax. Frankly, I haven't found the quality to be any qood. The "LQ" in the name of the function indicates low-quality. For using ipzCaptureWindowLQ() we will also need to specify the ZPL macro path to PyZDDE.  
<font color='red'>ipzCaptureWindow()</font>
ipzCaptureWindow() generally produces better quality graphis. It takes as input the 3-letter string code for the type of analysis. It uses zGetMetaFile() to request ZEMAX to output a windows metafile (standard or enhanced), resizes and converts into a PNG image using ImageMagick and embeds into a notebook cell. Note that since it uses zGetMetaFile(), the analysis window from the DDE server is retrieved unlike in the case of ipzCaptureWindowLQ(). We can also ask ipzCaptureWindow() not to render the PNG image; instead to return the pixel array as a Numpy ndarray. We can then use any graphic rendering tool such as matplotlib to manipulate, render and annotate the graphic. This notebook mainly focuses on ipzCaptureWindow().   
ipzCaptureWindowLQ() is much quicker than ipzCaptureWindow() as it doesn't have to do any intermediate image conversions. It is meant for quick interactive use (provided the ZPL macro path is provided to PyZDDE as explained later). ipzCaptureWindow() provides more flexibility and better quality images, though it is a little slower than ipzCaptureWindowLQ().
Note that it is assumed that PyZDDE is in the Python search path.
Import PyZDDE and create a pyzdde communication object
End of explanation
zfile = os.path.join(l.zGetPath()[1], 'Sequential', 'Objectives', 'Cooke 40 degree field.zmx')
l.zLoadFile(zfile)
Explanation: Load a lens file
End of explanation
l.zQuickFocus()
Explanation: Perform a quick-focus
End of explanation
l.ipzCaptureWindow('Lay', percent=15, gamma=0.4)
Explanation: Example of a Layout plot
Using ipzCaptureWindow to directly embed a Layout plot into the notebook.
End of explanation
arr = l.ipzCaptureWindow('Lay', percent=15, gamma=0.08, retArr=True)
Explanation: Why do we need to set gamma? 
 Is there one gamma value good for all analysis window rendering? 
Upto Zemax13 there was no way to control othe thickness of the lines produced by ZEMAX for the metafiles. Generally the lines produced were very thin and the rescaled version would be too light to be visible. One way in which this problem was addressed is to lowpass filter the original image, rescale and then use a gamma value less than one during the conversion from metafile to PNG. This is probably not the optimal solution. One obvious side effect is that the black text becomes very thick and ugly.
Instead of embedding the figure directly, we can also get a pixel array using PyZDDE. Plotting the returned array using matplotlib may allow more control and annotation options as shown below:
End of explanation
pyz.imshow(arr, cropBorderPixels=(5, 5, 1, 90), figsize=(10,10), title='Layout Plot')
Explanation: Now that we have the pixel array, we can either use the convenience function provided in PyZDDE to make a quick plot, or make our own figure and plot as we want it.
Let's first see how we can use the convenience function, imshow(), provided by PyZDDE to make a cropped plot. The functions takes as input the pixel array, a tuple indicating the number of pixels to crop from the left, right, top, bottom sides of the pixel array, a tuple indicating the matplotlib figure size (optional), and a title string (optional).
End of explanation
l.ipzGetFirst()
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
# Render the array
pyz.imshow(arr, cropBorderPixels=(5, 5, 1, 90), fig=fig, faxes=ax)
ax.set_title('Layout plot', fontsize=16)
# Annotate Lens numbers
ax.text(41, 70, "L1", fontsize=12)
ax.text(98, 105, "L2", fontsize=12)
ax.text(149, 89, "L3", fontsize=12) 
# Annotate the lens with radius of curvature information
col = (0.08,0.08,0.08)
s1_r = 1.0/l.zGetSurfaceData(1,2)
ax.annotate("{:0.2f}".format(s1_r), (37, 232), (8, 265), fontsize=12, 
                arrowprops=dict(arrowstyle="->", linewidth=0.45, color=col, relpos=(0.5,0.5)))
s2_r = 1.0/l.zGetSurfaceData(2,2)
ax.annotate("{:0.2f}".format(s2_r), (47, 232), (50, 265), fontsize=12, 
                arrowprops=dict(arrowstyle="->", linewidth=0.45, color=col,  relpos=(0.5,0.5)))
s6_r = 1.0/l.zGetSurfaceData(6,2)
ax.annotate("{:0.2f}".format(s6_r), (156, 218), (160, 251), fontsize=12, 
                arrowprops=dict(arrowstyle="->", linewidth=0.45, color=col,  relpos=(0.5,0.5)))
ax.text(5, 310, "Cooke Triplet, EFL = {} mm, F# = {}, Total track length = {} mm"
        .format(50, 5, 60.177), fontsize=14) 
plt.show()
Explanation: Next, we will create a figure and direct PyZDDE to render the Layout plot in the provided figure and axes. We can then annotate the figure as we like.
But first we will get some first-order properties of the lens
End of explanation
l.ipzCaptureWindow('Ray', percent=17, gamma=0.55)
rarr = l.ipzCaptureWindow('Ray', percent=25, gamma=0.15, retArr=True)
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
pyz.imshow(rarr, cropBorderPixels=(5, 5, 48, 170), fig=fig, faxes=ax)
ax.set_title('Transverse Ray Fan Plot for OBJ: 20.00 (deg)', fontsize=14)
plt.show()
Explanation: Example of Ray Fan plot
End of explanation
l.ipzCaptureWindow('Spt', percent=16, gamma=0.5)
sptd = l.ipzCaptureWindow('Spt', percent=25, gamma=0.15, retArr=True)
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(111)
pyz.imshow(sptd, cropBorderPixels=(150, 150, 30, 180), fig=fig, faxes=ax)
ax.set_title('Spot diagram for OBJ: 20.00 (deg)', fontsize=14)
plt.show()
Explanation: Example of Spot diagram
End of explanation
l.zSetMacroPath(r"C:\PROGRAMSANDEXPERIMENTS\ZEMAX\Macros")
l.ipzCaptureWindowLQ(1)
Explanation: Examples of using ipzCaptureWindowLQ() function in Zemax 13.2 or earlier
ipzCaptureWindowLQ() is useful for quickly capturing a graphic window, and embedding into an IPython notebook or QtConsole.
In order to use this function, please copy the ZPL macros from "PyZDDE\ZPLMacros" to the macro directory where Zemax is expecting the ZPL macros to be (i.e. the folder set in Zemax->Preference->Folders->ZPL).
For this particular example, the macro folder path is set to "C:\PROGRAMSANDEXPERIMENTS\ZEMAX\Macros"
End of explanation
l.zPushLens()
Explanation: Note that the above command didn't work, because we need to push the lens from the DDE server to the Zemax main window first. Then we also need to open each window.
End of explanation
l.ipzCaptureWindowLQ(1)
Explanation: Now open the layout analysis window in Zemax. Assuming that this is the first analysis window that has been open, Zemax would have assigned the number 1 to it.
End of explanation
l.ipzCaptureWindowLQ(2)
pyz.closeLink()
Explanation: Open the MTF analysis window in Zemax now.
End of explanation
l = pyz.createLink()
zfile = os.path.join(l.zGetPath()[1], 'Sequential', 'Objectives', 'Cooke 40 degree field.zmx')
l.zLoadFile(zfile)
l.zPushLens()
# Set the macro path
l.zSetMacroPath(r"C:\PROGRAMSANDEXPERIMENTS\ZEMAX\Macros")
Explanation: Examples of using ipzCaptureWindowLQ() function in Zemax 14 or later (OpticStudio)
In order to do this experiment, a new instance of Zemax 15 was opened, and new link created.
End of explanation
l.ipzCaptureWindowLQ(1)
Explanation: Now open the layout analysis window in OpticStudio as before.
End of explanation
l.ipzCaptureWindowLQ(2)
Explanation: Open FFT MTF analysis window
End of explanation
l.ipzCaptureWindowLQ(3)
Explanation: Next, the FFT PSF analysis window was opened
End of explanation
l.ipzCaptureWindowLQ(4) # Shaded Model
l.close()
Explanation: A few others .... just for show
End of explanation
<END_TASK>