Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- # coding: utf-8
- # In[228]:
- # import external modules
- import h5py
- import time
- import math
- import cv2
- import os
- import os.path
- import shutil
- import numpy as np
- import matplotlib.pyplot as plt
- import matplotlib.cm as cm
- from IPython.core.display import display, HTML
- from shutil import copyfile
- from os import path
- from scipy.interpolate import griddata
- from mpl_toolkits.axes_grid1 import make_axes_locatable
- from mpl_toolkits.axes_grid1.colorbar import colorbar
- from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator, AutoLocator)
- import pylatex
- get_ipython().run_line_magic('matplotlib', 'inline')
- # In[2]:
- # change width of Jupyter notebook
- def displaywidth(width):
- try:
- display(HTML("<style>.container { width:" + str(width) + "% !important; }</style>"))
- except:
- print("Enter an integer percentage for width.")
- # In[3]:
- def load_h5(scan, datatype, show_time=False):
- '''This function loads only a few selected h5 files, but the definition should suffice for all the files I might need throughout the work on my bachelor's thesis.'''
- start = time.time()
- try:
- if datatype == "positions":
- h5_file = h5py.File("/asap3/petra3/gpfs/p06/2018/data/11005475/processed/0016_EMPA_MSH_003c/scan_00" + str(scan) + "/positions.h5", "r")
- else:
- h5_file = h5py.File("/asap3/petra3/gpfs/p06/2018/data/11005475/processed/0016_EMPA_MSH_003c/scan_00" + str(scan) + "/data/" + datatype + ".h5", "r")
- return h5_file
- except:
- print("You entered '" + str(scan) + "' for the argument 'scan'. The function only takes an integer as first argument. Its value must lie between 178 and 192, except for 184, because this scan was aborted.\nThe second argument must be a string for the datatype, e.g. 'position' or 'fluo_roi'.")
- end = time.time()
- if show_time:
- print("Loading file " + datatype + ".h5 from scan 00" + str(scan) + "took " + str(end-start) + "seconds.")
- # In[4]:
- displaywidth(100)
- # In[5]:
- def counts2amps(scan, nA=True):
- '''This function takes the integer scan number as an argument, looks for the counter data inside of the h5 file,
- converts all the counts into XBIC in [nA] and returns the values as an ndarray.'''
- # load counts and turn it into 2d array
- if scan in [179,187,188,189,190]: # XBIC measurements without the chopper, i.e. without the lock-in-amplifier
- loaded_counts1 = load_h5(scan, "counter")["/data/solar_cell_0-10V"]
- counts_as_array1 = np.array(loaded_counts1)
- loaded_counts2 = load_h5(scan, "counter")["/data/solar_cell_0-10V"]
- counts_as_array2 = np.array(loaded_counts2)
- counts_as_array = counts_as_array1-counts_as_array2 # subtract negative from positive signal
- else:
- loaded_counts = load_h5(scan, "counter")["/data/lock_in_R_0-10V"]
- counts_as_array = np.array(loaded_counts).astype(float) # this integer array must be converted to float, otherwise np.reciprocal will return only zeros
- counts_as_array = np.array(load_h5(scan, "counter")["/data/lock_in_0-10V"]).astype(float)
- # load photon counts
- loaded_photon_counts = load_h5(scan, "counter")["/data/qbpm_micro_sum"]
- photon_counts_as_array = np.array(loaded_photon_counts).astype(float) # this integer array must be converted to float, otherwise np.reciprocal will return only zeros
- # load exposure times and turn it into 2d array
- loaded_exposure_times = load_h5(scan, "counter")["/data/exposure_time"]
- exposure_times_as_array = np.array(loaded_exposure_times)
- # normalize counts and photons to one second
- c_rate = (counts_as_array/exposure_times_as_array)
- ph_rate = photon_counts_as_array/exposure_times_as_array
- # normalize counts to the average photon rate and one second
- f_DAQ = c_rate * np.mean(ph_rate)/ph_rate # multiply each LIA count by the ratio of the average photon count to the respective photon count (e.g. twice as much photons as the average should be normalized to half of the XBIC curent)
- # calculate the conversion factor
- if scan in [178,179,180,181,182,183,184,185,186,191,192]: # these scans have a sensitivity of 1 μA/V
- A_PA = 10**6 # "P_A" = 1/sensitivity: Preamplifier amplification factor in V/A, values taken from LogbuchStrahlzeitPetraIII31.10.-6.11.2018.pptx, slide 54f.
- if scan in [187,188,189,190]: # these scans have a sensitivity of 100 mA/V
- A_PA = 10
- A_LIA = 1 # "A_LIA" = 1/scaling = Lock-in amplifier amplification factor in V/V, values also taken from the pptx logbook
- V2f = 1000000
- Wff = math.sqrt(2) # the output signal (in this case a sine signal) of the LIA is the RMS amplitude, but we are interested in the peak-to-peak value (see jove paper, p.4)
- H_conv = 2*Wff/(V2f*A_LIA*A_PA)
- # finally multiply the conversion factor with the normalized count of each pixel
- if not nA:
- S_XBIC = f_DAQ * H_conv
- S_XBIC = f_DAQ * H_conv * 10**9
- # return S_XBIC_raw_nA
- return S_XBIC
- # In[ ]:
- plotXBIC(14)
- # In[ ]:
- for i in range(178,193):
- plotXBIC_singlecell(singleplots=[i])
- # In[ ]:
- print(cv2.imread(r"/asap3/petra3/gpfs/p06/2018/data/11005475/scratch_cc/Jan/savefig/plotXBIC_singlecell/01.png"))
- # In[ ]:
- # In[255]:
- img1 = cv2.imread(r"savefig/plotXBIC_singlecell/01.png")
- img2 = cv2.imread(r"savefig/plotXBIC_singlecell/02.png")
- #gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
- vis = cv2.vconcat([img1, img2])
- cv2.imshow("concatenated images",img1)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
- # In[ ]:
- img1 = cv2.imread(r"savefig/plotXBIC_singlecell/01.png")
- cv2.imshow("concatenated images",img1)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
- # In[ ]:
- im = cv2.imread('IMG_FILENAME',0)
- h,w = im.shape[:2]
- print(im.shape)
- plt.imshow(im,cmap='gray')
- plt.show()
- # In[ ]:
- folder_path = "savefig/plotXBIC_singlecell/"
- # Open one of the files,
- for data_file in os.listdir(folder_path):
- print(data_file)
- # In[ ]:
- # move the copies of the singlecell PNGs into the copy folder
- os.chdir(r"/asap3/petra3/gpfs/p06/2018/data/11005475/scratch_cc/Jan/")
- os.chdir(r"savefig/plotXBIC_singlecell/")
- newPath = "copied singlecell plots/"
- for file in os.listdir(os.getcwd()):
- if "Copy" in file:
- print(str(file), "was moved to", str(newPath))
- shutil.move(file,newPath)
- else:
- print(str(file), "does not contain \"Copy\"")
- os.chdir(r"/asap3/petra3/gpfs/p06/2018/data/11005475/scratch_cc/Jan/")
- # In[204]:
- # copy all PNGs from the copies folder into the upper folder and remove the Copy part of the name
- os.chdir(r"/asap3/petra3/gpfs/p06/2018/data/11005475/scratch_cc/Jan/savefig/plotXBIC_singlecell/copied singlecell plots/")
- for file in sorted(os.listdir(os.getcwd())):
- file_renamed = file.replace("-Copy1", "")
- os.rename(file,file_renamed)
- copyfile(file_renamed,r"../" + file_renamed)
- os.chdir(r"/asap3/petra3/gpfs/p06/2018/data/11005475/scratch_cc/Jan/")
- # In[253]:
- # rename the files in order
- os.chdir(r"/asap3/petra3/gpfs/p06/2018/data/11005475/scratch_cc/Jan/")
- os.chdir(r"savefig/plotXBIC_singlecell/")
- index = 1
- for file in sorted(os.listdir(os.getcwd())):
- if ".png" in file:
- os.rename(file,"{:02d}.png".format(index))
- index += 1
- os.chdir(r"/asap3/petra3/gpfs/p06/2018/data/11005475/scratch_cc/Jan/")
- # In[9]:
- def plotXBIC_singlecell(plot_range=None, singleplots=None, compareA=None, compareB=None, figsize=(30,30)):
- '''
- This function plots the XBIC, using data from the previously defined counts2amps() function. Look at the examples to see how to use it:
- plotXBIC(plot_range=14) will do the following:
- It will plot 14 datasets, starting with #178 and ending with #192 (and omitting 184 which is still counted).
- plotXBIC(singleplots=[178,185,192]) will do the following:
- It will plot #178, #185 and #192.
- plotXBIC(compareA=[178,178,185], compareB=[187,189,189]) will do the following:
- It will plot
- Scan 178 minus Scan 187
- Scan 178 minus Scan 189
- Scan 185 minus Scan 189.
- '''
- # the best looking fontsize is about half of the width of the figsize
- fontsize = figsize[0]//2
- # individualize titles for each scan if there is a bias voltage applied (information from LogbuchStrahlzeitPetraIII31.10.-6.11.2018.pptx, slide 54f., corresponding to handwritten logbook)
- voltage_dic = {
- 178: "",
- 179: "",
- 180: "",
- 181: "",
- 182: " (+ 100 mV)",
- 183: " (- 100 mV)",
- 185: " (- 200 mV)",
- 186: " (+ 200 mV)",
- 187: " (+ 500 mV)",
- 188: "(- 500 mV)",
- 189: " (- 1 V)",
- 190: " (+ 600 mv)",
- 191: "",
- 192: ""
- }
- # create a figure for all plots
- fig = plt.figure(figsize=figsize)
- loop_count = 1 # the subplot number should be independent of omitted scans (e.g. scan #184); otherwise you would see an empty space at that position
- if type(plot_range) is int:
- if plot_range > 6:
- plot_range += 1 # scan #184 is omitted, but still counted by the for-loop
- for scan in range(178, 178 + plot_range):
- if scan == 184:
- continue # scan 184 was aborted
- plotXBIC_loop_single(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count)
- loop_count += 1
- plt.show()
- if type(singleplots) is list:
- for scan in singleplots:
- if scan == 184:
- continue # scan 184 was aborted
- plotXBIC_loop_single(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count, savepng=True)
- loop_count += 1
- plt.show()
- if type(compareA) is list:
- compareB_counter=0
- for scan in compareA:
- plotXBIC_loop_single(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count,compare=True,compareB=compareB,compareB_counter=compareB_counter)
- loop_count += 1
- compareB_counter += 1
- plt.show()
- # In[147]:
- def plotXBIC_loop_single(scan, fig, fontsize, voltage_dic, loop_count, compareB=None, compareB_counter=None, compare=False, dpi=None, savepng=False):
- start = time.time() # measure time for each plot
- #fig.suptitle("Reduced LIA count normalized", fontsize=2*fontsize, x=0.7, y=0.92) # optional title for the figure (with this x and y it is centered and has a good distance)
- # load position and define y, z and f(y,z) as arrays that can be interpreted by the imshow() function
- positions = load_h5(scan, "positions")
- y_axis_h5 = positions["/data/encoder_fast/data"]
- z_axis_h5 = positions["/data/encoder_slow/data"]
- y = np.array(y_axis_h5)
- z = np.array(z_axis_h5)
- channels = {
- 1: "lock-in_-10-0V",
- 2: "lock_in_0-10V",
- 3: "lock_in_R_0-10V",
- 4: "solar_cell_-10-0V",
- 5: "solar_cell_0-10V"
- }
- for index in range(5):
- counts_as_array = np.array(load_h5(scan, "counter")["/data/" + channels[index+1]]).astype(float)
- # load photon counts
- loaded_photon_counts = load_h5(scan, "counter")["/data/qbpm_micro_sum"]
- photon_counts_as_array = np.array(loaded_photon_counts).astype(float) # this integer array must be converted to float, otherwise np.reciprocal will return only zeros
- # load exposure times and turn it into 2d array
- loaded_exposure_times = load_h5(scan, "counter")["/data/exposure_time"]
- exposure_times_as_array = np.array(loaded_exposure_times)
- # normalize counts and photons to one second
- c_rate = (counts_as_array/exposure_times_as_array)
- ph_rate = photon_counts_as_array/exposure_times_as_array
- # normalize counts to the average photon rate and one second
- f_DAQ = c_rate * np.mean(ph_rate)/ph_rate # multiply each LIA count by the ratio of the average photon count to the respective photon count (e.g. twice as much photons as the average should be normalized to half of the XBIC curent)
- # calculate the conversion factor
- if scan in [178,179,180,181,182,183,184,185,186,191,192]: # these scans have a sensitivity of 1 μA/V
- A_PA = 10**6 # "P_A" = 1/sensitivity: Preamplifier amplification factor in V/A, values taken from LogbuchStrahlzeitPetraIII31.10.-6.11.2018.pptx, slide 54f.
- if scan in [187,188,189,190]: # these scans have a sensitivity of 100 mA/V
- A_PA = 10
- A_LIA = 1 # "A_LIA" = 1/scaling = Lock-in amplifier amplification factor in V/V, values also taken from the pptx logbook
- V2f = 1000000
- Wff = math.sqrt(2) # the output signal (in this case a sine signal) of the LIA is the RMS amplitude, but we are interested in the peak-to-peak value (see jove paper, p.4)
- H_conv = 2*Wff/(V2f*A_LIA*A_PA)
- # finally multiply the conversion factor with the normalized count of each pixel
- S_XBIC = f_DAQ * H_conv * 10**9
- current = S_XBIC
- if compare:
- counts2amps_A = current
- counts2amps_B = counts2amps(compareB[compareB_counter])
- # append NaN: scan 180 has the shape (40199,) and thus cannot be broadcast together with the other scans which have shapes of (40200,)
- if scan == 180:
- counts2amps_A = np.append(current,np.nan)
- if compareB[compareB_counter] == 180:
- counts2amps_B = np.append(counts2amps(compareB[compareB_counter]),np.nan)
- current = counts2amps_A-counts2amps_B
- y_grid, z_grid, current_array = supergrid(y,z,current,1000)
- fig = plt.figure()
- ax = fig.add_subplot(111)
- # spacing to other subplots
- plt.subplots_adjust(right=1.3, hspace=0.5, wspace=0.5)
- # y and z labels
- ax.set_xlabel("Position Y [μm]", labelpad = 0, style = "italic", fontsize=fontsize)
- ax.set_ylabel("Position Z [μm]", labelpad = 0, style = "italic", fontsize=fontsize)
- # title
- bias_voltage = voltage_dic[scan]
- if compare:
- plt.title("Scan #" + str(scan) + " minus Scan #" + str(compareB[compareB_counter]), pad = 15, fontsize=round(9/8*fontsize))
- else:
- plt.title("Scan #" + str(scan) + bias_voltage, pad = 15, fontsize=round(9/8*fontsize))
- # individual ticks: it's an extrapolated plot from 201x201 to 1000x1000 pixels, but this corresponds to 10x10 micrometers on the solar cell
- ax.xaxis.set_ticklabels([0,5,10],fontsize=round(4/5*fontsize))
- ax.xaxis.set_ticks([0,500,999]) # if 1000 instead of 999 it won't display
- ax.yaxis.set_ticklabels([0,5,10],fontsize=round(4/5*fontsize))
- ax.yaxis.set_ticks([0,500,999])
- ax.xaxis.set_minor_locator(MultipleLocator(50)) # Minor ticks are set to multiples of 50
- ax.yaxis.set_minor_locator(MultipleLocator(50))
- # plot the data
- im = ax.imshow(current_array, interpolation='nearest', cmap=cm.afmhot, origin='lower')
- # add a colorbar as legend
- ax_divider = make_axes_locatable(ax) # Introduce a divider next to the axis already in place
- cax = ax_divider.append_axes("right", size = "15%", pad = "5%") # Append a new axis object with name "cax" to the divider. Width ("size") and distance to the 2D-Plot ("pad") can be given in % of the width of the x axis.
- legend = colorbar(im, cax = cax) # Introduce a legend (colorbar) where the new axis has been placed
- cax.set_ylabel(r"$\frac{XBIC}{pixel \cdot photons_{avg}}$" + " in [nA]", rotation = -90, labelpad = 50 , style = "italic", fontsize=5/4*fontsize) # Place this label next to the colorbar; labelpad denotes the distance of the colorbar
- cax.yaxis.set_major_locator(AutoLocator())
- cax.yaxis.set_minor_locator(AutoMinorLocator())
- plt.show()
- if savepng:
- from datetime import datetime
- now = datetime.now()
- dt_string = now.strftime("%d-%m-%Y_%H_%M_%S")
- if dpi is None:
- fig.savefig("savefig/plotXBIC_singlecell/plotXBIC_singlecell_" + dt_string + ".png", dpi=fig.dpi, bbox_inches="tight")
- else:
- fig.savefig("savefig/plotXBIC_singlecell/plotXBIC_singlecell_" + dt_string + ".png", dpi=dpi, bbox_inches="tight")
- end = time.time()
- if compare:
- print("Scan " + str(scan) + " minus Scan " + str(compareB[compareB_counter]) + " took " + str(round(end-start,2)) + " seconds to plot.")
- else:
- print("Scan " + str(scan) + " took " + str(round(end-start,2)) + " seconds to plot.")
- # In[11]:
- def supergrid(yvalues, zvalues, currents, gridres):
- """This function creates a rectangular grid where both axes have the given length. The given datapoints, which
- location is characterized by a tuple of y- and z-values, are interpolated such that every point in the grid gets
- assigned a value according to the nearest neighbor method.
- ARGUMENTS:
- yvalues (1D-array): Corresponding y-values for every measurement
- zvalues (1D-array): Corresponding x-values for every measurement
- currents (1D-array): All currents measured on the respective y- and z-coordinates
- gridres (float): Resolution of the grid insofar as it is the length of both axes of the grid in pixels
- RETURNS:
- (yvalues_new, zvalues_new, currents_supergrid) (Tuple of three 2D-Arrays): three grids with corresponding
- y-values, z-values and currents at every single point in the grid.
- """
- if np.size(yvalues) != np.size(zvalues):
- raise Exception("Arrays 'yvalues' and 'zvalues' must have same size.")
- else:
- if np.size(yvalues) - np.size(currents) == -1: # This paragraph is to catch an error that is raised when
- currents = currents[:np.size(currents) - 1] # dealing with the XRF scan XBIC data. It appears that
- if np.size(yvalues) - np.size(currents) == 1: # the y- and z-arrays or the currents are too long by one
- yvalues = yvalues[:np.size(yvalues) - 1] # element where no measurement was done. This element is
- zvalues = zvalues[:np.size(zvalues) - 1] # removed from the respective array to align points and data.
- if np.size(yvalues) - np.size(currents) == 0:
- pass
- else:
- raise Exception("Positions (y, z) and corresponding data points can't be aligned due to their different size.")
- yvalues_shift = yvalues - yvalues.min() # shift y-values to obtain the relative position
- zvalues_shift = zvalues - zvalues.min() # shift y-values to obtain the relative position
- # Create grid of y- and z-values with respect to the selected grid resolution (gridres)
- yvalues_new, zvalues_new = np.mgrid[0:yvalues_shift.max():gridres * 1j, 0:zvalues_shift.max():gridres * 1j]
- # Interpolate given currents such that they fit the grid of x- and y-values
- currents_supergrid = griddata((yvalues_shift, zvalues_shift), currents, (yvalues_new, zvalues_new), method = "nearest")
- return yvalues_new, zvalues_new, currents_supergrid.T
- # In[12]:
- def plotXBIC_loop(scan, fig, fontsize, voltage_dic, loop_count, compareB=None, compareB_counter=None, compare=False):
- start = time.time() # measure time for each plot
- #fig.suptitle("Reduced LIA count normalized", fontsize=2*fontsize, x=0.7, y=0.92) # optional title for the figure (with this x and y it is centered and has a good distance)
- # load position and define y, z and f(y,z) as arrays that can be interpreted by the imshow() function
- positions = load_h5(scan, "positions")
- y_axis_h5 = positions["/data/encoder_fast/data"]
- z_axis_h5 = positions["/data/encoder_slow/data"]
- y = np.array(y_axis_h5)
- z = np.array(z_axis_h5)
- current = counts2amps(scan)
- if compare:
- counts2amps_A = current
- counts2amps_B = counts2amps(compareB[compareB_counter])
- # append NaN: scan 180 has the shape (40199,) and thus cannot be broadcast together with the other scans which have shapes of (40200,)
- if scan == 180:
- counts2amps_A = np.append(current,np.nan)
- if compareB[compareB_counter] == 180:
- counts2amps_B = np.append(counts2amps(compareB[compareB_counter]),np.nan)
- current = counts2amps_A-counts2amps_B
- y_grid, z_grid, current_array = supergrid(y,z,current,1000)
- # axes for new subplot
- ax = fig.add_subplot(4, 4, loop_count)
- # spacing to other subplots
- plt.subplots_adjust(right=1.3, hspace=0.5, wspace=0.5)
- # y and z labels
- ax.set_xlabel("Position Y [μm]", labelpad = 0, style = "italic", fontsize=fontsize)
- ax.set_ylabel("Position Z [μm]", labelpad = 0, style = "italic", fontsize=fontsize)
- # title
- bias_voltage = voltage_dic[scan]
- if compare:
- plt.title("Scan #" + str(scan) + " minus Scan #" + str(compareB[compareB_counter]), pad = 15, fontsize=round(9/8*fontsize))
- else:
- plt.title("Scan #" + str(scan) + bias_voltage, pad = 15, fontsize=round(9/8*fontsize))
- # individual ticks: it's an extrapolated plot from 201x201 to 1000x1000 pixels, but this corresponds to 10x10 micrometers on the solar cell
- ax.xaxis.set_ticklabels([0,5,10],fontsize=round(4/5*fontsize))
- ax.xaxis.set_ticks([0,500,999]) # if 1000 instead of 999 it won't display
- ax.yaxis.set_ticklabels([0,5,10],fontsize=round(4/5*fontsize))
- ax.yaxis.set_ticks([0,500,999])
- ax.xaxis.set_minor_locator(MultipleLocator(50)) # Minor ticks are set to multiples of 50
- ax.yaxis.set_minor_locator(MultipleLocator(50))
- # plot the data
- im = ax.imshow(current_array, interpolation='nearest', cmap=cm.afmhot, origin='lower')
- # add a colorbar as legend
- ax_divider = make_axes_locatable(ax) # Introduce a divider next to the axis already in place
- cax = ax_divider.append_axes("right", size = "15%", pad = "5%") # Append a new axis object with name "cax" to the divider. Width ("size") and distance to the 2D-Plot ("pad") can be given in % of the width of the x axis.
- legend = colorbar(im, cax = cax) # Introduce a legend (colorbar) where the new axis has been placed
- cax.set_ylabel(r"$\frac{XBIC}{pixel \cdot photons_{avg}}$" + " in [nA]", rotation = -90, labelpad = 50 , style = "italic", fontsize=5/4*fontsize) # Place this label next to the colorbar; labelpad denotes the distance of the colorbar
- cax.yaxis.set_major_locator(AutoLocator())
- cax.yaxis.set_minor_locator(AutoMinorLocator())
- end = time.time()
- if compare:
- print("Scan " + str(scan) + " minus Scan " + str(compareB[compareB_counter]) + " took " + str(round(end-start,2)) + " seconds to plot.")
- else:
- print("Scan " + str(scan) + " took " + str(round(end-start,2)) + " seconds to plot.")
- # In[13]:
- def plotXBIC(plot_range=None, singleplots=None, compareA=None, compareB=None, figsize=(30,30), savepng=False, dpi=None):
- '''
- This function plots the XBIC, using data from the previously defined counts2amps() function. Look at the examples to see how to use it:
- plotXBIC(plot_range=14) will do the following:
- It will plot 14 datasets, starting with #178 and ending with #192 (and omitting 184 which is still counted).
- plotXBIC(singleplots=[178,185,192]) will do the following:
- It will plot #178, #185 and #192.
- plotXBIC(compareA=[178,178,185], compareB=[187,189,189]) will do the following:
- It will plot
- Scan 178 minus Scan 187
- Scan 178 minus Scan 189
- Scan 185 minus Scan 189.
- '''
- # the best looking fontsize is about half of the width of the figsize
- fontsize = figsize[0]//2
- # individualize titles for each scan if there is a bias voltage applied (information from LogbuchStrahlzeitPetraIII31.10.-6.11.2018.pptx, slide 54f., corresponding to handwritten logbook)
- voltage_dic = {
- 178: "",
- 179: "",
- 180: "",
- 181: "",
- 182: " (+ 100 mV)",
- 183: " (- 100 mV)",
- 185: " (- 200 mV)",
- 186: " (+ 200 mV)",
- 187: " (+ 500 mV)",
- 188: "(- 500 mV)",
- 189: " (- 1 V)",
- 190: " (+ 600 mv)",
- 191: "",
- 192: ""
- }
- # create a figure for all plots
- fig = plt.figure(figsize=figsize)
- loop_count = 1 # the subplot number should be independent of omitted scans (e.g. scan #184); otherwise you would see an empty space at that position
- if type(plot_range) is int:
- if plot_range > 6:
- plot_range += 1 # scan #184 is omitted, but still counted by the for-loop
- for scan in range(178, 178 + plot_range):
- if scan == 184:
- continue # scan 184 was aborted
- plotXBIC_loop(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count)
- loop_count += 1
- plt.show()
- if type(singleplots) is list:
- for scan in singleplots:
- if scan == 184:
- continue # scan 184 was aborted
- plotXBIC_loop(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count)
- loop_count += 1
- plt.show()
- if type(compareA) is list:
- compareB_counter=0
- for scan in compareA:
- plotXBIC_loop(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count,compare=True,compareB=compareB,compareB_counter=compareB_counter)
- loop_count += 1
- compareB_counter += 1
- plt.show()
- if savepng:
- from datetime import datetime
- now = datetime.now()
- dt_string = now.strftime("%d-%m-%Y_%H_%M_%S")
- if dpi is None:
- fig.savefig("savefig/plotXBIC_" + dt_string + ".png", dpi=fig.dpi, bbox_inches="tight")
- else:
- fig.savefig("savefig/plotXBIC_" + dt_string + ".png", dpi=dpi, bbox_inches="tight")
- # In[14]:
- def ImageRegistration(scan1,scan2,cell=None,printdetails=False):
- positions = load_h5(scan1, "positions")
- y_axis_h5 = positions["/data/encoder_fast/data"]
- z_axis_h5 = positions["/data/encoder_slow/data"]
- y = np.array(y_axis_h5)
- z = np.array(z_axis_h5)
- current1 = counts2amps(scan1)
- current2 = counts2amps(scan2)
- y_grid1, z_grid1, current1_array_original = supergrid(y,z,current1,1000)
- y_grid2, z_grid2, current2_array_original = supergrid(y,z,current2,1000)
- # convert current1_array to a grayscale image format (values between 0 and 255)
- current1_array_8bitgrayscale = current1_array_original/current1_array_original.max()
- current1_array_8bitgrayscale *= (1/1-current1_array_8bitgrayscale.min())
- current1_array_8bitgrayscale += 1 - current1_array_8bitgrayscale.max()
- current1_array_8bitgrayscale[current1_array_8bitgrayscale < 0] = 0
- current1_array_8bitgrayscale = np.array(current1_array_8bitgrayscale*255, dtype = np.uint8)
- current2_array_8bitgrayscale = current2_array_original/current2_array_original.max()
- current2_array_8bitgrayscale *= (1/1-current2_array_8bitgrayscale.min())
- current2_array_8bitgrayscale += 1 - current2_array_8bitgrayscale.max()
- current2_array_8bitgrayscale[current2_array_8bitgrayscale < 0] = 0
- current2_array_8bitgrayscale = np.array(current2_array_8bitgrayscale*255, dtype = np.uint8)
- shape = np.shape(current1_array_8bitgrayscale)
- warp_mode = cv2.MOTION_TRANSLATION # we only need translation in direction of y and z (no rotation etc.)
- warp_matrix = np.eye(2, 3, dtype=np.float32) # this is the matrix that the results of the ECC algorithm are stored in
- number_of_iterations = 5000 # Specify the number of iterations
- termination_eps = 1e-10 # Specify the threshold of the increment in the correlation coefficient between two iterations
- # Specify the overall criteria
- criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, number_of_iterations, termination_eps)
- (cc, warp_matrix) = cv2.findTransformECC(current1_array_8bitgrayscale, current2_array_8bitgrayscale, warp_matrix, warp_mode, criteria, None, 1)
- if printdetails == True:
- scan2_aligned = cv2.warpAffine(current2_array_8bitgrayscale, warp_matrix, (shape[1], shape[0]), flags = cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP).astype(np.float32)
- # show where the values of the registered image lie (XBIC as a function of the 40200 datapoints)
- scan2_aligned_ravel = scan2_aligned.ravel()
- x = np.arange(np.shape(scan2_aligned_ravel)[0])
- plt.figure(figsize=(50,5))
- plt.scatter(x, scan2_aligned_ravel)
- plt.show()
- fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize = (15, 15), constrained_layout = True)
- im1 = ax1.imshow(current1_array_8bitgrayscale, origin = "lower", cmap = cm.afmhot)
- ax1.set_title("Scan #" + str(scan1))
- ax1_divider = make_axes_locatable(ax1) # Introduce a divider next to the axis already in place
- cax1 = ax1_divider.append_axes("right", size = "15%", pad = "5%") # Append a new axis object with name "cax" to the divider. Width ("size") and distance to the 2D-Plot ("pad") can be given in % of the width of the x axis.
- legend = colorbar(im1, cax = cax1) # Introduce a legend (colorbar) where the new axis has been placed
- cax1.yaxis.set_major_locator(AutoLocator())
- cax1.yaxis.set_minor_locator(AutoMinorLocator())
- im2 = ax2.imshow(current2_array_8bitgrayscale, origin = "lower", cmap = cm.afmhot)
- ax2.set_title("Scan #" + str(scan2))
- ax2_divider = make_axes_locatable(ax2) # Introduce a divider next to the axis already in place
- cax2 = ax2_divider.append_axes("right", size = "15%", pad = "5%") # Append a new axis object with name "cax" to the divider. Width ("size") and distance to the 2D-Plot ("pad") can be given in % of the width of the x axis.
- legend = colorbar(im2, cax = cax2) # Introduce a legend (colorbar) where the new axis has been placed
- cax2.yaxis.set_major_locator(AutoLocator())
- cax2.yaxis.set_minor_locator(AutoMinorLocator())
- im3 = ax3.imshow(scan2_aligned, origin = "lower", cmap = "inferno")
- ax3.set_title("Scan #" + str(scan2) + " aligned")
- ax3.set_ylim(bottom = 0)
- ax3_divider = make_axes_locatable(ax3) # Introduce a divider next to the axis already in place
- cax3 = ax3_divider.append_axes("right", size = "15%", pad = "5%") # Append a new axis object with name "cax" to the divider. Width ("size") and distance to the 2D-Plot ("pad") can be given in % of the width of the x axis.
- legend = colorbar(im3, cax = cax3) # Introduce a legend (colorbar) where the new axis has been placed
- cax3.yaxis.set_major_locator(AutoLocator())
- cax3.yaxis.set_minor_locator(AutoMinorLocator())
- plt.tight_layout(w_pad=6)
- return warp_matrix
- ImageRegistration(181,182,printdetails=True)
- # In[15]:
- print(ImageRegistration(181,182))
- # In[16]:
- ImageRegistration(181,182)[0][2]
- # In[17]:
- def warpTransform(scan):
- warp_matrix = ImageRegistration(181,scan)
- scan_array = supergrid(np.array(load_h5(scan, "positions")["/data/encoder_fast/data"]), np.array(load_h5(scan, "positions")["/data/encoder_slow/data"]), counts2amps(scan), 1000)
- # Create a template array for the warped image
- zero_array = np.zeros((np.shape(scan_array)[0],np.shape(scan_array)[1]))
- transformY = ImageRegistration(181,scan)[0][2]
- transformZ = ImageRegistration(181,scan)[1][2]
- registered_image = transformY
- return registered_image
- # In[18]:
- def plotXBIC_loop2(scan, fig, fontsize, voltage_dic, loop_count, compareB=None, compareB_counter=None, compare=False):
- start = time.time() # measure time for each plot
- # fig.suptitle("Reduced LIA count normalized", fontsize=2*fontsize, x=0.7, y=0.92) # optional title for the figure (with this x and y it is centered and has a good distance)
- # load position and define y, z and f(y,z) as arrays that can be interpreted by the imshow() function
- positions = load_h5(scan, "positions")
- y_axis_h5 = positions["/data/encoder_fast/data"]
- z_axis_h5 = positions["/data/encoder_slow/data"]
- y = np.array(y_axis_h5)
- z = np.array(z_axis_h5)
- current = counts2amps(scan)
- if compare:
- counts2amps_A = current
- counts2amps_B = counts2amps(compareB[compareB_counter])
- # append NaN: scan 180 has the shape (40199,) and thus cannot be broadcast together with the other scans which have shapes of (40200,)
- if scan == 180:
- counts2amps_A = np.append(current,np.nan)
- if compareB[compareB_counter] == 180:
- counts2amps_B = np.append(counts2amps(compareB[compareB_counter]),np.nan)
- current = counts2amps_A-counts2amps_B
- y_grid, z_grid, current_array = supergrid(y,z,current,1000)
- # axes for new subplot
- ax = fig.add_subplot(4, 4, loop_count)
- # spacing to other subplots
- plt.subplots_adjust(right=1.3, hspace=0.5, wspace=0.5)
- # y and z labels
- ax.set_xlabel("Position Y [μm]", labelpad = 0, style = "italic", fontsize=fontsize)
- ax.set_ylabel("Position Z [μm]", labelpad = 0, style = "italic", fontsize=fontsize)
- # title
- bias_voltage = voltage_dic[scan]
- if compare:
- plt.title("Scan #" + str(scan) + " minus Scan #" + str(compareB[compareB_counter]), pad = 15, fontsize=round(9/8*fontsize))
- else:
- plt.title("Scan #" + str(scan) + bias_voltage, pad = 15, fontsize=round(9/8*fontsize))
- # individual ticks: it's an extrapolated plot from 201x201 to 1000x1000 pixels, but this corresponds to 10x10 micrometers on the solar cell
- ax.xaxis.set_ticklabels([0,5,10],fontsize=round(4/5*fontsize))
- ax.xaxis.set_ticks([0,500,999]) # if 1000 instead of 999 it won't display
- ax.yaxis.set_ticklabels([0,5,10],fontsize=round(4/5*fontsize))
- ax.yaxis.set_ticks([0,500,999])
- ax.xaxis.set_minor_locator(MultipleLocator(50)) # Minor ticks are set to multiples of 50
- ax.yaxis.set_minor_locator(MultipleLocator(50))
- shape = np.shape(current_array)
- if scan in [178,179]: # scan 178 and 179 were at another position than the rest of the scans
- warp_matrix = ImageRegistration(178,scan)
- else:
- warp_matrix = ImageRegistration(181,scan)
- if scan not in [178,181]: # scan 178 and 181 are reference scans for the warp matrices, so they don't need to be transformed
- current_array = cv2.warpAffine(current_array, warp_matrix, (shape[1], shape[0]), flags = cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP, borderValue = float("NaN")).astype(np.float32)
- current_array_ravel = current_array.ravel()
- x = np.arange(np.shape(current_array_ravel)[0])
- plt.figure(figsize=(50,5))
- plt.scatter(x, current_array_ravel)
- #plt.show()
- # plot the data
- im = ax.imshow(current_array, interpolation='nearest', cmap=cm.afmhot, origin='lower')
- # add a colorbar as legend
- ax_divider = make_axes_locatable(ax) # Introduce a divider next to the axis already in place
- cax = ax_divider.append_axes("right", size = "15%", pad = "5%") # Append a new axis object with name "cax" to the divider. Width ("size") and distance to the 2D-Plot ("pad") can be given in % of the width of the x axis.
- legend = colorbar(im, cax = cax) # Introduce a legend (colorbar) where the new axis has been placed
- cax.set_ylabel(r"$\frac{XBIC}{pixel \cdot photons_{avg}}$" + " in [nA]", rotation = -90, labelpad = 50 , style = "italic", fontsize=5/4*fontsize) # Place this label next to the colorbar; labelpad denotes the distance of the colorbar
- cax.yaxis.set_major_locator(AutoLocator())
- cax.yaxis.set_minor_locator(AutoMinorLocator())
- end = time.time()
- if compare:
- print("Scan " + str(scan) + " minus Scan " + str(compareB[compareB_counter]) + " took " + str(round(end-start,2)) + " seconds to plot.")
- else:
- print("Scan " + str(scan) + " took " + str(round(end-start,2)) + " seconds to plot.")
- # In[19]:
- def plotXBIC2(plot_range=None, singleplots=None, compareA=None, compareB=None, figsize=(30,30), savepng=False, dpi=None):
- '''
- This function plots the XBIC, using data from the previously defined counts2amps() function. Look at the examples to see how to use it:
- plotXBIC(plot_range=14) will do the following:
- It will plot 14 datasets, starting with #178 and ending with #192 (and omitting 184 which is still counted).
- plotXBIC(singleplots=[178,185,192]) will do the following:
- It will plot #178, #185 and #192.
- plotXBIC(compareA=[178,178,185], compareB=[187,189,189]) will do the following:
- It will plot
- Scan 178 minus Scan 187
- Scan 178 minus Scan 189
- Scan 185 minus Scan 189.
- '''
- # the best looking fontsize is about half of the width of the figsize
- fontsize = figsize[0]//2
- # individualize titles for each scan if there is a bias voltage applied (information from LogbuchStrahlzeitPetraIII31.10.-6.11.2018.pptx, slide 54f., corresponding to handwritten logbook)
- voltage_dic = {
- 178: "",
- 179: "",
- 180: "",
- 181: "",
- 182: " (+ 100 mV)",
- 183: " (- 100 mV)",
- 185: " (- 200 mV)",
- 186: " (+ 200 mV)",
- 187: " (+ 500 mV)",
- 188: "(- 500 mV)",
- 189: " (- 1 V)",
- 190: " (+ 600 mv)",
- 191: "",
- 192: ""
- }
- # create a figure for all plots
- fig = plt.figure(figsize=figsize)
- loop_count = 1 # the subplot number should be independent of omitted scans (e.g. scan #184); otherwise you would see an empty space at that position
- if type(plot_range) is int:
- if plot_range > 6:
- plot_range += 1 # scan #184 is omitted, but still counted by the for-loop
- for scan in range(178, 178 + plot_range):
- if scan == 184:
- continue # scan 184 was aborted
- plotXBIC_loop2(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count)
- loop_count += 1
- plt.show()
- if type(singleplots) is list:
- for scan in singleplots:
- if scan == 184:
- continue # scan 184 was aborted
- plotXBIC_loop2(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count)
- loop_count += 1
- plt.show()
- if type(compareA) is list:
- compareB_counter=0
- for scan in compareA:
- plotXBIC_loop2(scan=scan,fig=fig,fontsize=fontsize,voltage_dic=voltage_dic,loop_count=loop_count,compare=True,compareB=compareB,compareB_counter=compareB_counter)
- loop_count += 1
- compareB_counter += 1
- plt.show()
- if savepng:
- from datetime import datetime
- now = datetime.now()
- dt_string = now.strftime("%d-%m-%Y_%H_%M_%S")
- if dpi is None:
- fig.savefig("savefig/plotXBIC_" + dt_string + ".png", dpi=fig.dpi, bbox_inches="tight")
- else:
- fig.savefig("savefig/plotXBIC_" + dt_string + ".png", dpi=dpi, bbox_inches="tight")
- # In[20]:
- plotXBIC2(singleplots=[181,182,183])
- # In[21]:
- plotXBIC(14)
- # In[22]:
- def plotIV(thinning=10,savepng=False):
- start = time.time()
- # voltages
- voltages = [-1000,-500,-200,-100,0,100,200,500,600]
- # scans (ordered by voltages)
- scans_ordered = [189,188,185,183,181,182,186,187,190]
- current_mean = []
- pixelplotting_array = np.empty([5,1000,1000])
- pixelplotting_array_x = 0
- for scan in scans_ordered[2:-2]:
- positions = load_h5(scan, "positions")
- y_axis_h5 = positions["/data/encoder_fast/data"]
- z_axis_h5 = positions["/data/encoder_slow/data"]
- y_axis = np.array(y_axis_h5)
- z_axis = np.array(z_axis_h5)
- current = counts2amps(scan)
- y_grid, z_grid, current_array = supergrid(y_axis,z_axis,current,1000)
- current_mean.append(np.mean(current))
- for y in range(1000):
- for z in range(1000):
- pixelplotting_array[pixelplotting_array_x,z,y] = current_array[y,z]
- pixelplotting_array_x += 1
- fig = plt.figure(figsize=(40,20))
- ax1 = fig.add_subplot(121)
- for y in np.linspace(0,999,1000/thinning,dtype=int):
- for z in np.linspace(0,999,1000/thinning,dtype=int):
- ax1.plot(voltages[2:-2], pixelplotting_array[:,y,z],linewidth = 0.2,color="blue")
- ax2 = fig.add_subplot(122)
- ax2.plot(voltages[2:-2], current_mean)
- end = time.time()
- print(end-start)
- plt.show()
- plotIV(thinning=50)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement