OpTaliX: Transverse ray fan plot with Python (plotly)

1.3. OpTaliX: Transverse ray fan plot with Python (plotly)

This section describes how an OpTaliX macro “ray_fan.mac” can be used to write the transverse ray fan data of an optical system opened in OpTaliX (here: Mobile_US20070024958A1.OTX) to an ascii file. This file is then read with Python and the transverse ray fans are plotted with “plotly”.

Content of the macro “ray_fan.mac”:

! Get transverse ray aberration fan data
!
print "start."

$nfi = 4    ! number of fields defined
$nwl = 3    ! number of fields defined


out fil C:\Work\OpTaliX\Test\ray_fan_py.txt   ! redirect output to file

print "C number of wavelengths, number of fields: "
print $nwl $nfi
do $wl = 1, $nwl
	$wavelength = [WL w$wl]
	print $wl $wavelength
enddo

do $fi = 1, $nfi
	$fxan = [XAN f$fi]
	$fyan = [YAN f$fi]
	print 'format I3 F13.9 ,F13.9' $fi $fxan $fyan
enddo
!
$maxfl = [si]           ! get number of surfaces
$py = 1
$px = 1
$dpy = 0.01
$dpx = 0.01
glo no    ! means xyz relative to local surface vertex
! does not work with glo yes

do $wl = 1, $nwl
   do $fi = 1, $nfi
      do $p = -$py,$py, $dpy
         $y = [y s$maxfl f$fi w$wl 0 $p]
         print 'format I3, I3, F13.9 ,F13.9' $wl $fi $p $y  
      enddo
   enddo
enddo
!
out t                   ! redirect output to terminal (windows)

$fi = 1
$nfi = 4

out fil C:\Work\OpTaliX\Test\ray_fan_px.txt   ! redirect output to file
!
do $wl = 1, $nwl
   do $fi = 1, $nfi
      do $p = -$px,$px, $dpx
         $x = [x s$maxfl f$fi w$wl $p 0]
         print 'format I3, I3, F13.9, F13.9' $wl $fi $p $x  
      enddo
   enddo
enddo
!

out t                   ! redirect output to terminal (windows)
print "finished px and py ray fans."

Now the python code for plotting with plotly:

# -*- coding: utf-8 -*-
"""
Created on Wed Apr  6 15:52:19 2022

@author: herbst
"""
import numpy as np
import matplotlib.pylab as plt
import plotly.express as px
import plotly.graph_objs as go
from plotly.subplots import make_subplots
from plotly.colors import n_colors
import time 

t0 = time.perf_counter()


def find_nearest(array, value):
    array = np.asarray(array)
    idx = (np.abs(array - value)).argmin()
    return array[idx]

filename_py = r'C:\Work\OpTaliX\Test\RAY_FAN_PY.txt'
nwavelengths = int(np.loadtxt(filename_py, comments = 'C',max_rows=1)[0])
nfields = int(np.loadtxt(filename_py, comments = 'C',max_rows=1)[1])
wavelengths = np.loadtxt(filename_py, comments = 'C',skiprows = 2, max_rows=nwavelengths)[:,1]
fields = np.loadtxt(filename_py, comments = 'C',skiprows = 2+nwavelengths, max_rows=nfields)

rayfandata_py = np.loadtxt(filename_py, comments = 'C', skiprows = nwavelengths+2+nfields)

filename_px = r'C:\Work\OpTaliX\Test\RAY_FAN_PX.txt'
rayfandata_px = np.loadtxt(filename_px, comments = 'C', skiprows = nwavelengths+2+nfields)

n_fields = len(fields)
Lim = 0.02    # mm
#nwavelengths = 3

rayfandata_px_L= []
rayfandata_py_L = []
rayfandata_PY0_L = []
for w in range(0, nwavelengths):
    #print("w = ", w)
    rayfandata_px_LL = []
    rayfandata_py_LL = []
    rayfandata_px0 = rayfandata_px[rayfandata_px[:,0]==w+1]
    rayfandata_py0 = rayfandata_py[rayfandata_py[:,0]==w+1]                 # select data by wavelength
    

    
    for i in range(0, n_fields):
        rayfandata_px_LL.append(rayfandata_px0[rayfandata_px0[:,1]==i+1])
        rayfandata_PY = rayfandata_py0[rayfandata_py0[:,1]==i+1]            # select data by field
        

        if w == 0:
            rayfandata_PY0 = rayfandata_PY[np.where(rayfandata_PY[:,2] == find_nearest( rayfandata_PY[:,2], value = 0))[0],3][0]
            rayfandata_PY0_L.append(rayfandata_PY0)
        rayfandata_PY[:,3] -= rayfandata_PY0_L[i]
        #print("i = ", i, " , rayfandata_PY0: ", rayfandata_PY0)
        rayfandata_py_LL.append(rayfandata_PY)
    rayfandata_px_L.append(rayfandata_px_LL)
    rayfandata_py_L.append(rayfandata_py_LL)
    

plot = 1
if plot:
    
    
    if 0:
        import plotly.express as px
        
        fig = px.line(x=rayfandata_px[:,0], y=rayfandata_px[:,1],line_shape="spline")
        fig.show(renderer="browser")
    Titles = ('tangential (ey over py)','sagittal (ex over px)')
    names = ('field 1','field 2', 'field 3', 'field4')
    
    def to_rgb(name):
        from matplotlib import colors
        import matplotlib.cm
        C = colors.to_rgba(name)
        c = 'rgb'+str((C[0], C[1], C[2]))
        return c
    # with OpTaliX Field colors:
    #colors = (to_rgb('blue'),to_rgb('green'),to_rgb('red'))#, to_rgb('magenta'), to_rgb('cyan'),to_rgb('yellow'), to_rgb('orange'), to_rgb('mediumpurple'), to_rgb('lightseagreen'))
    colors = px.colors.sample_colorscale("jet", [n/(nwavelengths -1) for n in range(nwavelengths)])
    # sort data by wavelength
    sortedw = np.argsort(wavelengths)
    
    row_L = np.array([1,2,3,4])
    fig = make_subplots(rows=n_fields,cols=2, vertical_spacing=0.1,
                      horizontal_spacing=0.1,
                      subplot_titles=Titles,
                      shared_yaxes='all',
                      x_title='normalized pupil coordinate (referenced to entrance pupil)',
                      y_title='transverse aberration e / mm')
    for w in range(0, nwavelengths):
        if w == 0:
            mode = 'lines'#'+markers'
            line = dict(shape = 'linear',dash = "dash")
        elif w == 1:
            mode = 'lines'
            line = dict(shape = 'linear')
        elif w == 2:
            line = dict(shape = 'linear',dash = "dot")
        for i in range(0, n_fields):
            if i == 0:
                showlegend1=True
                showlegend2=False
            else:
                showlegend1=False
                showlegend2=False
            
            fig.add_scatter(x=rayfandata_py_L[sortedw[w]][i][1:-1,2], y=rayfandata_py_L[sortedw[w]][i][1:-1,3], mode=mode, line = line, row = row_L[i], col=1, name=wavelengths[sortedw[w]], marker_color = colors[w], showlegend = showlegend2)
    
            fig.add_scatter(x=rayfandata_px_L[sortedw[w]][i][1:-1,2], y=rayfandata_px_L[sortedw[w]][i][1:-1,3], mode=mode, line = line, row = row_L[i], col=2, name=str(wavelengths[sortedw[w]]*1e3)+' nm', marker_color = colors[w], showlegend = showlegend1)
            
            if w == 0:
                fig.add_annotation(x=0, y=Lim*0.75,
                            text="XAN, YAN = ("+str(np.round(fields[i,1],decimals=2))+ ", "+str(np.round(fields[i,2],decimals=2))+')°',
                            showarrow=False,
                            arrowhead=0,
                            row = row_L[i],
                            col=1)
                fig.add_annotation(x=0, y=Lim*0.75,
                            text="XAN, YAN = ("+str(np.round(fields[i,1],decimals=2))+ ", "+str(np.round(fields[i,2],decimals=2))+')°',
                            showarrow=False,
                            arrowhead=0,
                            row = row_L[i],
                            col=2)

    fig.update_xaxes(range=[-1, 1], dtick=1/2)
    fig.update_yaxes(range=[-Lim, Lim], dtick=Lim/2)
    fig.update_layout(height=900, width=900, template= 'seaborn')  # 'simple_white'
    fig.show()

    
    
        
    
print("Elapsed time: ", np.round(time.perf_counter()-t0, decimals = 4), " s")
Elapsed time:  2.0045  s
_images/OpTaliX_plotly_ray_fan_5_0.png