Skip to content

Commit

Permalink
switch to PyQt5 backend
Browse files Browse the repository at this point in the history
  • Loading branch information
Z-H-Sun committed May 18, 2020
1 parent b6823b6 commit 3364e4e
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 402 deletions.
Binary file modified Compile/1.ico
Binary file not shown.
3 changes: 2 additions & 1 deletion Compile/Make.bat
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pyinstaller -F --version-file=v.txt --icon=1.ico ../FETAnal.py
set PATH=C:\mingw64\bin;%PATH%
nuitka --mingw64 --show-progress --show-memory --show-modules --standalone --recurse-all --recurse-not-to=numpy,matplotlib --windows-icon="%~dp0\1.ico" ../FETAnal
44 changes: 0 additions & 44 deletions Compile/v.txt

This file was deleted.

17 changes: 0 additions & 17 deletions Config.ini

This file was deleted.

65 changes: 47 additions & 18 deletions FETAnal
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,25 @@

from __future__ import print_function
import os
import sys
import time
import warnings
import numpy
from matplotlib.pyplot import *
import xlrd

# preparatory work
print('\033]0;FET Analyser v1.04 by Z. Sun\a')
warnings.simplefilter('ignore', np.RankWarning) # turn off polyfit warnings
if hasattr(__builtins__, 'raw_input'): input = raw_input
if os.name == 'nt': os.system('title FET Analyzer v1.041 by Z. Sun')
else: print('\033]0;FET Analyser v1.041 by Z. Sun\a')
warnings.simplefilter('ignore', numpy.RankWarning) # turn off polyfit warnings
warnings.simplefilter('ignore', UserWarning) # turn off matplotlib/font-not-found warnings
thisDir = os.path.abspath(os.path.dirname(sys.argv[0])) # where this script locates

try: f = open(os.path.join(thisDir, 'Config.ini')); exec(f.read()); f.close() # definitions
except: print('Config file missing or damaged.'); os._exit(-1)
try: f = open(os.path.join(thisDir, 'FETAnal.config')); exec(f.read()); f.close() # definitions
except:
print('Config file missing or damaged.')
if os.name == 'nt': os.system('pause')
os._exit(-1)

autowl = (W == 0 or L == 0) # read W & L in filenames
if DIELECTRIC < 0:
Expand All @@ -29,12 +34,20 @@ if DIELECTRIC == 2: # For BCB, serial connection
cp = cp*cp0/(cp+cp0)

if len(sys.argv) == 1:
print('Enter "-config" or .xls files or their path here (drag-drop supported): ', end='')
os.system('"' + sys.argv[0] + '" ' + raw_input().strip())
print('\nEnter `-config\' or .xls files array or their path here (drag-drop supported): ', end='')
if os.name == 'nt':
cmdline = '"' + sys.argv[0] + '" ' + input()
if '.py' in sys.argv[0]: cmdline = 'python ' + cmdline # if $0 is a .py script rather than an executable file
else: cmdline = 'cmd /c "' + cmdline + '"' # I really hate to employ such a circuitous way, but `os.system' has an annoying bug when handling commands with space sign and multiple quoted arguments
# please refer to https://bugs.python.org/issue1524 (a ten-year-old issue yet not resolved)
else: cmdline = '"' + sys.argv[0] + '" ' + input().strip()
os.system(cmdline)
os._exit(0)
if sys.argv[1].lower() == "-config":
os.chdir(thisDir)
os.system('vi config.ini'); os._exit(0)
if os.name == 'nt': os.system('start notepad FETAnal.config')
else: os.system('vi config.ini')
os._exit(0)

print('\nPlease check the following parameters:\nCapacitance [F/cm^2]\tW/L [μm]\tCol # of V_gs/√I_d')
print("\t%.2E\t%d/%d\t\t%d/%d" % (cp, W, L, ColGateV, ColIDrain))
Expand All @@ -49,7 +62,10 @@ else:
try:
os.chdir(path)
if not os.path.exists('Results'): os.mkdir('Results')
except: print("Path not applicable."); os._exit(-1)
except:
print("Path not applicable.")
if os.name == 'nt': os.system('pause')
os._exit(-1)


def savitzky_golay(y): # Smooth data with a Savitzky-Golay filter (in fact incorporated in scipy.signal)
Expand Down Expand Up @@ -113,11 +129,24 @@ def on_scroll(event):
event.canvas.figure.clear()
plot_sp() # plot the previous/next figure
event.canvas.draw()

fl = open('Results/Results_' + time.strftime('%m%d%y_%H%M%S') + '.csv', 'w')
fd = open('Results/Data_' + time.strftime('%m%d%y_%H%M%S') + '.csv', 'w')

def open2(filename):
if sys.version_info.major >= 3: # Python 3 supports UTF-8
f = open(filename, 'w', encoding='utf-8')
f.write('\uFEFF') # BOM
return f
else:
return open(filename, 'w')

def checkUTF8(str):
if sys.version_info.major < 3: # Python 2 does not support UTF-8
return str.replace('μ', '\\mu').replace('√', '\\sqrt ')
else: return str

fl = open2('Results/Results_' + time.strftime('%m%d%y_%H%M%S') + '.csv')
fd = open2('Results/Data_' + time.strftime('%m%d%y_%H%M%S') + '.csv')
print('\nName\t\t\tμ_f [cm^2 / (V s)]\tV_thf [V]\tμ_b [cm^2 / (V s)]\tV_thb [V]\tI_On/I_Off')
fl.write('Entry,Name,\\mu_f[cm^2/(V s)],V_thf[V],\\mu_b[cm^2/(V s)],V_thb[V],I_On/I_Off\n')
fl.write(checkUTF8('Entry,Name,μ_f[cm^2/(V s)],V_thf[V],μ_b[cm^2/(V s)],V_thb[V],I_On/I_Off\n'))
results = []

fig = figure(figsize=(8, 5))
Expand All @@ -141,8 +170,8 @@ for i in files:

try:
wb = xlrd.open_workbook(i, logfile=open(os.devnull, 'w'), on_demand = False)
# set logfile to `null` to depress warnings
# in fact, `on_demand` is not supported for .xls documents (with BIFF<5.0)
# set logfile to `null' to depress warnings
# in fact, `on_demand' is not supported for .xls documents (with BIFF<5.0)
sheet = wb.sheet_by_name('Data') # wb.sheet_by_index(0)
headers = sheet.row_values(0)
_ColGateV, _ColIDrain = ColGateV-1, ColIDrain-1 # start counting from 0
Expand All @@ -159,7 +188,7 @@ for i in files:
nscan = len(gatev)//2 # forward/backward
gatev = [gatev[:nscan], gatev[:nscan-1:-1]] # flipping the backward sequence is beneficial
fd.write(','.join(numpy.array(gatev, dtype=str).flatten()))
fd.write('\n\\sqrt I_d(smoothed)[A],')
fd.write(checkUTF8('\nI_d(smoothed)[A],'))
idlin = sheet.col_values(_ColIDrain, start_rowx=1, end_rowx=None) # sqrt(Ids)
idlin = [idlin[:nscan], idlin[:nscan-1:-1]]
idsg = [0, 0] # smoothed value of sqrt(Ids)
Expand All @@ -180,7 +209,7 @@ for i in files:
fl.write(vth+',')

fd.write(','.join(numpy.array(idsg, dtype=str).flatten()))
fd.write('\n\\mu[cm^2/(V s)],')
fd.write(checkUTF8('\nμ[cm^2/(V s)],'))
for k in [0, 1]:
fd.write('N/A,'*half+','.join(numpy.array(diff[k][0]**2*2*L/W/cp, dtype=str))+',N/A'*half+',')
for j in [0, 1]: # 0=slope, 1=intercept
Expand All @@ -202,7 +231,7 @@ for i in files:
pic += 1
results.append((fn[0], gatev, idlin, idsg, diff, maxs)) # record results
plot_sp()
subplots_adjust(left=.11, right=.92, top=.95, bottom=.12)
subplots_adjust(left=.11, right=.91, top=.95, bottom=.12)
savefig('Results/' + fn[0] + PICEXT)

print('\nResults (.csv and ' + PICEXT + ' files) were saved at: %s.' % os.path.abspath('Results'))
Expand Down
66 changes: 66 additions & 0 deletions FETAnal.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
DIELECTRIC = -1 # 0=SiOx, 1=Parylene, 2=BCB+SiOx, -1=Other
W, L = 20, 1 # Channel length/width in [um], or leave 0 as default
# To automatically get W, L from filenames, please name the files this way: ... 50um ... 20um ..., where the first number refers to W, the second L.

EPS = [3.9, 3, 2.65] # Permittivity of the dielectric
TD = [300, 706, 25] # Thickness of the dielectric in [nm]
DCP = 3.7e-9 # If DIELECTRIC=-1, then designate capacitance here in [F/cm^2]

ColGateV = 0 # Col # of "GateV", counting from 1 rather than 0, or leave 0 as default
ColIDrain = 0 # Col # of "IDrain", ibid.
# To automatically get ColGateV & ColIDrain from spreadsheets, please make sure that the column headers are named exactly as "GateV" & "IDRAIN"/"IDLIN", respectively.

PICEXT = '.png' # Desired extension name for saved picture files (eg. png, svg, eps ...)

# Please do not change these parameters for the Savitzky-Golay filter if you don't know what they are.
WINDOWLEN = 5 # The length of the filter window (i.e. the number of coefficients); must be a positive odd integer; if the signal is rough, use 7 or more points to smooth
POLYORDER = 1 # The order of the polynomial used to fit the samples


# This file is in nature python script, which will be executed before the main function runs
# So you can monkey patch the main program here. Below are examples
# This section is experimental and may be unstable. In the future, it may be moved into the main program. Please comment these lines out if they cause trouble
FIGURE_SIZE = (8, 5) # the default size of the figure window (in inches)
CONSOLE_WINDOW_AT_BOTTOM = False # For Windows only: Whether to place the console window below the figure window or on the right side of it

# Change default backend
from matplotlib import use, get_backend
if get_backend() == 'MacOSX': use('TkAgg') # Use preferentially TkAgg over MacOSX
backend = get_backend()
from matplotlib.pyplot import *
try: switch_backend('Qt5Agg') # Use preferentially Qt5Agg over TkAgg
except: switch_backend(backend)

# Change default figure window title, size and position
oriFig = figure # alias of the original func
def newFig(**k):
fig = oriFig(figsize=FIGURE_SIZE) # define default window size here
if get_backend() not in ('TkAgg', 'Qt5Agg', 'Qt4Agg', 'WXAgg'): return fig
win = fig.canvas.manager.window
title = os.path.abspath(path) + ' - FETAnal'
# move the window to the top-left corner of the screen and set figure title
# https://stackoverflow.com/a/37999370/11979352
if get_backend() == 'TkAgg':
if os.name == 'nt': hwnd = int(win.frame(), 16)
else: win.wm_geometry(win.wm_geometry().split('+')[0]+'+0+0'); win.winfo_toplevel().title(title)
elif get_backend() == 'Qt5Agg' or get_backend() == 'Qt4Agg':
if os.name == 'nt': hwnd = int(win.winId())
else: win.move(0, 0); win.setWindowTitle(title)
#elif get_backend() == 'WXAgg':
# if os.name == 'nt': hwnd = win.GetHandle()
# else: win.SetPosition(0, 0)
# for windows only: move the console window and set figure title
if os.name == 'nt':
import ctypes
ctypes.windll.user32.SetWindowPos(hwnd, 0, 0, 0, 0, 0, 5) # move the figure window
ctypes.windll.user32.SetWindowTextA(hwnd, title.encode('mbcs')) # set figure title as filename
pause(0.01)
class RECT(ctypes.Structure):
_fields_ = [("left", ctypes.c_long), ("top", ctypes.c_long), ("right", ctypes.c_long), ("bottom", ctypes.c_long)]
rect = RECT()
ctypes.windll.user32.GetWindowRect(hwnd,ctypes.byref(rect))
hwnd_c = ctypes.windll.kernel32.GetConsoleWindow()
if CONSOLE_WINDOW_AT_BOTTOM: ctypes.windll.user32.SetWindowPos(hwnd_c, 0, 0, rect.bottom, 0, 0, 5)
else: ctypes.windll.user32.SetWindowPos(hwnd_c, 0, rect.right, 0, 0, 0, 5)
return fig
figure = newFig
Loading

0 comments on commit 3364e4e

Please sign in to comment.