├── .gitattributes ├── .gitignore ├── Ophus_APS_tutorial_programmatic_figures_v02_export.pdf ├── Ophus_STROBE_programmatic_figures_v01_export.pdf ├── README.md ├── images └── STEM4D_movie04b_export.gif ├── matlab ├── part_01_basics │ ├── color_flowlines.jpg │ ├── color_flowlines.pdf │ ├── color_flowlines.png │ ├── deformed_lattice.jpg │ ├── deformed_lattice.pdf │ ├── deformed_lattice.png │ ├── hilbert.png │ ├── hilbert_scan.jpg │ └── hilbert_scan.pdf ├── part_02_images │ ├── example_02_various_images.mat │ ├── inferno.m │ ├── plotImage.m │ ├── plotImageFullRange.m │ ├── plotImageOrdered.m │ ├── plotImageStdDev.m │ └── violetFire.m ├── part_03_04_atoms │ ├── animAtoms01a.m │ ├── animAtoms01b.m │ ├── animAtoms02a.m │ ├── animAtoms02b.m │ ├── atomData02.mat │ ├── plotAtoms00.m │ ├── plotAtoms01.m │ └── progressbar.m └── part_05_06_physics │ ├── DPC01.m │ ├── DPC02.m │ ├── animFEM01.m │ ├── animFEM02.m │ ├── animFEM03.m │ ├── animOrient01.m │ ├── animOrient02.m │ ├── animStrain01.m │ ├── animStrain02.m │ ├── colorComplex.m │ ├── colorComplexLAB.m │ ├── makeFourierCoords.m │ ├── makeSpiralEW.m │ ├── schematic01.m │ └── tukeywinMake.m └── python ├── atoms01.ipynb ├── atoms_plot_output_01.png ├── diffraction_movie_02.mp4 ├── images01_scaling.ipynb ├── physics01.ipynb └── schematic_03.png /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /Ophus_APS_tutorial_programmatic_figures_v02_export.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/Ophus_APS_tutorial_programmatic_figures_v02_export.pdf -------------------------------------------------------------------------------- /Ophus_STROBE_programmatic_figures_v01_export.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/Ophus_STROBE_programmatic_figures_v01_export.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Programmatic Figures and Movies Tutorial 2 | 3 | ### Colin Ophus - updated 2021 March 4 | 5 | This repo contains the presentation files, codes, and images for programmatic visualization tutorials - this includes examples for image plotting, 3D scatter plots, and physics demonstration movies. There are implementations in both Matlab and Python (matplotlib specifically), and associated powerpoint slides shown below. 6 | 7 | [![4DSTEM movie](images/STEM4D_movie04b_export.gif)](https://www.youtube.com/watch?v=2QUFgO5x1OY) 8 | 9 | 10 | ### 2024 11 | 12 | [PDF export of the slides ](https://github.com/cophus/Programmatic_Figures_Tutorial/blob/main/Ophus_STROBE_programmatic_figures_v01_export.pdf) 13 | 14 | [Animated powerpoint slides on Google Drive](https://docs.google.com/presentation/d/1Yk2e2dS7XuHPw7Ga1GtVrdp_a4IC1-t9/edit?usp=drive_link&ouid=117018913006577578883&rtpof=true&sd=true) 15 | 16 | 17 | ### 2023 18 | 19 | [PDF export of the slides ](https://github.com/cophus/Programmatic_Figures_Tutorial/blob/main/Ophus_APS_tutorial_programmatic_figures_v02_export.pdf) 20 | 21 | [Animated powerpoint slides on Google Drive](https://drive.google.com/file/d/1PrV0_dmF_txkJctAWFWi6JNVDcQTA2Ye) -------------------------------------------------------------------------------- /images/STEM4D_movie04b_export.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/images/STEM4D_movie04b_export.gif -------------------------------------------------------------------------------- /matlab/part_01_basics/color_flowlines.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/color_flowlines.jpg -------------------------------------------------------------------------------- /matlab/part_01_basics/color_flowlines.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/color_flowlines.pdf -------------------------------------------------------------------------------- /matlab/part_01_basics/color_flowlines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/color_flowlines.png -------------------------------------------------------------------------------- /matlab/part_01_basics/deformed_lattice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/deformed_lattice.jpg -------------------------------------------------------------------------------- /matlab/part_01_basics/deformed_lattice.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/deformed_lattice.pdf -------------------------------------------------------------------------------- /matlab/part_01_basics/deformed_lattice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/deformed_lattice.png -------------------------------------------------------------------------------- /matlab/part_01_basics/hilbert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/hilbert.png -------------------------------------------------------------------------------- /matlab/part_01_basics/hilbert_scan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/hilbert_scan.jpg -------------------------------------------------------------------------------- /matlab/part_01_basics/hilbert_scan.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_01_basics/hilbert_scan.pdf -------------------------------------------------------------------------------- /matlab/part_02_images/example_02_various_images.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_02_images/example_02_various_images.mat -------------------------------------------------------------------------------- /matlab/part_02_images/inferno.m: -------------------------------------------------------------------------------- 1 | function [cmap] = inferno(numberColors) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % Quick implementation / tweak of a perceptually-uniform colormap "inferno" 5 | % by Stefan van der Walt and Nathaniel Smith. If you run this script 6 | % without an output, it will plot the colormap in a figure window. 7 | 8 | % Input: 9 | % numberColors - how many colors to include (# of RGB values). Default: 256 10 | 11 | % Output: 12 | % [numberColors x 3] sized array containing the colormap, columns = [R G B] 13 | 14 | % default number of colors 15 | if nargin < 1 16 | numberColors = 256; 17 | end 18 | 19 | % Init 20 | cmap = ones(numberColors,3); 21 | cmap(:,3) = linspace(0,1,numberColors); 22 | 23 | % Determine specific color indices 24 | indsEdge = round(numberColors*[0 0.3 0.5 0.75 0.90 1]) + [1 0 0 0 0 0]; 25 | 26 | % black -> purple 27 | inds = indsEdge(1):(indsEdge(2)-1); 28 | c = linspace(0,1,indsEdge(2)-indsEdge(1)+1)'; 29 | c(end) = []; 30 | cmap(inds,1) = 4/6 + c/6; 31 | cmap(inds,2) = 3*c.^2 - 2*c.^3; 32 | 33 | % purple -> red 34 | inds = indsEdge(2):(indsEdge(3)-1); 35 | c = linspace(0,1,indsEdge(3)-indsEdge(2)+1)'; 36 | c(end) = []; 37 | cmap(inds,1) = 5/6 + c/6; 38 | 39 | % red -> orange 40 | inds = indsEdge(3):(indsEdge(4)-1); 41 | c = linspace(0,1,indsEdge(4)-indsEdge(3)+1)'; 42 | c(end) = []; 43 | cmap(inds,1) = c/12; 44 | 45 | % orange -> yellow 46 | inds = indsEdge(4):(indsEdge(5)-1); 47 | c = linspace(0,1,indsEdge(5)-indsEdge(4)+1)'; 48 | c(end) = []; 49 | cmap(inds,1) = 1/12 + c/12; 50 | 51 | % yellow -> white 52 | inds = indsEdge(5):indsEdge(6); 53 | c = linspace(0,1,indsEdge(6)-indsEdge(5)+1)'; 54 | cmap(inds,1) = 1/6; 55 | cmap(inds,2) = 1 - 3*c.^2 + 2*c.^3; 56 | 57 | 58 | % convert from HSV to RGB 59 | cmap(:) = hsv2rgb(cmap); 60 | 61 | % plotting 62 | if nargout < 1 63 | figure(101) 64 | clf 65 | imagesc(reshape(cmap,[numberColors 1 3])) 66 | axis off 67 | set(gca,'xtick',[]) 68 | 69 | end -------------------------------------------------------------------------------- /matlab/part_02_images/plotImage.m: -------------------------------------------------------------------------------- 1 | function [imageRGB] = plotImage(imageInput,varargin) 2 | 3 | 4 | % Colin Ophus - clophus@lbl.gov - 2020 February 5 | % APS tutorial example 01 - plotting images with automatic color scaling 6 | 7 | % In this example, we will plot scalar (single-value per pixel) images, 8 | % with automatically determined color ranges, using a defined colormap. 9 | 10 | % Input: 11 | % imageInput - the raw image data, 1 value per pixel 12 | % flagSimpleScaling = false; % Set to true to use mean / standard deviation scaling 13 | flagDrawColorbar = false; % set to true to draw a colorbar 14 | 15 | % Optional inputs 16 | % 2 element vector [min_value max_value] specifies the relative or abs color range 17 | % [N x 3] array will be assigned as the colormap 18 | % 'absolute' character vector to change the color scaling to absolute 19 | % 'ordered' character vector to change the color scaling to order instead 20 | % 'asymmetric' character vector to change the color scaling to asymmetric 21 | % 'log' character vector to change the color scaling to absolute 22 | % 'zero' character vector to fix black level at zero 23 | % any other character vector will be assigned as file name for writing an output png file 24 | 25 | % Init 26 | intRange = []; 27 | cmap = []; 28 | flagAbsoluteScaling = false; 29 | flagOrderedScaling = false; 30 | flagAsymmetricScaling = false; 31 | flagLogScaling = false; 32 | flagZeroScaling = false; 33 | flagWriteOutput = false; 34 | 35 | % Parse inputs 36 | numInputs = nargin - 1; 37 | for a0 = 1:numInputs 38 | if ischar(varargin{a0}) == true 39 | 40 | 41 | % Check for keywords as inputs 42 | if strcmp(varargin{a0},'absolute') 43 | flagAbsoluteScaling = true; 44 | elseif strcmp(varargin{a0},'ordered') 45 | flagOrderedScaling = true; 46 | elseif strcmp(varargin{a0},'asymmetric') 47 | flagAsymmetricScaling = true; 48 | elseif strcmp(varargin{a0},'log') 49 | flagLogScaling = true; 50 | elseif strcmp(varargin{a0},'zero') 51 | flagZeroScaling = true; 52 | else 53 | % Otherwise assume string represents output file name 54 | fileNameBase = varargin{a0}; 55 | flagWriteOutput = true; 56 | end 57 | 58 | else 59 | % If input is not a string, check for range or colormap 60 | if numel(varargin{a0}) == 2 61 | intRange = varargin{a0}; 62 | 63 | elseif size(varargin{a0},1) > 1 && size(varargin{a0},2) == 3 64 | cmap = varargin{a0}; 65 | 66 | else 67 | disp(['Input parameter #' num2str(a0+1) ' was ignored.']); 68 | end 69 | end 70 | end 71 | 72 | % Default parameters 73 | if isempty(intRange) && ~flagAbsoluteScaling 74 | intRange = [-1 1]*2; 75 | end 76 | if isempty(cmap) 77 | % cmap = inferno(256); 78 | cmap = violetFire(256); 79 | end 80 | 81 | % Scale figure 82 | imageScale = double(real(imageInput)); 83 | if flagAbsoluteScaling == true 84 | if isempty(intRange) 85 | intRange = [min(imageScale(:)) max(imageScale(:))]; 86 | end 87 | imageScale(:) = (imageScale - intRange(1)) / (intRange(2) - intRange(1)); 88 | 89 | elseif flagOrderedScaling == true 90 | numberColors = size(cmap,1); 91 | 92 | % Ordering of pixel intensities 93 | [sigOrder,indsOrder] = sort(imageInput(:)); 94 | 95 | % indices 96 | imageSize = size(imageInput); 97 | indsRange = round(linspace(0,1,numberColors+1)' * prod(imageSize)); 98 | if nargout > 1 || flagDrawColorbar == true 99 | % Output the intensity ranges corresponding to each color 100 | intensityRange = [ ... 101 | sigOrder(max(indsRange(1:end-1),1)) ... 102 | sigOrder(indsRange(2:end))]; 103 | end 104 | 105 | % Generate image 106 | imageRGB = zeros(imageSize(1),imageSize(2),3); 107 | for a0 = 1:(length(indsRange)-1) 108 | inds = indsOrder((indsRange(a0)+1):(indsRange(a0+1))); 109 | % red 110 | imageRGB(inds) = cmap(a0,1); 111 | % green 112 | imageRGB(inds+(prod(imageSize))) = cmap(a0,2); 113 | % blue 114 | imageRGB(inds+(2*prod(imageSize))) = cmap(a0,3); 115 | end 116 | 117 | elseif flagAsymmetricScaling == true 118 | imageMedian = median(imageScale(:)); 119 | sub = imageScale < imageMedian; 120 | imageRMSneg = sqrt(mean((imageScale(sub) - imageMedian).^2)); 121 | sub = imageScale > imageMedian; 122 | imageRMSpos = sqrt(mean((imageScale(sub) - imageMedian).^2)); 123 | 124 | intRangeNew = imageMedian + ... 125 | [intRange(1)*imageRMSneg intRange(2)*imageRMSpos]; 126 | imageScale(:) = (imageScale - intRangeNew(1)) ... 127 | / (intRangeNew(2) - intRangeNew(1)); 128 | 129 | elseif flagLogScaling == true 130 | % logarithmic scaling 131 | sub = imageScale > 0; 132 | sig = log(imageScale(sub)); 133 | 134 | sigMean = mean(sig); 135 | sigRMS = sqrt(mean((sig - sigMean).^2)); 136 | intRangeNew = exp(sigMean + intRange*sigRMS); 137 | 138 | imageScale(:) = (imageScale - intRangeNew(1)) ... 139 | / (intRangeNew(2) - intRangeNew(1)); 140 | 141 | elseif flagZeroScaling == true 142 | % Fix zero level, compute RMS intensity relative to zero 143 | imageScale = imageScale / sqrt(mean(imageScale(:).^2)); 144 | imageScale(:) = imageScale / intRange(2); 145 | 146 | else 147 | % Simple scaling by mean +/- standard deviation 148 | imageScale = imageScale - mean(imageScale(:)); 149 | imageScale = imageScale / sqrt(mean(imageScale(:).^2)); 150 | imageScale(:) = (imageScale - intRange(1)) / (intRange(2) - intRange(1)); 151 | 152 | end 153 | 154 | if flagOrderedScaling == false 155 | % Clamp values to 0 and 1 156 | imageScale(:) = min(max(imageScale,0),1); 157 | 158 | % Generate RGB image 159 | imageRGB = ind2rgb(round(imageScale*(size(cmap,1)-1))+1,cmap); 160 | end 161 | 162 | % If needed, write figure into file. 163 | % Descriptive file name 164 | if flagWriteOutput == true 165 | if flagAbsoluteScaling == true 166 | fileName = [fileNameBase '_absolute_range_' ... 167 | sprintf('%.01d',intRange(1)) '_' ... 168 | sprintf('%.01d',intRange(2)) ... 169 | '.png']; 170 | elseif flagAsymmetricScaling == true 171 | fileName = [fileNameBase '_asymmetric_range_' ... 172 | sprintf('%.01d',intRange(1)) '_' ... 173 | sprintf('%.01d',intRange(2)) ... 174 | '.png']; 175 | elseif flagOrderedScaling == true 176 | fileName = [fileNameBase '_ordered.png']; 177 | elseif flagLogScaling == true 178 | fileName = [fileNameBase '_log_range_' ... 179 | sprintf('%.01d',intRange(1)) '_' ... 180 | sprintf('%.01d',intRange(2)) ... 181 | '.png']; 182 | elseif flagZeroScaling == true 183 | fileName = [fileNameBase '_zero_range_' ... 184 | sprintf('%.01d',intRange(1)) '_' ... 185 | sprintf('%.01d',intRange(2)) ... 186 | '.png']; 187 | else 188 | fileName = [fileNameBase '_range_' ... 189 | sprintf('%.01d',intRange(1)) '_' ... 190 | sprintf('%.01d',intRange(2)) ... 191 | '.png']; 192 | end 193 | 194 | imwrite(imageRGB,fileName,'png') 195 | end 196 | 197 | 198 | % Plot the figure will full axes 199 | figure(1) 200 | clf 201 | imagesc(imageRGB) 202 | axis equal off 203 | set(gca,'position',[0 0 1 1]) 204 | drawnow; 205 | 206 | 207 | if flagDrawColorbar == true && flagOrderedScaling == true 208 | figure(2) 209 | clf 210 | set(gcf,'color','w') 211 | 212 | % Vertical orientation 213 | imagesc(reshape(cmap,[numberColors 1 3])); 214 | set(gca,'position',[0.1 0.05 0.1 0.90]) 215 | set(gca,'xtick',[]) 216 | set(gca,'ydir','normal') 217 | set(gca,'yaxislocation','right') 218 | % labels 219 | numTicks = 16 + 1; 220 | indsPlot = round(linspace(1,numberColors,numTicks)); 221 | indValues = (intensityRange(indsPlot,1) + intensityRange(indsPlot,1))/2; 222 | indValues(:) = round(indValues); 223 | set(gca,'ytick',indsPlot); 224 | set(gca,'yticklabels',indValues); 225 | end 226 | 227 | 228 | end -------------------------------------------------------------------------------- /matlab/part_02_images/plotImageFullRange.m: -------------------------------------------------------------------------------- 1 | function [] = plotImageFullRange(imageInput,fileNameBase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Save images from min to max range, inferno colormap 5 | % Note that if fileNameBase is not specified, this 6 | % script will plot the image instead, and no file 7 | % will be written. 8 | 9 | % Inputs: 10 | % imageInput - scalar image array 11 | % fileNameBase - char string containing file name 12 | 13 | 14 | % Convert to double floating point 15 | imageInput = double(imageInput); 16 | 17 | % scale image from 0 to 1 18 | imageInput(:) = imageInput - min(imageInput(:)); 19 | imageInput(:) = imageInput / max (imageInput(:)); 20 | 21 | % Save or plot image 22 | if nargin < 2 23 | figure(1) 24 | clf 25 | imagesc(imageInput) 26 | axis equal off 27 | colormap(inferno) 28 | set(gca,'position',[0 0 1 1]) 29 | caxis([0 1]) 30 | else 31 | fileName = [fileNameBase '.png']; 32 | imwrite(round(imageInput*255)+1,inferno,fileName); 33 | end 34 | 35 | 36 | 37 | end 38 | -------------------------------------------------------------------------------- /matlab/part_02_images/plotImageOrdered.m: -------------------------------------------------------------------------------- 1 | function [imageRGB,intensityRange] = plotImageOrdered(imageInput,fileNameBase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Save images with the intensity scaled by the 5 | % ordered distribution of intensties 6 | 7 | % Inputs: 8 | % imageInput - scalar image array 9 | % fileNameBase - char string containing file name 10 | flagDrawColorbar = true; % draw and label a colorbar for the output image 11 | 12 | % Output: 13 | % imageRGB - output image with colormap applied 14 | 15 | % Colormap 16 | cmap = inferno; 17 | % cmap = violetFire; 18 | numberColors = size(cmap,1); 19 | 20 | % Convert to double floating point 21 | imageInput = double(imageInput); 22 | 23 | % Ordering of pixel intensities 24 | [sigOrder,indsOrder] = sort(imageInput(:)); 25 | 26 | % indices 27 | imageSize = size(imageInput); 28 | indsRange = round(linspace(0,1,numberColors+1)' * prod(imageSize)); 29 | if nargout > 1 || flagDrawColorbar == true 30 | % Output the intensity ranges corresponding to each color 31 | intensityRange = [ ... 32 | sigOrder(max(indsRange(1:end-1),1)) ... 33 | sigOrder(indsRange(2:end))]; 34 | end 35 | 36 | % init 37 | imageRGB = zeros(imageSize(1),imageSize(2),3); 38 | 39 | % Generate image 40 | for a0 = 1:(length(indsRange)-1) 41 | inds = indsOrder((indsRange(a0)+1):(indsRange(a0+1))); 42 | 43 | % red 44 | imageRGB(inds) = cmap(a0,1); 45 | 46 | % green 47 | imageRGB(inds+(prod(imageSize))) = cmap(a0,2); 48 | 49 | % blue 50 | imageRGB(inds+(2*prod(imageSize))) = cmap(a0,3); 51 | end 52 | 53 | 54 | % Save or plot image 55 | if nargin < 2 56 | figure(1) 57 | clf 58 | imagesc(imageRGB) 59 | axis equal off 60 | set(gca,'position',[0 0 1 1]) 61 | else 62 | fileName = [fileNameBase '.png']; 63 | imwrite(imageRGB,fileName); 64 | end 65 | 66 | 67 | if flagDrawColorbar == true 68 | figure(2) 69 | clf 70 | set(gcf,'color','w') 71 | 72 | % Vertical orientation 73 | imagesc(reshape(cmap,[numberColors 1 3])); 74 | set(gca,'position',[0.1 0.05 0.1 0.90]) 75 | set(gca,'xtick',[]) 76 | set(gca,'ydir','normal') 77 | set(gca,'yaxislocation','right') 78 | % labels 79 | numTicks = 16 + 1; 80 | indsPlot = round(linspace(1,numberColors,numTicks)); 81 | indValues = (intensityRange(indsPlot,1) + intensityRange(indsPlot,1))/2; 82 | indValues(:) = round(indValues); 83 | set(gca,'ytick',indsPlot); 84 | set(gca,'yticklabels',indValues); 85 | 86 | % % horizontal orientation 87 | % imagesc(reshape(cmap,[1 numberColors 3])); 88 | % set(gca,'position',[0.05 0.45 0.90 0.10]) 89 | % set(gca,'ytick',[]) 90 | % % labels 91 | % numTicks = 8 + 1; 92 | % indsPlot = round(linspace(1,numberColors,numTicks)); 93 | % set(gca,'xtick',indsPlot); 94 | % set(gca,'xticklabels', .... 95 | % (intensityRange(indsPlot,1) + intensityRange(indsPlot,1))/2); 96 | 97 | 98 | end 99 | 100 | end -------------------------------------------------------------------------------- /matlab/part_02_images/plotImageStdDev.m: -------------------------------------------------------------------------------- 1 | function [] = plotImageStdDev(imageInput,intRange,fileNameBase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Save images with the intensity scaled by the 5 | % standard deviation of the intensity distribution. 6 | % If fileNameBase input is not provided, plot image. 7 | 8 | % Inputs: 9 | % imageInput - scalar image array 10 | % fileNameBase - char string containing file name 11 | 12 | % Convert to double floating point 13 | imageInput = double(imageInput); 14 | 15 | % default settings for intensity range 16 | if nargin < 2 || isempty(intRange) 17 | intRange = [-2 2]; 18 | end 19 | 20 | % scale image into units of standard deviation 21 | imageInput(:) = imageInput - mean(imageInput(:)); 22 | imageInput(:) = imageInput / sqrt(mean(imageInput(:).^2)); 23 | 24 | % scale image output using desired intensity range 25 | imageInput(:) = (imageInput - intRange(1)) / (intRange(2) - intRange(1)); 26 | 27 | % clamp output from 0 to 1 28 | imageInput(:) = min(max(imageInput,0),1); 29 | 30 | % Save or plot image 31 | if nargin < 3 32 | figure(1) 33 | clf 34 | imagesc(imageInput) 35 | axis equal off 36 | colormap(inferno) 37 | set(gca,'position',[0 0 1 1]) 38 | caxis([0 1]) 39 | else 40 | fileName = [fileNameBase '.png']; 41 | imwrite(round(imageInput*255)+1,inferno,fileName); 42 | end 43 | 44 | 45 | 46 | end 47 | -------------------------------------------------------------------------------- /matlab/part_02_images/violetFire.m: -------------------------------------------------------------------------------- 1 | function [cmap] = violetFire(Nc) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % violet fire color map 5 | 6 | if nargin == 0 7 | Nc = 256; 8 | end 9 | 10 | % Make custom colormap 11 | % [R G B fraction] 12 | c = [0 0 0 0; 13 | .2 0 .4 .25; 14 | 1 0 0 .5; 15 | 1 .6 0 .65; 16 | 1 1 0 .75; 17 | 1 1 1 1]; 18 | cmap = zeros(Nc,3); 19 | for a0 = 1:(size(c,1)-1) 20 | f1 = round(c(a0,4)*Nc+1); 21 | f2 = round(c(a0+1,4)*Nc); 22 | inds = f1:f2; 23 | cnew = [linspace(c(a0,1),c(a0+1,1),length(inds))' ... 24 | linspace(c(a0,2),c(a0+1,2),length(inds))' ... 25 | linspace(c(a0,3),c(a0+1,3),length(inds))']; 26 | cmap(inds,:) = cnew; 27 | end 28 | % smooth colormap in hsv space? 29 | % cmap = rgb2hsv(cmap); 30 | % cmap(:,1) = smooth(cmap(:,1)-.5,11,'moving'); 31 | % cmap = hsv2rgb(cmap); 32 | cmap(:,1) = smooth(cmap(:,1),11,'moving'); 33 | cmap(:,2) = smooth(cmap(:,2),11,'moving'); 34 | cmap(:,3) = smooth(cmap(:,3),11,'moving'); 35 | cmap(cmap<0) = 0; 36 | cmap(cmap>1) = 1; 37 | 38 | end -------------------------------------------------------------------------------- /matlab/part_03_04_atoms/animAtoms01a.m: -------------------------------------------------------------------------------- 1 | function [] = animAtoms01a(atomData,atomLattice,cameraPosition) 2 | 3 | % Colin Ophus - clophus@lb2 l.gov - 2020 February 4 | % APS tutorial example 0- plotting atoms from the FePt sample 5 | 6 | % In this example, we will plot atoms in 3D, with separation between atomic 7 | % planes, coloring, shading (depth cueing) 8 | % Version 01 - 3D scatter plot with some plotting tricks 9 | 10 | % Inputs: 11 | % atomData - [N x 4] array, where first three columns are (x,y,z) and last 12 | % column is the atom ID (1, 2, ...). 13 | % atomLattice - [N x 4] array representing the basis for a fitted lattice: 14 | % [1 a b c] for the linear lattice equation: 15 | % r = r0 + a*u + b*v + c*w where (u,v,w) are 3 lattice vectors 16 | 17 | % Other variables: 18 | flagCenterAtoms = true; 19 | flagMoveAtomsToLattice = false; 20 | 21 | % Appearance of atoms 22 | atomSize = 40; 23 | atomColors = [ ... 24 | 1 0 0; 25 | 0 0.7 1]; 26 | atomColorEdges = [0 0 0]; 27 | flagPlotAtomTint = true; 28 | atomLinewidth = 1; 29 | 30 | % tinting 31 | atomColorTint = [1 1 1]; 32 | atomSizeTint = 5; 33 | atomShiftTint = [0 -1 2]; 34 | % atomSizeTint = 3; 35 | % atomShiftTint = [0 2 1]; 36 | 37 | % Shadowing 38 | flagApplyShadows = false; 39 | % radiusShadow = 4; 40 | % shadingShadow = 0.5; % reduction of intensity for being shadowed 41 | %vecShadow = [1 -1 1]; % direction vector for casting shadow 42 | radiusShadow = [3 4.5]; 43 | shadingShadow = [0.7 0.85]; % reduction of intensity for being shadowed 44 | vecShadow = [0.5 1 0.5]; % direction vector for casting shadow 45 | 46 | 47 | % Shading / depth cueing 48 | flagApplyDepthShading = true; 49 | atomsDepthShade = [1 0.25]; % [closest_to_camera furthest_from_camera] 50 | atomsDepthPower = 1; 51 | 52 | 53 | % positioning and splitting of atomic planes 54 | splitPlanesBunch = 2; % How many planes to group together in each slice 55 | splitPlanesShift = -1; % additive shift of atomic planes 56 | splitPlanesDistance = 70; % multiplicative shift of atomic planes (spacing) 57 | splitPlanesIndex = 2; % 1 for x, 2 for y, 3 for z 58 | 59 | 60 | % Camera stuff 61 | cameraTarget = [0 0 0]; 62 | % cameraPosition = [4 2 1]*1000; 63 | cameraAngle = 5; 64 | 65 | % init 66 | numberAtoms = size(atomData,1); 67 | 68 | 69 | % position of all atoms 70 | atomPos = zeros(numberAtoms,3); 71 | atomPos(:) = atomData(:,1:3); 72 | if flagCenterAtoms == true 73 | for a0 = 1:3 74 | atomPos(:,a0) = atomPos(:,a0) - mean(atomPos(:,a0)); 75 | end 76 | end 77 | 78 | % Shift atoms to best fit lattice coordinates 79 | if flagMoveAtomsToLattice == true 80 | subFit = ~isinf(sum(atomLattice,2)) ... 81 | & ~isnan(sum(atomLattice,2)); 82 | 83 | lat = atomLattice(subFit,:) \ atomPos(subFit,:); 84 | atomPos(subFit,:) = atomLattice(subFit,:) * lat; 85 | end 86 | 87 | 88 | % Measure distance of all atoms from camera 89 | distCamera = sqrt( ... 90 | (atomPos(:,1) - cameraPosition(1)).^2 + ... 91 | (atomPos(:,2) - cameraPosition(2)).^2 + ... 92 | (atomPos(:,3) - cameraPosition(3)).^2); 93 | 94 | % Split apart atomic planes to reveal interior structure 95 | if splitPlanesDistance > 0 96 | atomIndex = atomLattice(:,splitPlanesIndex+1); 97 | atomIndex(:) = atomIndex - median(atomIndex) + splitPlanesShift; 98 | atomIndex(:) = round(atomIndex / splitPlanesBunch); 99 | 100 | atomPos(:,splitPlanesIndex) = atomPos(:,splitPlanesIndex) ... 101 | + atomIndex * splitPlanesDistance; 102 | end 103 | 104 | 105 | % Generate coloring for all atoms 106 | atomTypes = unique(atomData(:,4)); 107 | atomRGB = zeros(numberAtoms,3); 108 | for a0 = 1:length(atomTypes) 109 | sub = atomData(:,4) == atomTypes(a0); 110 | atomRGB(sub,1) = atomColors(a0,1); 111 | atomRGB(sub,2) = atomColors(a0,2); 112 | atomRGB(sub,3) = atomColors(a0,3); 113 | end 114 | 115 | % Apply depth shading / depth cueing 116 | if flagApplyDepthShading == true 117 | scaleColor = distCamera - min(distCamera); 118 | scaleColor(:) = scaleColor / max(scaleColor); % scaled from 0 to 1 119 | scaleColor(:) = 3*scaleColor(:).^2 - 2*scaleColor(:).^3; 120 | scaleColor(:) = scaleColor.^atomsDepthPower; 121 | scaleColor = atomsDepthShade(1) + ... 122 | scaleColor*(atomsDepthShade(2) - atomsDepthShade(1)); % scaled to atomsDepthShade 123 | atomRGB(:) = atomRGB .* scaleColor; 124 | end 125 | 126 | 127 | % Apply shadowing 128 | if flagApplyShadows == true 129 | vecShadow = vecShadow / norm(vecShadow); 130 | distProj2 = zeros(numberAtoms,1); 131 | sub = false(numberAtoms,1); 132 | vecRep = repmat(vecShadow,[numberAtoms 1]); 133 | radiusShadow2 = radiusShadow.^2; 134 | 135 | subShadowed = false(numberAtoms,1); 136 | 137 | % Loop through each atomic site, determine if it is shadowed or not 138 | for a0 = 1:numberAtoms 139 | xyz0 = atomPos(a0,1:3); % site under consideration 140 | 141 | % Projected distance from shadow vector direction starting from xyz0 142 | % distProj(:) = abs(sum((atomPos - xyz0).*vecShadow,2)); 143 | distProj2(:) = sum(cross(atomPos - xyz0, vecRep).^2,2); 144 | % subset of atoms on the correct side to be shadowed 145 | sub(:) = sum((atomPos - xyz0).*vecShadow,2) > 0; 146 | minDist2 = min(distProj2(sub)); 147 | 148 | if minDist2 < radiusShadow2(1) 149 | atomRGB(a0,:) = atomRGB(a0,:) * shadingShadow(1); 150 | subShadowed(a0) = true; 151 | elseif minDist2 < radiusShadow2(2) 152 | atomRGB(a0,:) = atomRGB(a0,:) * shadingShadow(2); 153 | subShadowed(a0) = true; 154 | end 155 | end 156 | end 157 | 158 | 159 | 160 | % plotting 161 | figure(12) 162 | clf 163 | set(gcf,'color','w'); 164 | set(gcf,'outerposition',[500 500 576+512-6 512+6]) 165 | 166 | axes('position',[0 0 1 1]) 167 | hold on 168 | 169 | % Plot atoms 170 | % scatter3( ... 171 | % atomPos(:,1),... 172 | % atomPos(:,2),... 173 | % atomPos(:,3)); 174 | % scatter3( ... 175 | % atomPos(:,1),... 176 | % atomPos(:,2),... 177 | % atomPos(:,3),... 178 | % ones(numberAtoms,1)*atomSize,... 179 | % atomRGB); 180 | scatter3( ... 181 | atomPos(:,1),... 182 | atomPos(:,2),... 183 | atomPos(:,3),... 184 | ones(numberAtoms,1)*atomSize,... 185 | atomRGB,... 186 | 'filled','marker','o','linewidth',atomLinewidth,... 187 | 'markeredgecolor',atomColorEdges); 188 | 189 | 190 | if flagPlotAtomTint == true 191 | % Move tints in slightly front of other atoms, apply shift 192 | shiftTint = cameraPosition / norm(cameraPosition); 193 | shiftTint = shiftTint*0.1 + atomShiftTint; 194 | 195 | if flagApplyShadows == false 196 | scatter3( ... 197 | atomPos(:,1) + shiftTint(1),... 198 | atomPos(:,2) + shiftTint(2),... 199 | atomPos(:,3) + shiftTint(3),... 200 | 'sizedata',atomSizeTint,... 201 | 'marker','o',... 202 | 'markeredgecolor','none',... 203 | 'markerfacecolor',atomColorTint); 204 | else 205 | 206 | scatter3( ... 207 | atomPos(~subShadowed,1) + shiftTint(1),... 208 | atomPos(~subShadowed,2) + shiftTint(2),... 209 | atomPos(~subShadowed,3) + shiftTint(3),... 210 | 'sizedata',atomSizeTint,... 211 | 'marker','o',... 212 | 'markeredgecolor','none',... 213 | 'markerfacecolor',atomColorTint); 214 | end 215 | end 216 | 217 | 218 | 219 | hold off 220 | 221 | axis equal off 222 | 223 | 224 | % Camera stuff 225 | camtarget(cameraTarget) 226 | campos(cameraTarget + cameraPosition); 227 | camva(cameraAngle) 228 | camproj('perspective') 229 | 230 | 231 | 232 | 233 | end -------------------------------------------------------------------------------- /matlab/part_03_04_atoms/animAtoms01b.m: -------------------------------------------------------------------------------- 1 | function [] = animAtoms01b(atomData,atomLattice,fileNameBase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - animating the atom plot from the FePt sample 5 | 6 | % This script calls animAtoms01a.m with rotating camera angles, and then 7 | % outputs images with export_fig.m in order to render a movie. 8 | 9 | % Inputs 10 | % fbase - Character string for output file names. Note that you must 11 | % create output directories before writing to them. 12 | numberFrames = 60*6; 13 | thetaStart = 26.565*pi/180; 14 | cameraRadius = norm([4 2])*1000; 15 | cameraHeight = 1000; 16 | 17 | 18 | % camera variables 19 | thetaArray = linspace(0,2*pi,numberFrames+1) + thetaStart; 20 | thetaArray(end) = []; 21 | 22 | % Main loop 23 | for a0 = 1:numberFrames 24 | cameraPosition = [ ... 25 | cameraRadius*cos(thetaArray(a0)) ... 26 | cameraRadius*sin(thetaArray(a0)) ... 27 | cameraHeight]; 28 | 29 | % draw figure 30 | animAtoms01a(atomData,atomLattice,cameraPosition); 31 | 32 | % Output image 33 | fileName = [fileNameBase sprintf('%04d',a0) '.png']; 34 | evalc(['export_fig -nocrop -r90 ' fileName]); 35 | end 36 | 37 | 38 | 39 | end -------------------------------------------------------------------------------- /matlab/part_03_04_atoms/animAtoms02a.m: -------------------------------------------------------------------------------- 1 | function [] = animAtoms02a(atomData,atomLattice,splitPlanesDistance) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example 02 - plotting atoms from the FePt sample 5 | 6 | % In this example, we will plot atoms in 3D, with separation between atomic 7 | % planes, coloring, shading (depth cueing) 8 | % Version 01 - 3D scatter plot with some plotting tricks 9 | 10 | % Inputs: 11 | % atomData - [N x 4] array, where first three columns are (x,y,z) and last 12 | % column is the atom ID (1, 2, ...). 13 | % atomLattice - [N x 4] array representing the basis for a fitted lattice: 14 | % [1 a b c] for the linear lattice equation: 15 | % r = r0 + a*u + b*v + c*w where (u,v,w) are 3 lattice vectors 16 | 17 | % Other variables: 18 | flagCenterAtoms = true; 19 | flagMoveAtomsToLattice = false; 20 | 21 | % Appearance of atoms 22 | atomSize = 40; 23 | atomColors = [ ... 24 | 1 0 0; 25 | 0 0.7 1]; 26 | atomColorEdges = [0 0 0]; 27 | flagPlotAtomTint = true; 28 | atomLinewidth = 1; 29 | 30 | % tinting 31 | atomColorTint = [1 1 1]; 32 | % atomSizeTint = 5; 33 | % atomShiftTint = [0 -1 2]; 34 | 35 | 36 | % Shadowing 37 | flagApplyShadows = true; 38 | % radiusShadow = 4; 39 | % shadingShadow = 0.5; % reduction of intensity for being shadowed 40 | %vecShadow = [1 -1 1]; % direction vector for casting shadow 41 | radiusShadow = [3 4.5]; 42 | shadingShadow = [0.7 0.85]; % reduction of intensity for being shadowed 43 | vecShadow = [0.5 1 0.5]; % direction vector for casting shadow 44 | atomSizeTint = 3; 45 | atomShiftTint = [0 2 1]; 46 | 47 | % Shading / depth cueing 48 | flagApplyDepthShading = true; 49 | atomsDepthShade = [1 0.25]; % [closest_to_camera furthest_from_camera] 50 | atomsDepthPower = 1; 51 | 52 | 53 | % positioning and splitting of atomic planes 54 | splitPlanesBunch = 2; % How many planes to group together in each slice 55 | splitPlanesShift = -1-0.5*0; % additive shift of atomic planes 56 | % splitPlanesDistance = 70; % multiplicative shift of atomic planes (spacing) 57 | splitPlanesIndex = 2; % 1 for x, 2 for y, 3 for z 58 | 59 | 60 | % Camera stuff 61 | cameraTarget = [0 0 0]; 62 | cameraPosition = [4 2 1]*1000; 63 | cameraAngle = 5; 64 | 65 | % init 66 | numberAtoms = size(atomData,1); 67 | 68 | 69 | % position of all atoms 70 | atomPos = zeros(numberAtoms,3); 71 | atomPos(:) = atomData(:,1:3); 72 | if flagCenterAtoms == true 73 | for a0 = 1:3 74 | atomPos(:,a0) = atomPos(:,a0) - mean(atomPos(:,a0)); 75 | end 76 | end 77 | 78 | % Shift atoms to best fit lattice coordinates 79 | if flagMoveAtomsToLattice == true 80 | subFit = ~isinf(sum(atomLattice,2)) ... 81 | & ~isnan(sum(atomLattice,2)); 82 | 83 | lat = atomLattice(subFit,:) \ atomPos(subFit,:); 84 | atomPos(subFit,:) = atomLattice(subFit,:) * lat; 85 | end 86 | 87 | 88 | % Measure distance of all atoms from camera 89 | distCamera = sqrt( ... 90 | (atomPos(:,1) - cameraPosition(1)).^2 + ... 91 | (atomPos(:,2) - cameraPosition(2)).^2 + ... 92 | (atomPos(:,3) - cameraPosition(3)).^2); 93 | 94 | % Split apart atomic planes to reveal interior structure 95 | if splitPlanesDistance > 0 96 | atomIndex = atomLattice(:,splitPlanesIndex+1); 97 | atomIndex(:) = atomIndex - median(atomIndex) + splitPlanesShift; 98 | atomIndex(:) = round(atomIndex / splitPlanesBunch); 99 | 100 | atomPos(:,splitPlanesIndex) = atomPos(:,splitPlanesIndex) ... 101 | + atomIndex * splitPlanesDistance; 102 | end 103 | 104 | 105 | % Generate coloring for all atoms 106 | atomTypes = unique(atomData(:,4)); 107 | atomRGB = zeros(numberAtoms,3); 108 | for a0 = 1:length(atomTypes) 109 | sub = atomData(:,4) == atomTypes(a0); 110 | atomRGB(sub,1) = atomColors(a0,1); 111 | atomRGB(sub,2) = atomColors(a0,2); 112 | atomRGB(sub,3) = atomColors(a0,3); 113 | end 114 | 115 | % Apply depth shading / depth cueing 116 | if flagApplyDepthShading == true 117 | scaleColor = distCamera - min(distCamera); 118 | scaleColor(:) = scaleColor / max(scaleColor); % scaled from 0 to 1 119 | scaleColor(:) = 3*scaleColor(:).^2 - 2*scaleColor(:).^3; 120 | scaleColor(:) = scaleColor.^atomsDepthPower; 121 | scaleColor = atomsDepthShade(1) + ... 122 | scaleColor*(atomsDepthShade(2) - atomsDepthShade(1)); % scaled to atomsDepthShade 123 | atomRGB(:) = atomRGB .* scaleColor; 124 | end 125 | 126 | 127 | % Apply shadowing 128 | if flagApplyShadows == true 129 | vecShadow = vecShadow / norm(vecShadow); 130 | distProj2 = zeros(numberAtoms,1); 131 | sub = false(numberAtoms,1); 132 | vecRep = repmat(vecShadow,[numberAtoms 1]); 133 | radiusShadow2 = radiusShadow.^2; 134 | 135 | subShadowed = false(numberAtoms,1); 136 | 137 | % Loop through each atomic site, determine if it is shadowed or not 138 | for a0 = 1:numberAtoms 139 | xyz0 = atomPos(a0,1:3); % site under consideration 140 | 141 | % Projected distance from shadow vector direction starting from xyz0 142 | % distProj(:) = abs(sum((atomPos - xyz0).*vecShadow,2)); 143 | distProj2(:) = sum(cross(atomPos - xyz0, vecRep).^2,2); 144 | % subset of atoms on the correct side to be shadowed 145 | sub(:) = sum((atomPos - xyz0).*vecShadow,2) > 0; 146 | minDist2 = min(distProj2(sub)); 147 | 148 | if minDist2 < radiusShadow2(1) 149 | atomRGB(a0,:) = atomRGB(a0,:) * shadingShadow(1); 150 | subShadowed(a0) = true; 151 | elseif minDist2 < radiusShadow2(2) 152 | atomRGB(a0,:) = atomRGB(a0,:) * shadingShadow(2); 153 | subShadowed(a0) = true; 154 | end 155 | end 156 | end 157 | 158 | 159 | 160 | % plotting 161 | figure(12) 162 | clf 163 | set(gcf,'color','w'); 164 | % set(gcf,'outerposition',[500 500 576+512 512]) 165 | set(gcf,'outerposition',[500 500 576+512-6 512+6]) 166 | 167 | axes('position',[0 0 1 1]) 168 | hold on 169 | 170 | % Plot atoms 171 | % scatter3( ... 172 | % atomPos(:,1),... 173 | % atomPos(:,2),... 174 | % atomPos(:,3)); 175 | % scatter3( ... 176 | % atomPos(:,1),... 177 | % atomPos(:,2),... 178 | % atomPos(:,3),... 179 | % ones(numberAtoms,1)*atomSize,... 180 | % atomRGB); 181 | scatter3( ... 182 | atomPos(:,1),... 183 | atomPos(:,2),... 184 | atomPos(:,3),... 185 | ones(numberAtoms,1)*atomSize,... 186 | atomRGB,... 187 | 'filled','marker','o','linewidth',atomLinewidth,... 188 | 'markeredgecolor',atomColorEdges); 189 | 190 | 191 | if flagPlotAtomTint == true 192 | % Move tints in slightly front of other atoms, apply shift 193 | shiftTint = cameraPosition / norm(cameraPosition); 194 | shiftTint = shiftTint*0.1 + atomShiftTint; 195 | 196 | if flagApplyShadows == false 197 | scatter3( ... 198 | atomPos(:,1) + shiftTint(1),... 199 | atomPos(:,2) + shiftTint(2),... 200 | atomPos(:,3) + shiftTint(3),... 201 | 'sizedata',atomSizeTint,... 202 | 'marker','o',... 203 | 'markeredgecolor','none',... 204 | 'markerfacecolor',atomColorTint); 205 | else 206 | 207 | scatter3( ... 208 | atomPos(~subShadowed,1) + shiftTint(1),... 209 | atomPos(~subShadowed,2) + shiftTint(2),... 210 | atomPos(~subShadowed,3) + shiftTint(3),... 211 | 'sizedata',atomSizeTint,... 212 | 'marker','o',... 213 | 'markeredgecolor','none',... 214 | 'markerfacecolor',atomColorTint); 215 | end 216 | end 217 | 218 | 219 | 220 | hold off 221 | 222 | axis equal off 223 | 224 | 225 | % Camera stuff 226 | camtarget(cameraTarget) 227 | campos(cameraTarget + cameraPosition); 228 | camva(cameraAngle) 229 | camproj('perspective') 230 | 231 | 232 | 233 | 234 | end -------------------------------------------------------------------------------- /matlab/part_03_04_atoms/animAtoms02b.m: -------------------------------------------------------------------------------- 1 | function [] = animAtoms02b(atomData,atomLattice,fileNameBase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - animating the atom plot from the FePt sample 5 | 6 | % This script calls animAtoms01a.m with rotating camera angles, and then 7 | % outputs images with export_fig.m in order to render a movie. 8 | 9 | % Inputs 10 | % fbase - Character string for output file names. Note that you must 11 | % create output directories before writing to them. 12 | numberFrames = 60*2; 13 | splitPlanes = linspace(0,70,numberFrames); 14 | 15 | % Main loop 16 | for a0 = 1:numberFrames 17 | % draw figure 18 | animAtoms02a(atomData,atomLattice,splitPlanes(a0)); 19 | 20 | % Output image 21 | fileName = [fileNameBase sprintf('%04d',a0) '.png']; 22 | evalc(['export_fig -nocrop -r90 ' fileName]); 23 | end 24 | 25 | 26 | 27 | end -------------------------------------------------------------------------------- /matlab/part_03_04_atoms/atomData02.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/matlab/part_03_04_atoms/atomData02.mat -------------------------------------------------------------------------------- /matlab/part_03_04_atoms/plotAtoms00.m: -------------------------------------------------------------------------------- 1 | function [] = plotAtoms00(atomData,atomLattice) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example 02 - plotting atoms from the FePt sample 5 | 6 | % In this example, we will plot atoms in 3D, with separation between atomic 7 | % planes, coloring, shading (depth cueing) 8 | % Version 01 - 3D scatter plot with some plotting tricks 9 | 10 | % Inputs: 11 | % atomData - [N x 4] array, where first three columns are (x,y,z) and last 12 | % column is the atom ID (1, 2, ...). 13 | % atomLattice - [N x 4] array representing the basis for a fitted lattice: 14 | % [1 a b c] for the linear lattice equation: 15 | % r = r0 + a*u + b*v + c*w where (u,v,w) are 3 lattice vectors 16 | 17 | % Other variables: 18 | flagCenterAtoms = 0; 19 | flagMoveAtomsToLattice = false; 20 | 21 | % Appearance of atoms 22 | atomSize = 40; 23 | atomColors = [ ... 24 | 1 0 0; 25 | 0 0.7 1]; 26 | atomColorEdges = [0 0 0]; 27 | flagPlotAtomTint = true; 28 | atomLinewidth = 1; 29 | 30 | % tinting 31 | atomColorTint = [1 1 1]; 32 | atomSizeTint = 5; 33 | atomShiftTint = [0 -1 2]; 34 | 35 | 36 | % Shadowing 37 | flagApplyShadows = 0; 38 | % radiusShadow = 4; 39 | % shadingShadow = 0.5; % reduction of intensity for being shadowed 40 | %vecShadow = [1 -1 1]; % direction vector for casting shadow 41 | radiusShadow = [3 4.5]; 42 | shadingShadow = [0.7 0.85]; % reduction of intensity for being shadowed 43 | vecShadow = [0.5 1 0.5]; % direction vector for casting shadow 44 | % % moving tint reflection to match shadow 45 | % atomSizeTint = 3; 46 | % atomShiftTint = [0 2 1]; 47 | 48 | % Shading / depth cueing 49 | flagApplyDepthShading = 0; 50 | atomsDepthShade = [1 0.25]; % [closest_to_camera furthest_from_camera] 51 | atomsDepthPower = 1; 52 | 53 | 54 | % positioning and splitting of atomic planes 55 | splitPlanesBunch = 2; % How many planes to group together in each slice 56 | splitPlanesShift = -1 - 0.5*0; % additive shift of atomic planes 57 | splitPlanesDistance = 70*0; % multiplicative shift of atomic planes (spacing) 58 | splitPlanesIndex = 2; % 1 for x, 2 for y, 3 for z 59 | 60 | 61 | % Camera stuff 62 | cameraTarget = [0 0 0]; 63 | cameraPosition = [4 2 1]*1000; 64 | cameraAngle = 5; 65 | 66 | % init 67 | numberAtoms = size(atomData,1); 68 | 69 | 70 | % position of all atoms 71 | atomPos = zeros(numberAtoms,3); 72 | atomPos(:) = atomData(:,1:3); 73 | if flagCenterAtoms == true 74 | for a0 = 1:3 75 | atomPos(:,a0) = atomPos(:,a0) - mean(atomPos(:,a0)); 76 | end 77 | end 78 | 79 | % Shift atoms to best fit lattice coordinates 80 | if flagMoveAtomsToLattice == true 81 | subFit = ~isinf(sum(atomLattice,2)) ... 82 | & ~isnan(sum(atomLattice,2)); 83 | 84 | lat = atomLattice(subFit,:) \ atomPos(subFit,:); 85 | atomPos(subFit,:) = atomLattice(subFit,:) * lat; 86 | end 87 | 88 | 89 | % Measure distance of all atoms from camera 90 | distCamera = sqrt( ... 91 | (atomPos(:,1) - cameraPosition(1)).^2 + ... 92 | (atomPos(:,2) - cameraPosition(2)).^2 + ... 93 | (atomPos(:,3) - cameraPosition(3)).^2); 94 | 95 | % Split apart atomic planes to reveal interior structure 96 | if splitPlanesDistance > 0 97 | atomIndex = atomLattice(:,splitPlanesIndex+1); 98 | atomIndex(:) = atomIndex - median(atomIndex) + splitPlanesShift; 99 | atomIndex(:) = round(atomIndex / splitPlanesBunch); 100 | 101 | atomPos(:,splitPlanesIndex) = atomPos(:,splitPlanesIndex) ... 102 | + atomIndex * splitPlanesDistance; 103 | end 104 | 105 | 106 | % Generate coloring for all atoms 107 | atomTypes = unique(atomData(:,4)); 108 | atomRGB = zeros(numberAtoms,3); 109 | for a0 = 1:length(atomTypes) 110 | sub = atomData(:,4) == atomTypes(a0); 111 | atomRGB(sub,1) = atomColors(a0,1); 112 | atomRGB(sub,2) = atomColors(a0,2); 113 | atomRGB(sub,3) = atomColors(a0,3); 114 | end 115 | 116 | % Apply depth shading / depth cueing 117 | if flagApplyDepthShading == true 118 | scaleColor = distCamera - min(distCamera); 119 | scaleColor(:) = scaleColor / max(scaleColor); % scaled from 0 to 1 120 | scaleColor(:) = 3*scaleColor(:).^2 - 2*scaleColor(:).^3; 121 | scaleColor(:) = scaleColor.^atomsDepthPower; 122 | scaleColor = atomsDepthShade(1) + ... 123 | scaleColor*(atomsDepthShade(2) - atomsDepthShade(1)); % scaled to atomsDepthShade 124 | atomRGB(:) = atomRGB .* scaleColor; 125 | end 126 | 127 | 128 | % Apply shadowing 129 | if flagApplyShadows == true 130 | vecShadow = vecShadow / norm(vecShadow); 131 | distProj2 = zeros(numberAtoms,1); 132 | sub = false(numberAtoms,1); 133 | vecRep = repmat(vecShadow,[numberAtoms 1]); 134 | radiusShadow2 = radiusShadow.^2; 135 | 136 | subShadowed = false(numberAtoms,1); 137 | 138 | % Loop through each atomic site, determine if it is shadowed or not 139 | for a0 = 1:numberAtoms 140 | xyz0 = atomPos(a0,1:3); % site under consideration 141 | 142 | % Projected distance from shadow vector direction starting from xyz0 143 | % distProj(:) = abs(sum((atomPos - xyz0).*vecShadow,2)); 144 | distProj2(:) = sum(cross(atomPos - xyz0, vecRep).^2,2); 145 | % subset of atoms on the correct side to be shadowed 146 | sub(:) = sum((atomPos - xyz0).*vecShadow,2) > 0; 147 | minDist2 = min(distProj2(sub)); 148 | 149 | if minDist2 < radiusShadow2(1) 150 | atomRGB(a0,:) = atomRGB(a0,:) * shadingShadow(1); 151 | subShadowed(a0) = true; 152 | elseif minDist2 < radiusShadow2(2) 153 | atomRGB(a0,:) = atomRGB(a0,:) * shadingShadow(2); 154 | subShadowed(a0) = true; 155 | end 156 | end 157 | end 158 | 159 | 160 | 161 | % plotting 162 | figure(12) 163 | clf 164 | % set(gcf,'outerposition',[500 500 576+512 512]) 165 | % set(gcf,'outerposition',[500 500 576+512-6 512+6]) 166 | % set(gcf,'color','w'); 167 | set(gcf,'outerposition',[500 500 576+512-5 512+8]) 168 | 169 | % axes('position',[0 0 1 1]) 170 | hold on 171 | 172 | % Plot atoms 173 | scatter3( ... 174 | atomPos(:,1),... 175 | atomPos(:,2),... 176 | atomPos(:,3)); 177 | % scatter3( ... 178 | % atomPos(:,1),... 179 | % atomPos(:,2),... 180 | % atomPos(:,3),... 181 | % ones(numberAtoms,1)*atomSize,... 182 | % atomRGB); 183 | % scatter3( ... 184 | % atomPos(:,1),... 185 | % atomPos(:,2),... 186 | % atomPos(:,3),... 187 | % ones(numberAtoms,1)*atomSize,... 188 | % atomRGB,... 189 | % 'filled','marker','o','linewidth',atomLinewidth,... 190 | % 'markeredgecolor',atomColorEdges); 191 | 192 | 193 | if flagPlotAtomTint == true 194 | % Move tints in slightly front of other atoms, apply shift 195 | shiftTint = cameraPosition / norm(cameraPosition); 196 | shiftTint = shiftTint*0.1 + atomShiftTint; 197 | 198 | % if flagApplyShadows == false 199 | % scatter3( ... 200 | % atomPos(:,1) + shiftTint(1),... 201 | % atomPos(:,2) + shiftTint(2),... 202 | % atomPos(:,3) + shiftTint(3),... 203 | % 'sizedata',atomSizeTint,... 204 | % 'marker','o',... 205 | % 'markeredgecolor','none',... 206 | % 'markerfacecolor',atomColorTint); 207 | % else 208 | % 209 | % scatter3( ... 210 | % atomPos(~subShadowed,1) + shiftTint(1),... 211 | % atomPos(~subShadowed,2) + shiftTint(2),... 212 | % atomPos(~subShadowed,3) + shiftTint(3),... 213 | % 'sizedata',atomSizeTint,... 214 | % 'marker','o',... 215 | % 'markeredgecolor','none',... 216 | % 'markerfacecolor',atomColorTint); 217 | % end 218 | end 219 | 220 | 221 | 222 | hold off 223 | 224 | % axis equal off 225 | 226 | 227 | % % Camera stuff 228 | % camtarget(cameraTarget) 229 | % campos(cameraTarget + cameraPosition); 230 | % camva(cameraAngle) 231 | % camproj('perspective') 232 | 233 | 234 | 235 | 236 | end -------------------------------------------------------------------------------- /matlab/part_03_04_atoms/plotAtoms01.m: -------------------------------------------------------------------------------- 1 | function [] = plotAtoms01(atomData,atomLattice) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example 02 - plotting atoms from the FePt sample 5 | 6 | % In this example, we will plot atoms in 3D, with separation between atomic 7 | % planes, coloring, shading (depth cueing) 8 | % Version 01 - 3D scatter plot with some plotting tricks 9 | 10 | % Inputs: 11 | % atomData - [N x 4] array, where first three columns are (x,y,z) and last 12 | % column is the atom ID (1, 2, ...). 13 | % atomLattice - [N x 4] array representing the basis for a fitted lattice: 14 | % [1 a b c] for the linear lattice equation: 15 | % r = r0 + a*u + b*v + c*w where (u,v,w) are 3 lattice vectors 16 | 17 | % Other variables: 18 | flagCenterAtoms = true; 19 | flagMoveAtomsToLattice = false; 20 | 21 | % Appearance of atoms 22 | atomSize = 40; 23 | atomColors = [ ... 24 | 1 0 0; 25 | 0 0.7 1]; 26 | atomColorEdges = [0 0 0]; 27 | flagPlotAtomTint = true; 28 | atomLinewidth = 1; 29 | 30 | % tinting 31 | atomColorTint = [1 1 1]; 32 | atomSizeTint = 5; 33 | atomShiftTint = [0 -1 2]; 34 | % atomSizeTint = 3; 35 | % atomShiftTint = [0 2 1]; 36 | 37 | % Shadowing 38 | flagApplyShadows = false; 39 | % radiusShadow = 4; 40 | % shadingShadow = 0.5; % reduction of intensity for being shadowed 41 | %vecShadow = [1 -1 1]; % direction vector for casting shadow 42 | radiusShadow = [3 4.5]; 43 | shadingShadow = [0.7 0.85]; % reduction of intensity for being shadowed 44 | vecShadow = [0.5 1 0.5]; % direction vector for casting shadow 45 | 46 | 47 | % Shading / depth cueing 48 | flagApplyDepthShading = true; 49 | atomsDepthShade = [1 0.25]; % [closest_to_camera furthest_from_camera] 50 | atomsDepthPower = 1; 51 | 52 | 53 | % positioning and splitting of atomic planes 54 | splitPlanesBunch = 2; % How many planes to group together in each slice 55 | splitPlanesShift = -1; % additive shift of atomic planes 56 | splitPlanesDistance = 70; % multiplicative shift of atomic planes (spacing) 57 | splitPlanesIndex = 2; % 1 for x, 2 for y, 3 for z 58 | 59 | 60 | % Camera stuff 61 | cameraTarget = [0 0 0]; 62 | cameraPosition = [4 2 1]*1000; 63 | cameraAngle = 5; 64 | 65 | % init 66 | numberAtoms = size(atomData,1); 67 | 68 | 69 | % position of all atoms 70 | atomPos = zeros(numberAtoms,3); 71 | atomPos(:) = atomData(:,1:3); 72 | if flagCenterAtoms == true 73 | for a0 = 1:3 74 | atomPos(:,a0) = atomPos(:,a0) - mean(atomPos(:,a0)); 75 | end 76 | end 77 | 78 | % Shift atoms to best fit lattice coordinates 79 | if flagMoveAtomsToLattice == true 80 | subFit = ~isinf(sum(atomLattice,2)) ... 81 | & ~isnan(sum(atomLattice,2)); 82 | 83 | lat = atomLattice(subFit,:) \ atomPos(subFit,:); 84 | atomPos(subFit,:) = atomLattice(subFit,:) * lat; 85 | end 86 | 87 | 88 | % Measure distance of all atoms from camera 89 | distCamera = sqrt( ... 90 | (atomPos(:,1) - cameraPosition(1)).^2 + ... 91 | (atomPos(:,2) - cameraPosition(2)).^2 + ... 92 | (atomPos(:,3) - cameraPosition(3)).^2); 93 | 94 | % Split apart atomic planes to reveal interior structure 95 | if splitPlanesDistance > 0 96 | atomIndex = atomLattice(:,splitPlanesIndex+1); 97 | atomIndex(:) = atomIndex - median(atomIndex) + splitPlanesShift; 98 | atomIndex(:) = round(atomIndex / splitPlanesBunch); 99 | 100 | atomPos(:,splitPlanesIndex) = atomPos(:,splitPlanesIndex) ... 101 | + atomIndex * splitPlanesDistance; 102 | end 103 | 104 | 105 | % Generate coloring for all atoms 106 | atomTypes = unique(atomData(:,4)); 107 | atomRGB = zeros(numberAtoms,3); 108 | for a0 = 1:length(atomTypes) 109 | sub = atomData(:,4) == atomTypes(a0); 110 | atomRGB(sub,1) = atomColors(a0,1); 111 | atomRGB(sub,2) = atomColors(a0,2); 112 | atomRGB(sub,3) = atomColors(a0,3); 113 | end 114 | 115 | % Apply depth shading / depth cueing 116 | if flagApplyDepthShading == true 117 | scaleColor = distCamera - min(distCamera); 118 | scaleColor(:) = scaleColor / max(scaleColor); % scaled from 0 to 1 119 | scaleColor(:) = 3*scaleColor(:).^2 - 2*scaleColor(:).^3; 120 | scaleColor(:) = scaleColor.^atomsDepthPower; 121 | scaleColor = atomsDepthShade(1) + ... 122 | scaleColor*(atomsDepthShade(2) - atomsDepthShade(1)); % scaled to atomsDepthShade 123 | atomRGB(:) = atomRGB .* scaleColor; 124 | end 125 | 126 | 127 | % Apply shadowing 128 | if flagApplyShadows == true 129 | vecShadow = vecShadow / norm(vecShadow); 130 | distProj2 = zeros(numberAtoms,1); 131 | sub = false(numberAtoms,1); 132 | vecRep = repmat(vecShadow,[numberAtoms 1]); 133 | radiusShadow2 = radiusShadow.^2; 134 | 135 | subShadowed = false(numberAtoms,1); 136 | 137 | % Loop through each atomic site, determine if it is shadowed or not 138 | for a0 = 1:numberAtoms 139 | xyz0 = atomPos(a0,1:3); % site under consideration 140 | 141 | % Projected distance from shadow vector direction starting from xyz0 142 | % distProj(:) = abs(sum((atomPos - xyz0).*vecShadow,2)); 143 | distProj2(:) = sum(cross(atomPos - xyz0, vecRep).^2,2); 144 | % subset of atoms on the correct side to be shadowed 145 | sub(:) = sum((atomPos - xyz0).*vecShadow,2) > 0; 146 | minDist2 = min(distProj2(sub)); 147 | 148 | if minDist2 < radiusShadow2(1) 149 | atomRGB(a0,:) = atomRGB(a0,:) * shadingShadow(1); 150 | subShadowed(a0) = true; 151 | elseif minDist2 < radiusShadow2(2) 152 | atomRGB(a0,:) = atomRGB(a0,:) * shadingShadow(2); 153 | subShadowed(a0) = true; 154 | end 155 | end 156 | end 157 | 158 | 159 | 160 | % plotting 161 | figure(12) 162 | clf 163 | set(gcf,'color','w'); 164 | % set(gcf,'outerposition',[500 500 576+512 512]) 165 | set(gcf,'outerposition',[500 500 576+512-6 512+6]) 166 | 167 | axes('position',[0 0 1 1]) 168 | hold on 169 | 170 | % Plot atoms 171 | % scatter3( ... 172 | % atomPos(:,1),... 173 | % atomPos(:,2),... 174 | % atomPos(:,3)); 175 | % scatter3( ... 176 | % atomPos(:,1),... 177 | % atomPos(:,2),... 178 | % atomPos(:,3),... 179 | % ones(numberAtoms,1)*atomSize,... 180 | % atomRGB); 181 | scatter3( ... 182 | atomPos(:,1),... 183 | atomPos(:,2),... 184 | atomPos(:,3),... 185 | ones(numberAtoms,1)*atomSize,... 186 | atomRGB,... 187 | 'filled','marker','o','linewidth',atomLinewidth,... 188 | 'markeredgecolor',atomColorEdges); 189 | 190 | 191 | if flagPlotAtomTint == true 192 | % Move tints in slightly front of other atoms, apply shift 193 | shiftTint = cameraPosition / norm(cameraPosition); 194 | shiftTint = shiftTint*0.1 + atomShiftTint; 195 | 196 | if flagApplyShadows == false 197 | scatter3( ... 198 | atomPos(:,1) + shiftTint(1),... 199 | atomPos(:,2) + shiftTint(2),... 200 | atomPos(:,3) + shiftTint(3),... 201 | 'sizedata',atomSizeTint,... 202 | 'marker','o',... 203 | 'markeredgecolor','none',... 204 | 'markerfacecolor',atomColorTint); 205 | else 206 | 207 | scatter3( ... 208 | atomPos(~subShadowed,1) + shiftTint(1),... 209 | atomPos(~subShadowed,2) + shiftTint(2),... 210 | atomPos(~subShadowed,3) + shiftTint(3),... 211 | 'sizedata',atomSizeTint,... 212 | 'marker','o',... 213 | 'markeredgecolor','none',... 214 | 'markerfacecolor',atomColorTint); 215 | end 216 | end 217 | 218 | 219 | 220 | hold off 221 | 222 | axis equal off 223 | 224 | 225 | % Camera stuff 226 | camtarget(cameraTarget) 227 | campos(cameraTarget + cameraPosition); 228 | camva(cameraAngle) 229 | camproj('perspective') 230 | 231 | 232 | 233 | 234 | end -------------------------------------------------------------------------------- /matlab/part_03_04_atoms/progressbar.m: -------------------------------------------------------------------------------- 1 | %this m-file modified by Quan Quach on 12/12/07 2 | %email: quan.quach@gmail.com 3 | %Original Author: Steve Hoelzer 4 | function [stopBar] = progressbar(fractiondone,position) 5 | 6 | if(~exist('fractiondone')) 7 | return 8 | end 9 | % Description: 10 | % progressbar(fractiondone,position) provides an indication of the progress of 11 | % some task using graphics and text. Calling progressbar repeatedly will update 12 | % the figure and automatically estimate the amount of time remaining. 13 | % This implementation of progressbar is intended to be extremely simple to use 14 | % while providing a high quality user experience. 15 | % 16 | % Features: 17 | % - Can add progressbar to existing m-files with a single line of code. 18 | % - The figure closes automatically when the task is complete. 19 | % - Only one progressbar can exist so old figures don't clutter the desktop. 20 | % - Remaining time estimate is accurate even if the figure gets closed. 21 | % - Minimal execution time. Won't slow down code. 22 | % - Random color and position options. When a programmer gets bored.... 23 | % 24 | % Usage: 25 | % fractiondone specifies what fraction (0.0 - 1.0) of the task is complete. 26 | % Typically, the figure will be updated according to that value. However, if 27 | % fractiondone == 0.0, a new figure is created (an existing figure would be 28 | % closed first). If fractiondone == 1.0, the progressbar figure will close. 29 | % position determines where the progressbar figure appears on screen. This 30 | % argument only has an effect when a progress bar is first created or is reset 31 | % by calling with fractiondone = 0. The progress bar's position can be specifed 32 | % as follows: 33 | % [x, y] - Position of lower left corner in normalized units (0.0 - 1.0) 34 | % 0 - Centered (Default) 35 | % 1 - Upper right 36 | % 2 - Upper left 37 | % 3 - Lower left 38 | % 4 - Lower right 39 | % 5 - Random [x, y] position 40 | % The color of the progressbar is choosen randomly when it is created or 41 | % reset. Clicking inside the figure will cause a random color change. 42 | % For best results, call progressbar(0) (or just progressbar) before starting 43 | % a task. This sets the proper starting time to calculate time remaining. 44 | % 45 | % Example Function Calls: 46 | % progressbar(fractiondone,position) 47 | % progressbar % Initialize/reset 48 | % progressbar(0) % Initialize/reset 49 | % progressbar(0,4) % Initialize/reset and specify position 50 | % progressbar(0,[0.2 0.7]) % Initialize/reset and specify position 51 | % progressbar(0.5) % Update 52 | % progressbar(1) % Close 53 | % 54 | % Demo: 55 | % n = 1000; 56 | % progressbar % Create figure and set starting time 57 | % for i = 1:n 58 | % pause(0.01) % Do something important 59 | % progressbar(i/n) % Update figure 60 | % end 61 | % 62 | % Author: Steve Hoelzer 63 | % 64 | % Revisions: 65 | % 2002-Feb-27 Created function 66 | % 2002-Mar-19 Updated title text order 67 | % 2002-Apr-11 Use floor instead of round for percentdone 68 | % 2002-Jun-06 Updated for speed using patch (Thanks to waitbar.m) 69 | % 2002-Jun-19 Choose random patch color when a new figure is created 70 | % 2002-Jun-24 Click on bar or axes to choose new random color 71 | % 2002-Jun-27 Calc time left, reset progress bar when fractiondone == 0 72 | % 2002-Jun-28 Remove extraText var, add position var 73 | % 2002-Jul-18 fractiondone input is optional 74 | % 2002-Jul-19 Allow position to specify screen coordinates 75 | % 2002-Jul-22 Clear vars used in color change callback routine 76 | % 2002-Jul-29 Position input is always specified in pixels 77 | % 2002-Sep-09 Change order of title bar text 78 | % 2003-Jun-13 Change 'min' to 'm' because of built in function 'min' 79 | % 2003-Sep-08 Use callback for changing color instead of string 80 | % 2003-Sep-10 Use persistent vars for speed, modify titlebarstr 81 | % 2003-Sep-25 Correct titlebarstr for 0% case 82 | % 2003-Nov-25 Clear all persistent vars when percentdone = 100 83 | % 2004-Jan-22 Cleaner reset process, don't create figure if percentdone = 100 84 | % 2004-Jan-27 Handle incorrect position input 85 | % 2004-Feb-16 Minimum time interval between updates 86 | % 2004-Apr-01 Cleaner process of enforcing minimum time interval 87 | % 2004-Oct-08 Seperate function for timeleftstr, expand to include days 88 | % 2004-Oct-20 Efficient if-else structure for sec2timestr 89 | % 90 | stopBar = 0; 91 | persistent progfig progpatch starttime lastupdate firstIteration 92 | 93 | % Set defaults for variables not passed in 94 | if nargin < 1 95 | fractiondone = 0; 96 | end 97 | if nargin < 2 98 | position = 0; 99 | end 100 | 101 | try 102 | % Access progfig to see if it exists ('try' will fail if it doesn't) 103 | dummy = get(progfig,'UserData'); 104 | % If progress bar needs to be reset, close figure and set handle to empty 105 | if fractiondone == 0 106 | delete(progfig) % Close progress bar 107 | progfig = []; % Set to empty so a new progress bar is created 108 | end 109 | catch 110 | progfig = []; % Set to empty so a new progress bar is created 111 | end 112 | 113 | 114 | percentdone = floor(100*fractiondone); 115 | 116 | % Create new progress bar if needed 117 | 118 | if (isempty(progfig) && (isempty(firstIteration))) 119 | firstIteration = 1; 120 | % Calculate position of progress bar in normalized units 121 | scrsz = [0 0 1 1]; 122 | width = scrsz(3)/4; 123 | height = scrsz(4)/50; 124 | if (length(position) == 1) 125 | hpad = scrsz(3)/64; % Padding from left or right edge of screen 126 | vpad = scrsz(4)/24; % Padding from top or bottom edge of screen 127 | left = scrsz(3)/2 - width/2; % Default 128 | bottom = scrsz(4)/2 - height/2; % Default 129 | switch position 130 | case 0 % Center 131 | % Do nothing (default) 132 | case 1 % Top-right 133 | left = scrsz(3) - width - hpad; 134 | bottom = scrsz(4) - height - vpad; 135 | case 2 % Top-left 136 | left = hpad; 137 | bottom = scrsz(4) - height - vpad; 138 | case 3 % Bottom-left 139 | left = hpad; 140 | bottom = vpad; 141 | case 4 % Bottom-right 142 | left = scrsz(3) - width - hpad; 143 | bottom = vpad; 144 | case 5 % Random 145 | left = rand * (scrsz(3)-width); 146 | bottom = rand * (scrsz(4)-height); 147 | otherwise 148 | warning('position must be (0-5). Reset to 0.') 149 | end 150 | position = [left bottom]; 151 | elseif length(position) == 2 152 | % Error checking on position 153 | if (position(1) < 0) || (scrsz(3)-width < position(1)) 154 | position(1) = max(min(position(1),scrsz(3)-width),0); 155 | warning('Horizontal position adjusted to fit on screen.') 156 | end 157 | if (position(2) < 0) || (scrsz(4)-height < position(2)) 158 | position(2) = max(min(position(2),scrsz(4)-height),0); 159 | warning('Vertical position adjusted to fit on screen.') 160 | end 161 | else 162 | error('position is not formatted correctly') 163 | end 164 | 165 | % Initialize progress bar 166 | progfig = figure(... 167 | 'Units', 'normalized',... 168 | 'Position', [position width height],... 169 | 'NumberTitle', 'off',... 170 | 'Resize', 'off',... 171 | 'MenuBar', 'none',... 172 | 'BackingStore', 'off' ); 173 | progaxes = axes(... 174 | 'Position', [0.02 0.15 0.96 0.70],... 175 | 'XLim', [0 1],... 176 | 'YLim', [0 1],... 177 | 'Box', 'on',... 178 | 'ytick', [],... 179 | 'xtick', [] ); 180 | progpatch = patch(... 181 | 'XData', [0 0 0 0],... 182 | 'YData', [0 0 1 1],... 183 | 'EraseMode', 'none' ); 184 | 185 | % enable this code if you want the bar to change colors when the 186 | % user clicks on the progress bar 187 | % set(progfig, 'ButtonDownFcn',{@changecolor,progpatch}); 188 | % set(progaxes, 'ButtonDownFcn',{@changecolor,progpatch}); 189 | % set(progpatch,'ButtonDownFcn',{@changecolor,progpatch}); 190 | % changecolor(0,0,progpatch) 191 | 192 | set(progpatch,'FaceColor',[.1 1 .1]); 193 | 194 | % Set time of last update to ensure a redraw 195 | lastupdate = clock - 1; 196 | 197 | % Task starting time reference 198 | if isempty(starttime) || (fractiondone == 0) 199 | starttime = clock; 200 | end 201 | 202 | set(progfig,'CloseRequestFcn',@closeBar); 203 | 204 | end 205 | 206 | %if the user closes the progress bar during the data processing 207 | %then this will erase all the variables are return 1 to the output 208 | if (isempty(progfig) && ~(fractiondone==0)) 209 | delete(progfig) % Close progress bar 210 | 211 | % Clear persistent vars 212 | clear progfig progpatch starttime lastupdate firstIteration 213 | stopBar = 1; 214 | return 215 | 216 | end 217 | 218 | 219 | %Enforce a minimum time interval between updates 220 | %but allows for the case when the bar reaches 100% so that the user can see 221 | %it 222 | if (etime(clock,lastupdate) < 0.01 && ~(percentdone == 100)) 223 | return 224 | end 225 | 226 | % Update progress patch 227 | set(progpatch,'XData',[0 fractiondone fractiondone 0]) 228 | 229 | % Update progress figure title bar 230 | if (fractiondone == 0) 231 | titlebarstr = ' 0%'; 232 | else 233 | runtime = etime(clock,starttime); 234 | timeleft = runtime/fractiondone - runtime; 235 | timeleftstr = sec2timestr(timeleft); 236 | titlebarstr = sprintf('%2d%% %s remaining',percentdone,timeleftstr); 237 | end 238 | set(progfig,'Name',titlebarstr) 239 | 240 | % Force redraw to show changes 241 | drawnow 242 | 243 | % If task completed, close figure and clear vars, then exit 244 | 245 | if percentdone == 100 % Task completed 246 | delete(progfig) % Close progress bar 247 | 248 | %change the close request function back to normal 249 | % set(progfig,'CloseRequestFcn','closereq'); 250 | % Clear persistent vars 251 | clear progfig progpatch starttime lastupdate firstIteration 252 | return 253 | end 254 | % Record time of this update 255 | lastupdate = clock; 256 | 257 | %% 258 | % ------------------------------------------------------------------------------ 259 | function changecolor(h,e,progpatch) 260 | Change the color of the progress bar patch 261 | 262 | colorlim = 2.8; % Must be <= 3.0 - This keeps the color from being too light 263 | thiscolor = rand(1,3); 264 | while sum(thiscolor) > colorlim 265 | thiscolor = rand(1,3); 266 | end 267 | set(progpatch,'FaceColor',thiscolor); 268 | 269 | 270 | 271 | %% 272 | % ------------------------------------------------------------------------------ 273 | function timestr = sec2timestr(sec) 274 | % Convert a time measurement from seconds into a human readable string. 275 | 276 | % Convert seconds to other units 277 | d = floor(sec/86400); % Days 278 | sec = sec - d*86400; 279 | h = floor(sec/3600); % Hours 280 | sec = sec - h*3600; 281 | m = floor(sec/60); % Minutes 282 | sec = sec - m*60; 283 | s = floor(sec); % Seconds 284 | 285 | % Create time string 286 | if d > 0 287 | if d > 9 288 | timestr = sprintf('%d day',d); 289 | else 290 | timestr = sprintf('%d day, %d hr',d,h); 291 | end 292 | elseif h > 0 293 | if h > 9 294 | timestr = sprintf('%d hr',h); 295 | else 296 | timestr = sprintf('%d hr, %d min',h,m); 297 | end 298 | elseif m > 0 299 | if m > 9 300 | timestr = sprintf('%d min',m); 301 | else 302 | timestr = sprintf('%d min, %d sec',m,s); 303 | end 304 | else 305 | timestr = sprintf('%d sec',s); 306 | end 307 | 308 | %% 309 | function closeBar(src,evnt) 310 | 311 | selection = questdlg('Do you wish to cancel this process?',... 312 | 'Stop process',... 313 | 'Yes','No','Yes'); 314 | switch selection, 315 | case 'Yes', 316 | delete(gcf) 317 | case 'No' 318 | return 319 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/DPC01.m: -------------------------------------------------------------------------------- 1 | function [sDPC] = DPC01() 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - DPC plot / movies 5 | 6 | % simulate a CoM DPC reconstruction as a 1D slice 7 | 8 | sDPC.pixelSize = 1; 9 | sDPC.imageSize = [1 1]*512*1; 10 | 11 | % Coordinates 12 | [sDPC.qxa,sDPC.qya] = makeFourierCoords(sDPC.imageSize,sDPC.pixelSize); 13 | 14 | 15 | 16 | % Generate atomic potential 17 | x = (1:sDPC.imageSize(1))'; 18 | 19 | p = zeros(sDPC.imageSize(1),1); 20 | 21 | numPeaks = 20; 22 | t = linspace(0,1,numPeaks); 23 | % xp = sDPC.imageSize(1)*0.34 + t*sDPC.imageSize(1)*0.6; 24 | % Ip = t*pi; 25 | % sigma = sDPC.imageSize(1)*0.009; 26 | xp = sDPC.imageSize(1)*0.25 + t*sDPC.imageSize(1)*0.5; 27 | Ip = sqrt(1-(1-2*t).^2)*pi; 28 | sigma = sDPC.imageSize(1)*0.008; 29 | 30 | % sigma = sDPC.imageSize(1)*0.002; 31 | 32 | 33 | for a0 = 1:length(t) 34 | p(:) = p + ... 35 | Ip(a0)*exp(-(x-xp(a0)).^2/(2*sigma^2)); 36 | end 37 | sDPC.x = x; 38 | sDPC.p = p; 39 | sDPC.pot = repmat(p,[1 sDPC.imageSize(2)]); 40 | 41 | 42 | 43 | figure(11) 44 | clf 45 | plot(x,p,'linewidth',2,'color','r') 46 | 47 | 48 | 49 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/DPC02.m: -------------------------------------------------------------------------------- 1 | function [sDPC] = DPC02(sDPC,fbase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - DPC plot / movies 5 | 6 | flagPlot = 1; 7 | 8 | % convergence semiangle - from 0.02 to 0.32 roughly 9 | sDPC.qProbeMax = 0.16; 10 | 11 | 12 | sDPC.probeRange = sDPC.imageSize(1) * [0 1]; 13 | sDPC.numProbes = 60*4*4 / 4; 14 | % vecInds = 480+8; 15 | vecInds = 1:sDPC.numProbes; 16 | 17 | % sDPC.qProbeMax = 0.32; 18 | % sDPC.qProbeMax = 0.16; 19 | % sDPC.qProbeMax = 0.06; 20 | % sDPC.qProbeMax = 0.02; 21 | 22 | yR1 = [0 pi]*1.1; 23 | xCut = 512; 24 | yCut = 182; 25 | 26 | sDPC.sigmaPot = 1; 27 | sigCountsTotal = 500*0;%1e3; 28 | 29 | 30 | intRangeFFT = [0.0 1.1]; 31 | intPowerFFT = 1; 32 | intRange = [0 0.004]; 33 | intPower = 1; 34 | 35 | 36 | % scaling 37 | intRange = intRange / (0.06 / sDPC.qProbeMax)^2; 38 | 39 | % Probes 40 | sDPC.xp = linspace(sDPC.probeRange(1),sDPC.probeRange(2),sDPC.numProbes+1); 41 | sDPC.xp(end) = []; 42 | 43 | % Potentials 44 | trans = exp((1i*sDPC.sigmaPot)*sDPC.pot); 45 | 46 | 47 | % Generate initial probe 48 | sDPC.q2 = sDPC.qxa.^2 + sDPC.qya.^2; 49 | sDPC.q1 = sqrt(sDPC.q2); 50 | dq = sDPC.qxa(2,1); 51 | sDPC.psi0 = min(max((sDPC.qProbeMax - sDPC.q1)/dq+0.5,0),1); 52 | 53 | % signal counts 54 | sigCounts = sigCountsTotal / sum(abs(sDPC.psi0(:).^2)); 55 | 56 | 57 | % Coords 58 | xc = [(1:(xCut/2)) ((1-xCut/2):0)+sDPC.imageSize(1)]; 59 | yc = [(1:(yCut/2)) ((1-yCut/2):0)+sDPC.imageSize(2)]; 60 | 61 | 62 | 63 | % Main 64 | % Psi0 = fft2(sDPC.psi0); 65 | psi0 = zeros(sDPC.imageSize); 66 | psi = zeros(sDPC.imageSize); 67 | Psi = zeros(sDPC.imageSize); 68 | 69 | % Main loop 70 | 71 | sDPC.CoM = zeros(sDPC.numProbes,2); 72 | 73 | for a0 = vecInds 74 | xx = sDPC.xp(a0); 75 | 76 | 77 | qShift = exp((-2i*pi*xx)*sDPC.qxa); 78 | psi0(:) = ifft2(sDPC.psi0 .* qShift); 79 | psi(:) = psi0 .* trans; 80 | Psi(:) = fft2(psi); 81 | 82 | PsiInt = abs(Psi).^2; 83 | if sigCounts > 0 84 | PsiInt(:) = poissrnd(PsiInt*sigCounts)/sigCounts; 85 | end 86 | xCoM = sum(PsiInt(:).*sDPC.qxa(:)) / sum(PsiInt(:)); 87 | sDPC.CoM(a0,:) = [sDPC.xp(a0) xCoM]; 88 | 89 | if flagPlot == true 90 | P = exp(1i*pi) * Psi ./ qShift; 91 | Pc = fftshift(P(xc,yc)); 92 | 93 | p = psi(:,1); 94 | pamp = abs(p).*intPower; 95 | prgb = colorComplex(ones(size(pamp)),angle(p),[0 1]); 96 | pamp(:) = (pamp - intRange(1).^intPower) ... 97 | / (intRange(2).^intPower - intRange(1).^intPower); 98 | pamp(:) = min(max(pamp,0),pi); 99 | 100 | if sigCounts > 0 101 | Pint = abs(Pc).^2; 102 | Pint(:) = poissrnd(Pint*sigCounts)/sigCounts; 103 | Pc(:) = sqrt(Pint).*exp(1i*angle(Pc)); 104 | end 105 | 106 | Igray = abs(Pc).^intPowerFFT; 107 | Igray(:) = (Igray - intRangeFFT(1).^intPowerFFT) ... 108 | / (intRangeFFT(2).^intPowerFFT - intRangeFFT(1).^intPowerFFT); 109 | Igray = repmat(Igray,[1 1 3]); 110 | Irgb = colorComplex(abs(Pc).^intPowerFFT,... 111 | angle(Pc),intRangeFFT.^intPowerFFT); 112 | 113 | 114 | figure(11) 115 | clf 116 | set(gcf,'color','w') 117 | % set(gcf,... 118 | % 'outerposition',[1000 500-256 576 512+256],... 119 | % 'color','w') 120 | 121 | b = [0.01 0.004]; 122 | axes('position',[0+b(1) 0.6+b(2) 1-2*b(1) 0.4-2*b(2)]) 123 | % plot(sDPC.x,sDPC.p,'linewidth',2,'color','k') 124 | area(sDPC.x(:),... 125 | sDPC.p(:),... 126 | 'linewidth',2,... 127 | 'facecolor',[1 1 1]*0.6,'edgecolor','none') 128 | hold on 129 | % area(sDPC.x,pamp,'linewidth',2,... 130 | % 'facecolor',prgb,'edgecolor','none') 131 | % % patch([sDPC.x(:); sDPC.x(end); sDPC.x(1)],... 132 | % % [pamp(:); 0; 0],'r',... 133 | % % 'facecolor','interp',... 134 | % % 'facevertexcdata',... 135 | % % [squeeze(prgb); 0 0 0; 0 0 0]) 136 | % xp = [sDPC.x(:); flipud(sDPC.x(:))]; 137 | % yp = [pamp(:); pamp(:)*0]; 138 | v = [sDPC.x(:) pamp(:);sDPC.x(:) pamp(:)*0]; 139 | Nv = size(v,1)/2; 140 | f = [(1:Nv-1)' (1:Nv-1)'+1 ... 141 | (1:Nv-1)'+1+Nv (1:Nv-1)'+Nv]; 142 | patch('vertices',v,'faces',f,... 143 | 'facecolor','interp',... 144 | 'edgecolor','none',... 145 | 'cdata',repmat(prgb,[1 2 1])) 146 | 147 | hold off 148 | 149 | box on 150 | set(gca,'xtick',[],'ytick',[]) 151 | xlim(sDPC.x([1 end])) 152 | ylim(yR1) 153 | 154 | 155 | axes('position',[0+b(1) 0.3+b(2) 1-2*b(1) 0.3-2*b(2)]) 156 | imagesc(permute(Igray,[2 1 3])) 157 | hold on 158 | xx = xCoM*sDPC.imageSize(1); 159 | plot([0 0]+xx+sDPC.imageSize(1)/2+1,... 160 | [1 yCut],... 161 | 'linewidth',1,'color',[0 0.8 0]) 162 | 163 | hold off 164 | axis equal off 165 | 166 | 167 | axes('position',[0+b(1) 0.0+b(2) 1-2*b(1) 0.3-2*b(2)]) 168 | imagesc(permute(Irgb,[2 1 3])) 169 | axis equal off 170 | 171 | drawnow 172 | 173 | if nargin > 1 174 | fname = [fbase sprintf('%04d',a0) '.png']; 175 | eval(['export_fig -nocrop -r101 ' fname]); 176 | end 177 | 178 | % % Ip = abs(Psi).^intPowerFFT; 179 | % P = fftshift(exp(1i*pi) * Psi ./ qShift); 180 | % Irgb = colorComplex(abs(P).^intPowerFFT,... 181 | % angle(P),intRangeFFT.^intPowerFFT); 182 | % imagesc(Irgb) 183 | % %imagesc(fftshift(Ip.^intPowerFFT)); 184 | % % imagesc([abs(psi0) abs(psi)]) 185 | % % imagesc(fftshift(sDPC.psi0)) 186 | % axis equal off 187 | % drawnow 188 | % %colormap(gray(256)) 189 | % % caxis(intRangeFFT.^intPowerFFT) 190 | 191 | 192 | else 193 | if length(vecInds) > 1 194 | comp = a0 / sDPC.numProbes; 195 | progressbar(comp,2); 196 | end 197 | end 198 | 199 | 200 | 201 | end 202 | 203 | 204 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/animFEM01.m: -------------------------------------------------------------------------------- 1 | function [] = animFEM01(probeSites,rScale) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Animation to show interaction of STEM probe with a 5 | % sample that ranges from fully ordered on the left 6 | % side, to fully disordered on the right side. 7 | % 01 - This script renders the scene. 8 | 9 | rng(1+2); 10 | 11 | skip = 1; 12 | flagScatter = 1; 13 | 14 | padding = 50; 15 | imageSizeOutput = [200 200]; 16 | numAtoms = [10 50 10]; 17 | pixelSize = 0.05; 18 | sigmaAtoms = 4; 19 | 20 | linewidthProbes = 1.5; 21 | probeRadius = 0.3 + 0.05; 22 | % probeSites = [ ... 23 | % 5 05; 24 | % 5 15; 25 | % 5 25; 26 | % 5 35; 27 | % 5 45]; 28 | % probeWeights = [1.0 0.75 0.50 0.25 0]; 29 | probeRep = 3; 30 | 31 | % appearance 32 | mSize = 50; 33 | lw = 1; 34 | radius = 0.48 + 0.04; 35 | % radius = 4; 36 | 37 | 38 | probePos = [20 0 -20]*1.2 + 5; 39 | probeImageScale = 10 + 5; 40 | 41 | % Camera 42 | cellDim = numAtoms + 0; 43 | cTar = [0 0 0] + cellDim * 0.5 + [0 -0.6 0]; 44 | cPos = [-3 0 1.5]*36; 45 | cAngle = 20 + 1; 46 | 47 | 48 | % Atomic sites 49 | [yp,xp,zp] = meshgrid(1:numAtoms(2),1:numAtoms(1),1:numAtoms(3)); 50 | p = [xp(:) yp(:) zp(:)]; 51 | for a0 = 1:size(p,1) 52 | if nargin == 1 53 | r = (numAtoms(2) - p(a0,2)).^1.5*0.0015; 54 | else 55 | r = (numAtoms(2) - p(a0,2)).^1.5*rScale; 56 | end 57 | dxy = randn(1,2) * r; 58 | p(a0,1:2) = p(a0,1:2) + dxy; 59 | end 60 | 61 | 62 | % Potential image 63 | k = fspecial('gaussian',2*ceil(4*sigmaAtoms)+1,sigmaAtoms); 64 | imageSize = round(cellDim(1:2) ./ pixelSize); 65 | xInd = (p(:,1) - 0.5) / pixelSize; 66 | yInd = (p(:,2) - 0.5) / pixelSize; 67 | xInd = min(max(round(xInd),1),imageSize(1)); 68 | yInd = min(max(round(yInd),1),imageSize(2)); 69 | imagePot = accumarray([xInd yInd],... 70 | ones(length(xInd),1),imageSize); 71 | imagePot(:) = conv2(imagePot,k,'same'); 72 | 73 | 74 | % Image coordinates 75 | x = linspace(-probeImageScale/2,probeImageScale/2,imageSizeOutput(1)); 76 | y = linspace(-probeImageScale/2,probeImageScale/2,imageSizeOutput(2)); 77 | [yi,xi] = meshgrid(y-mean(y),x-mean(x)); 78 | 79 | 80 | % Other image stuff 81 | w2 = hanning(imageSizeOutput(1)) * hanning(imageSizeOutput(2))'; 82 | xx = linspace(-1,1,imageSizeOutput(1)); 83 | yy = linspace(-1,1,imageSizeOutput(2)); 84 | [ya,xa] = meshgrid(yy,xx); 85 | ra2 = xa.^2 + ya.^2; 86 | ra = sqrt(ra2); 87 | kDisk = fspecial('disk',2); 88 | wa = 1 ... 89 | + 10*ra.*exp(-(ra - 0.35).^2/(2*0.07^2)) ... 90 | + 12*ra.*exp(-(ra - 0.70).^2/(2*0.09^2)) ... 91 | + 40*ra.*exp(-(ra - 1.05).^2/(2*0.13^2)); 92 | % wa(:) = wa * 1.2; 93 | wa(:) = wa * 0.8; 94 | 95 | % Sphere 96 | [xs,ys,zs] = sphere(8); 97 | xs = xs * radius; 98 | ys = ys * radius; 99 | zs = zs * radius; 100 | 101 | % Plotting 102 | h = figure(1); 103 | clf 104 | set(h,'color','w') 105 | % set(h,'color',[1 1 1],'outerposition',[1020 380-120 576 512+128]) 106 | % set(h,'color',[1 1 1],'outerposition',[1020 260 576-2 640+10]) 107 | hold on 108 | % sub = p(:,1) < 1.5 - 100*1; 109 | if flagScatter == true 110 | % scatter3(p(sub,2),p(sub,1),p(sub,3),... 111 | % 'marker','o','sizedata',mSize,'linewidth',lw,... 112 | % 'markerfacecolor',[1 0.7 0.7],'markeredgecolor',[1 0 0]) 113 | % 114 | % scatter3(p(~sub,2),p(~sub,1),p(~sub,3),... 115 | % 'marker','o','sizedata',mSize,'linewidth',lw,... 116 | % 'markerfacecolor',[1 0.9 0.9],'markeredgecolor',[1 0.5 0.5]) 117 | 118 | % scatter3(p(sub,2),p(sub,1),p(sub,3),... 119 | % 'marker','o','sizedata',mSize,'linewidth',lw,... 120 | % 'markerfacecolor',[1 0 0],'markeredgecolor',[0 0 0]) 121 | 122 | scatter3(p(:,2),p(:,1),p(:,3),... 123 | 'marker','o','sizedata',mSize,'linewidth',lw,... 124 | 'markerfacecolor',[1 0 0],'markeredgecolor',[0 0 0]) 125 | 126 | d = cPos; 127 | d = d / norm(d) * 0.05 + [0 -0.1 0.1]; 128 | scatter3(p(:,2)+d(1),p(:,1)+d(2),p(:,3)+d(3),... 129 | 'marker','o','sizedata',10,'linewidth',lw,... 130 | 'markerfacecolor',[1 0.7 0.7],'markeredgecolor','none') 131 | 132 | d = cPos; 133 | d = d / norm(d) * 0.1 + [0 -0.1 0.1]; 134 | scatter3(p(:,2)+d(1),p(:,1)+d(2),p(:,3)+d(3),... 135 | 'marker','o','sizedata',3,'linewidth',lw,... 136 | 'markerfacecolor',[1 0.9 0.9],'markeredgecolor','none') 137 | else 138 | Np = size(p,1); 139 | for a0 = 1:skip:Np 140 | xyz = p(a0,:); 141 | c2 = [0.3 0 0]; 142 | surf(xs+xyz(2),ys+xyz(1),zs+xyz(3),... 143 | 'edgecolor','none','facecolor',c2) 144 | end 145 | end 146 | 147 | 148 | % Probes coords 149 | t = linspace(0,2*pi,180+1); 150 | ct = cos(t); 151 | st = sin(t); 152 | Nprobes = size(probeSites,1); 153 | xVec = [(1:(imageSizeOutput(1)/2)) ... 154 | ((1-imageSizeOutput(1)/2):0) + imageSizeOutput(1)*probeRep]; 155 | yVec = [(1:(imageSizeOutput(2)/2)) ... 156 | ((1-imageSizeOutput(2)/2):0) + imageSizeOutput(2)*probeRep]; 157 | 158 | 159 | for a0 = 1:Nprobes 160 | line([-1 1]*probeRadius+probeSites(a0,2),... 161 | [0 0]+probeSites(a0,1),... 162 | probePos([1 3]),... 163 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 164 | line([1 -1]*probeRadius+probeSites(a0,2),... 165 | [0 0]+probeSites(a0,1),... 166 | probePos([1 3]),... 167 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 168 | line(ct*probeRadius+probeSites(a0,2),... 169 | st*probeRadius+probeSites(a0,1),... 170 | probePos(3)+ct*0,... 171 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 172 | 173 | xInds = mod((1:imageSizeOutput(1)) ... 174 | - imageSizeOutput(1)/2 ... 175 | + probeSites(a0,1)/pixelSize-1, imageSize(1))+1; 176 | yInds = mod((1:imageSizeOutput(2)) ... 177 | - imageSizeOutput(2)/2 ... 178 | + probeSites(a0,2)/pixelSize-1, imageSize(2))+1; 179 | % imageCut = imagePot(xInds,yInds); 180 | imageCut = imagePot(round(xInds),round(yInds)); 181 | 182 | 183 | imageCut = fft2(repmat(imageCut .* w2,[1 1]*probeRep)); 184 | imageCut = imageCut(xVec,yVec); 185 | imageCut = fftshift(abs(imageCut)); 186 | imageCut(:) = conv2(imageCut,kDisk,'same'); 187 | % imageCut(:) = (imageCut).^0.667 ... 188 | % .* (wa * probeWeights(a0) + (1-probeWeights(a0))); 189 | probeWeightScan = (probeSites(2) - 5) / 40; 190 | probeWeightScan = 1 - 0.5*min(max(probeWeightScan,0),1); 191 | imageCut(:) = 2*(imageCut).^0.5 ... 192 | .* (wa * probeWeightScan + (1-probeWeightScan)); 193 | 194 | imageCut(:) = imageCut * 0.06; 195 | imageCut(:) = min(max(imageCut,0),1); 196 | % imageCut(:) = 1 -imageCut; 197 | imagePad = padarray(imageCut,[1 1]*padding/2,0,'both'); 198 | 199 | warp(yi+probeSites(a0,2),... 200 | xi+probeSites(a0,1),... 201 | xi*0+probePos(3),... 202 | imagePad) 203 | end 204 | 205 | hold off 206 | axis equal off 207 | caxis([0 1]) 208 | set(gca,'ydir','reverse') 209 | 210 | 211 | % camlight left 212 | % light('style','infinite','position',[1 -6 1+1]*1e3) 213 | % light('style','infinite','position',[0 -6 -1+1]*1e3) 214 | % lighting phong 215 | % material shiny 216 | 217 | camva(cAngle) 218 | camproj('perspective') 219 | camtarget(cTar([2 1 3])) 220 | campos(cPos([2 1 3])+cTar([2 1 3])) 221 | 222 | % toc 223 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/animFEM02.m: -------------------------------------------------------------------------------- 1 | function [] = animFEM02(fbase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Animation to show interaction of STEM probe with a 5 | % sample that ranges from fully ordered on the left 6 | % side, to fully disordered on the right side. 7 | % 02 - This script calls 01, and animates the ordered --> disordered 8 | % transformation of the sample. 9 | 10 | 11 | % Ordering animation 12 | Nc = 60; 13 | probeSites = [5 45]; 14 | rScaleArray = linspace(0,1,Nc) * 0.0015; 15 | 16 | for a0 = 1:length(rScaleArray) 17 | rScale = rScaleArray(a0); 18 | 19 | animFEM01(probeSites,rScale); 20 | 21 | if nargin > 0 22 | fname = [fbase sprintf('%04d',a0) '.png']; 23 | eval(['export_fig -nocrop -r110 ' fname]); 24 | else 25 | drawnow; 26 | end 27 | end 28 | 29 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/animFEM03.m: -------------------------------------------------------------------------------- 1 | function [] = animFEM03(fbase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Animation to show interaction of STEM probe with a 5 | % sample that ranges from fully ordered on the left 6 | % side, to fully disordered on the right side. 7 | % 03 - This script calls 01, animates STEM probe motion. 8 | 9 | 10 | % Ordering animation 11 | Nc = 120; 12 | v = linspace(45,5,Nc+1)'; 13 | probeSitesArray = [ ... 14 | [ones(Nc,1)*5 v(1:(end-1))]; 15 | [ones(Nc,1)*5 flipud(v(2:end))] 16 | ]; 17 | rScale = 0.0015; 18 | 19 | for a0 = 1:size(probeSitesArray,1) 20 | probeSites = probeSitesArray(a0,:); 21 | animFEM01(probeSites,rScale); 22 | 23 | if nargin > 0 24 | fname = [fbase sprintf('%04d',a0) '.png']; 25 | eval(['export_fig -nocrop -r110 ' fname]); 26 | else 27 | drawnow; 28 | end 29 | end 30 | 31 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/animOrient01.m: -------------------------------------------------------------------------------- 1 | function [] = animOrient01(probeSites) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Animation to show interaction of STEM probe with a 5 | % crystalline sample, consisting of three grains 6 | % with different orientations. 7 | % 01 - This script renders the scene. 8 | 9 | rng(1); % set random see for repeatable behaviour 10 | 11 | skip = 1; 12 | flagScatter = 1; 13 | 14 | imageSizeOutput = [200 200]; 15 | numAtoms = [10 50 10]; 16 | pixelSize = 0.05; 17 | sigmaAtoms = 4; 18 | 19 | linewidthProbes = 1.5;%1.2 - 0.3; 20 | probeRadius = 0.7; 21 | if nargin == 0 22 | probeSites = [ ... 23 | 5 05; 24 | ... % 5 15; 25 | 5 25; 26 | ... % 5 35; 27 | 5 45]; 28 | end 29 | % probeWeights = [1.0 0.75 0.50 0.25 0]; 30 | probeRep = 3; 31 | 32 | % appearance 33 | mSize = 50;% * 4; 34 | mSizeTint = 10;%*1.5; 35 | lw = 1; 36 | radius = 0.48 + 0.04; 37 | % radius = 0.36; 38 | 39 | probePos = [20 0 -20]*1.2 + 5; 40 | probeImageScale = 15; 41 | 42 | % Camera 43 | cellDim = numAtoms + 0; 44 | cTar = [0 0 0] + cellDim * 0.5 + [0 -0.6 0]; 45 | cPos = [-3 0 1.5]*36; 46 | cAngle = 20 + 1; 47 | % % More dramatic camera angles 48 | % cellDim = numAtoms + 0; 49 | % cTar = [0 0 0] + cellDim * 0.5 + [10 5 -15]; 50 | % cPos = [-2.25 1.75 0]*13; 51 | % cAngle = 75; 52 | 53 | 54 | % Atomic sites 55 | numAtomsMax = max(numAtoms); 56 | v = -round(numAtomsMax/2):round(numAtomsMax/2); 57 | [yy,xx,zz] = meshgrid(v,v,v); 58 | p0 = [xx(:) yy(:) zz(:)]; 59 | Np = size(p0,1); 60 | 61 | p1 = p0; 62 | p2 = p0; 63 | p3 = p0; 64 | 65 | t = [45 54 -18.43]*pi/180; 66 | m1 = [cos(t(1)) -sin(t(1)) 0; 67 | sin(t(1)) cos(t(1)) 0; 68 | 0 0 1]; 69 | m2 = [1 0 0; 70 | 0 cos(t(2)) -sin(t(2)); 71 | 0 sin(t(2)) cos(t(2))]; 72 | m3 = [cos(t(3)) -sin(t(3)) 0; 73 | sin(t(3)) cos(t(3)) 0; 74 | 0 0 1]; 75 | p2 = p2 * m1 * m2 * m3; 76 | 77 | 78 | % t = [32 47 -70]*pi/180; 79 | t = [64 45+4-1 -70]*pi/180; 80 | m1 = [cos(t(1)) -sin(t(1)) 0; 81 | sin(t(1)) cos(t(1)) 0; 82 | 0 0 1]; 83 | m2 = [1 0 0; 84 | 0 cos(t(2)) -sin(t(2)); 85 | 0 sin(t(2)) cos(t(2))]; 86 | m3 = [cos(t(3)) -sin(t(3)) 0; 87 | sin(t(3)) cos(t(3)) 0; 88 | 0 0 1]; 89 | p1 = p1 * m1 * m2 * m3; 90 | 91 | 92 | 93 | p1 = p1 + repmat([0 0 0],[Np 1]); 94 | p2 = p2 + repmat([0 20 0],[Np 1]); 95 | p3 = p3 + repmat([0 40 0],[Np 1]); 96 | 97 | % abcd12 = [0.2 1 1.2 22]; 98 | % abcd23 = [0.8 1 -0.6 37]; 99 | 100 | 101 | abcd12 = [0.2 1 1.2 / 2 22]; 102 | abcd23 = [0.8 1 -0.6 / 2 37]; 103 | 104 | del = p1(:,1) < 1 | p1(:,1) > cellDim(1) ... 105 | | p1(:,2) < 1 | p1(:,2) > cellDim(2) ... 106 | | p1(:,3) < 1 | p1(:,3) > cellDim(3) ... 107 | | p1(:,1)*abcd12(1) + p1(:,2)*abcd12(2) + p1(:,3)*abcd12(3) > abcd12(4) - 0.1; 108 | p1(del,:) = []; 109 | 110 | del = p2(:,1) < 1 | p2(:,1) > cellDim(1) ... 111 | | p2(:,2) < 1 | p2(:,2) > cellDim(2) ... 112 | | p2(:,3) < 1 | p2(:,3) > cellDim(3) ... 113 | | p2(:,1)*abcd12(1) + p2(:,2)*abcd12(2) + p2(:,3)*abcd12(3) < abcd12(4) + 0.1 ... 114 | | p2(:,1)*abcd23(1) + p2(:,2)*abcd23(2) + p2(:,3)*abcd23(3) > abcd23(4) - 0.1; 115 | p2(del,:) = []; 116 | 117 | del = p3(:,1) < 1 | p3(:,1) > cellDim(1) ... 118 | | p3(:,2) < 1 | p3(:,2) > cellDim(2) ... 119 | | p3(:,3) < 1 | p3(:,3) > cellDim(3) ... 120 | | p3(:,1)*abcd23(1) + p3(:,2)*abcd23(2) + p3(:,3)*abcd23(3) < abcd23(4) + 0.1; 121 | p3(del,:) = []; 122 | 123 | 124 | p = [p1;p2; p3]; 125 | % p = p1; 126 | % [yp,xp,zp] = meshgrid(1:numAtoms(2),1:numAtoms(1),1:numAtoms(3)); 127 | % p = [xp(:) yp(:) zp(:)]; 128 | % p = [1 1 1]; 129 | 130 | 131 | % Potential image 132 | k = fspecial('gaussian',2*ceil(4*sigmaAtoms)+1,sigmaAtoms); 133 | imageSize = round(cellDim(1:2) ./ pixelSize); 134 | xInd = (p(:,1) - 0.5) / pixelSize; 135 | yInd = (p(:,2) - 0.5) / pixelSize; 136 | xInd = min(max(round(xInd),1),imageSize(1)); 137 | yInd = min(max(round(yInd),1),imageSize(2)); 138 | imagePot = accumarray([xInd yInd],... 139 | ones(length(xInd),1),imageSize); 140 | imagePot(:) = conv2(imagePot,k,'same'); 141 | 142 | % Image coordinates 143 | x = linspace(-probeImageScale/2,probeImageScale/2,imageSizeOutput(1)); 144 | y = linspace(-probeImageScale/2,probeImageScale/2,imageSizeOutput(2)); 145 | [yi,xi] = meshgrid(y-mean(y),x-mean(x)); 146 | 147 | 148 | % Make probes 149 | [qxa,qya] = makeFourierCoords(imageSize,1); 150 | q2 = qxa.^2 + qya.^2; 151 | qMask = q2 < 0.25^2; 152 | 153 | 154 | % Other image stuff 155 | % w2 = hanning(imageSizeOutput(1)) * hanning(imageSizeOutput(2))'; 156 | w2 = tukeywinMake(imageSizeOutput); 157 | % xx = 1:imageSizeOutput(1); 158 | % yy = 1:imageSizeOutput(2); 159 | % [ya,xa] = meshgrid( 160 | xx = linspace(-1,1,imageSizeOutput(1)); 161 | yy = linspace(-1,1,imageSizeOutput(2)); 162 | [ya,xa] = meshgrid(yy,xx); 163 | ra2 = xa.^2 + ya.^2; 164 | ra = sqrt(ra2); 165 | % wa = max(1 - ra,0); 166 | % wa = exp(-ra2); 167 | kDisk = fspecial('disk',8-2); 168 | wa = 1 ... 169 | + 10*ra.*exp(-(ra - 0.35).^2/(2*0.07^2)) ... 170 | + 12*ra.*exp(-(ra - 0.70).^2/(2*0.09^2)) ... 171 | + 40*ra.*exp(-(ra - 1.05).^2/(2*0.13^2)); 172 | 173 | % Sphere 174 | [xs,ys,zs] = sphere(8); 175 | xs = xs * radius; 176 | ys = ys * radius; 177 | zs = zs * radius; 178 | 179 | 180 | 181 | % Plotting 182 | h = figure(1); 183 | clf 184 | set(h,'color','w') 185 | % set(h,'color','w','outerposition',[1020 380-120 576 512+128]) 186 | % set(h,'color','w','outerposition',[100 100 576+576 512+512]) 187 | hold on 188 | % sub = p(:,1) < 1.5 - 100*1; 189 | % Np = size(p,1); 190 | if flagScatter == true 191 | scatter3(p3(:,2),p3(:,1),p3(:,3),... 192 | 'marker','o','sizedata',mSize,'linewidth',lw,... 193 | 'markeredgecolor',[1 0.7 0.7]*0,'markerfacecolor',[1 0 0]) 194 | scatter3(p2(:,2),p2(:,1),p2(:,3),... 195 | 'marker','o','sizedata',mSize,'linewidth',lw,... 196 | 'markeredgecolor',[0.8 1 0.8]*0,'markerfacecolor',[0 0.8 0]) 197 | scatter3(p1(:,2),p1(:,1),p1(:,3),... 198 | 'marker','o','sizedata',mSize,'linewidth',lw,... 199 | 'markeredgecolor',[1.0 0.5 1]*0,'markerfacecolor',[1 0 1]) 200 | 201 | 202 | d = cPos; 203 | d = d / norm(d) * 0.05 + [0 -0.1 0.1]; 204 | 205 | scatter3(p1(:,2)+d(1),p1(:,1)+d(2),p1(:,3)+d(3),... 206 | 'marker','o','sizedata',mSizeTint,'linewidth',lw,... 207 | 'markerfacecolor',[1 0.8 1],'markeredgecolor','none') 208 | scatter3(p2(:,2)+d(1),p2(:,1)+d(2),p2(:,3)+d(3),... 209 | 'marker','o','sizedata',mSizeTint,'linewidth',lw,... 210 | 'markerfacecolor',[0.8 1 0.8],'markeredgecolor','none') 211 | scatter3(p3(:,2)+d(1),p3(:,1)+d(2),p3(:,3)+d(3),... 212 | 'marker','o','sizedata',mSizeTint,'linewidth',lw,... 213 | 'markerfacecolor',[1 0.9 0.9],'markeredgecolor','none') 214 | 215 | 216 | else 217 | c = [0 0.4 0.6]; 218 | for a0 = 1:skip:size(p1,1) 219 | xyz = p1(a0,:); 220 | surf(xs+xyz(2),ys+xyz(1),zs+xyz(3),... 221 | 'edgecolor','none','facecolor',c) 222 | end 223 | 224 | c = [0 0.3 0]; 225 | for a0 = 1:skip:size(p2,1) 226 | xyz = p2(a0,:); 227 | surf(xs+xyz(2),ys+xyz(1),zs+xyz(3),... 228 | 'edgecolor','none','facecolor',c) 229 | end 230 | 231 | c = [0.3 0 0]; 232 | for a0 = 1:skip:size(p3,1) 233 | xyz = p3(a0,:); 234 | surf(xs+xyz(2),ys+xyz(1),zs+xyz(3),... 235 | 'edgecolor','none','facecolor',c) 236 | end 237 | end 238 | 239 | 240 | % Probes coords 241 | t = linspace(0,2*pi,180+1); 242 | ct = cos(t); 243 | st = sin(t); 244 | Nprobes = size(probeSites,1); 245 | xVec = [(1:(imageSizeOutput(1)/2)) ... 246 | ((1-imageSizeOutput(1)/2):0) + imageSizeOutput(1)*probeRep]; 247 | yVec = [(1:(imageSizeOutput(2)/2)) ... 248 | ((1-imageSizeOutput(2)/2):0) + imageSizeOutput(2)*probeRep]; 249 | 250 | 251 | for a0 = 1:Nprobes 252 | line([-1 1]*probeRadius+probeSites(a0,2),... 253 | [0 0]+probeSites(a0,1),... 254 | probePos([1 3]),... 255 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 256 | line([1 -1]*probeRadius+probeSites(a0,2),... 257 | [0 0]+probeSites(a0,1),... 258 | probePos([1 3]),... 259 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 260 | line(ct*probeRadius+probeSites(a0,2),... 261 | st*probeRadius+probeSites(a0,1),... 262 | probePos(3)+ct*0,... 263 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 264 | 265 | xInds = mod((1:imageSizeOutput(1)) ... 266 | - imageSizeOutput(1)/2 ... 267 | + probeSites(a0,1)/pixelSize-1, imageSize(1))+1; 268 | yInds = mod((1:imageSizeOutput(2)) ... 269 | - imageSizeOutput(2)/2 ... 270 | + probeSites(a0,2)/pixelSize-1, imageSize(2))+1; 271 | imageCut = imagePot(round(xInds),round(yInds)); 272 | % imageCut = fft2(imageCut .* w2); 273 | % imageCut = fftshift(wa .* abs(imageCut).^1); 274 | imageCut = fft2(repmat(imageCut .* w2,[1 1]*probeRep)); 275 | imageCut = imageCut(xVec,yVec); 276 | imageCut = fftshift(abs(imageCut)); 277 | imageCut(:) = conv2(imageCut,kDisk,'same'); 278 | imageCut(:) = imageCut.^(1/2); 279 | % imageCut(:) = (imageCut).^0.667 ... 280 | % .* (wa * probeWeights(a0) + (1-probeWeights(a0))); 281 | 282 | warp(yi+probeSites(a0,2),... 283 | xi+probeSites(a0,1),... 284 | xi*0+probePos(3),... 285 | imageCut * 0.08 * 1) 286 | end 287 | 288 | hold off 289 | axis equal off 290 | caxis([0 0.25]) 291 | 292 | 293 | 294 | camlight left 295 | light('style','infinite','position',[1 -6 1+1]*1e3) 296 | light('style','infinite','position',[0 -6 -1+1]*1e3) 297 | lighting phong 298 | material shiny 299 | 300 | camva(cAngle) 301 | camproj('perspective') 302 | camtarget(cTar([2 1 3])) 303 | campos(cPos([2 1 3])+cTar([2 1 3])) 304 | 305 | 306 | % toc 307 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/animOrient02.m: -------------------------------------------------------------------------------- 1 | function [] = animOrient02(fbase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Animation to show interaction of STEM probe with a 5 | % crystalline sample, consisting of three grains 6 | % with different orientations. 7 | % 02 - This script repeatedly calls 01, with different probe positions. 8 | 9 | % Ordering animation 10 | Nc = 120; % number of probe positions / frames in each direction 11 | v = linspace(45,5,Nc+1)'; 12 | probeSitesArray = [ ... 13 | [ones(Nc,1)*5 v(1:(end-1))]; 14 | [ones(Nc,1)*5 flipud(v(2:end))] 15 | ]; 16 | 17 | for a0 = 1:size(probeSitesArray,1) 18 | probeSites = probeSitesArray(a0,:); 19 | animOrient01(probeSites); 20 | 21 | if nargin > 0 22 | fname = [fbase sprintf('%04d',a0) '.png']; 23 | eval(['export_fig -nocrop -r110 ' fname]); 24 | else 25 | drawnow; 26 | end 27 | end 28 | 29 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/animStrain01.m: -------------------------------------------------------------------------------- 1 | function [] = animStrain01(probeSites) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Animation to show interaction of STEM probe with a 5 | % crystalline sample, where the sample has been 6 | % compressed on one side, and stretched on the other. 7 | % 01 - This script renders the scene. 8 | 9 | skip = 1; 10 | flagScatter = 1; 11 | 12 | 13 | imageSize = [1 1]*128; 14 | probeRadius = 0.6; 15 | % probeSites = [ ... 16 | % 5 5; 17 | % ...%5 15; 18 | % 5 25; 19 | % ...%5 35; 20 | % 5 45]; 21 | probeSites(:,2) = probeSites(:,2) + 0.2; 22 | probePos = [20 0 -20]*1.2 + 5; 23 | % probeAngle = 2; 24 | probeXY = [-5 5;-5 5]; 25 | probeRep = 3; 26 | probeCrop = imageSize;%[1 1]*100; 27 | probeImageScale = 16;%8*2; 28 | probeIntRange = [3 30]; 29 | linewidthProbes = 1; 30 | 31 | numAtoms = [10 50 10]; 32 | cellDim = [11 51 11]; 33 | 34 | mSize = 40 + 10; 35 | lw = 1; 36 | radius = 0.48; 37 | 38 | cTar = [0 0 0] + cellDim * 0.5 + [0 -1.3 0]; 39 | % cPos = [-3 0 2]*32; 40 | cPos = [-3 0 1.5]*36; 41 | cAngle = 20 + 1; 42 | 43 | 44 | % Atomic sites 45 | [yp,xp,zp] = meshgrid(1:numAtoms(2),1:numAtoms(1),1:numAtoms(3)); 46 | p = [xp(:) yp(:) zp(:)]; 47 | % Shifts 48 | dy = (p(:,2) - 0).^2*0.008; 49 | % dy = (p(:,2) - 0).^2*0.009 - p(:,2)*0.0; 50 | p(:,2) = p(:,2)*0.6 + dy + 0.5; 51 | p(:,2) = numAtoms(2)+1-p(:,2); 52 | 53 | % Projected sites for FFTs 54 | % x = 1:probeCrop(1); 55 | % y = 1:probeCrop(2); 56 | x = linspace(-probeImageScale/2,probeImageScale/2,probeCrop(1)); 57 | y = linspace(-probeImageScale/2,probeImageScale/2,probeCrop(2)); 58 | [yi,xi] = meshgrid(y-mean(y),x-mean(x)); 59 | w2 = hanning(imageSize(1))*hanning(imageSize(2))'; 60 | % w2 = sqrt(w2); 61 | k = fspecial('gaussian',21,1.5); 62 | kDisk = fspecial('disk',8-1); 63 | 64 | % Sphere 65 | % [xs,ys,zs] = sphere(8*2); 66 | % xs = xs * radius; 67 | % ys = ys * radius; 68 | % zs = zs * radius; 69 | 70 | 71 | % Plotting 72 | h = figure(1); 73 | clf 74 | % set(h,'color','w','outerposition',[1020 380 576 512+128]) 75 | set(h,'color','w') 76 | hold on 77 | % sub = p(:,1) < 1.5 - 100; 78 | % scatter3(p(sub,2),p(sub,1),p(sub,3),... 79 | % 'marker','o','sizedata',mSize,'linewidth',lw,... 80 | % 'markerfacecolor',[1 0.7 0.7],'markeredgecolor',[1 0 0]) 81 | % 82 | % scatter3(p(~sub,2),p(~sub,1),p(~sub,3),... 83 | % 'marker','o','sizedata',mSize,'linewidth',lw,... 84 | % 'markerfacecolor',[1 0.9 0.9],'markeredgecolor',[1 0.5 0.5]) 85 | 86 | if flagScatter == true 87 | % scatter3(p(:,2),p(:,1),p(:,3),... 88 | % 'marker','o','sizedata',mSize,'linewidth',lw,... 89 | % 'markerfacecolor',[1 0.7 0.7],'markeredgecolor',[1 0 0]) 90 | 91 | 92 | 93 | scatter3(p(:,2),p(:,1),p(:,3),... 94 | 'marker','o','sizedata',mSize,'linewidth',lw,... 95 | 'markerfacecolor',[1 0 0],'markeredgecolor',[0 0 0]) 96 | 97 | d = cPos; 98 | d = d / norm(d) * 0.05 + [0 -0.1 0.1]; 99 | scatter3(p(:,2)+d(1),p(:,1)+d(2),p(:,3)+d(3),... 100 | 'marker','o','sizedata',10,'linewidth',lw,... 101 | 'markerfacecolor',[1 0.7 0.7],'markeredgecolor','none') 102 | 103 | d = cPos; 104 | d = d / norm(d) * 0.1 + [0 -0.1 0.1]; 105 | scatter3(p(:,2)+d(1),p(:,1)+d(2),p(:,3)+d(3),... 106 | 'marker','o','sizedata',3,'linewidth',lw,... 107 | 'markerfacecolor',[1 0.9 0.9],'markeredgecolor','none') 108 | else 109 | 110 | Np = size(p,1); 111 | for a0 = 1:skip:Np 112 | xyz = p(a0,:); 113 | if sub(a0) == true 114 | % c1 = [1 0.7 0.7]; 115 | c2 = [1 0 0]; 116 | else 117 | % c1 = [1 0.9 0.9]; 118 | c2 = [0.5 0 0]; 119 | end 120 | 121 | surf(xs+xyz(2),ys+xyz(1),zs+xyz(3),... 122 | 'edgecolor','none','facecolor',c2) 123 | 124 | end 125 | end 126 | 127 | % Draw probes 128 | t = linspace(0,2*pi,180+1); 129 | ct = cos(t); 130 | st = sin(t); 131 | 132 | % imageProbe = zeros(imageSize); 133 | for a0 = 1:size(probeSites,1) 134 | xR = probeXY(1,:) + probeSites(a0,1); 135 | yR = probeXY(2,:) + probeSites(a0,2); 136 | sub = p(:,1) >= xR(1) ... 137 | & p(:,1) <= xR(2) ... 138 | & p(:,2) >= yR(1) ... 139 | & p(:,2) <= yR(2); 140 | 141 | xInd = (p(sub,1) - xR(1)) / (xR(2) - xR(1)); 142 | yInd = (p(sub,2) - yR(1)) / (yR(2) - yR(1)); 143 | xInd = min(max(round(xInd * imageSize(1)),1),imageSize(1)); 144 | yInd = min(max(round(yInd * imageSize(2)),1),imageSize(2)); 145 | imageProbe = accumarray([xInd yInd],... 146 | ones(sum(sub),1),imageSize); 147 | imageProbe(:) = conv2(imageProbe,k,'same'); 148 | imageProbe(:) = imageProbe .* w2; 149 | imageProbe = repmat(imageProbe,[1 1]*probeRep); 150 | imageProbe(:) = fft2(imageProbe); 151 | imageProbe = fftshift(abs(imageProbe( ... 152 | [(1:probeCrop(1)) ((1-probeCrop(1)):0)+size(imageProbe,1)],... 153 | [(1:probeCrop(2)) ((1-probeCrop(2)):0)+size(imageProbe,2)]))); 154 | imageProbe(:) = conv2(imageProbe,kDisk,'same'); 155 | 156 | 157 | warp(yi+probeSites(a0,2),... 158 | xi+probeSites(a0,1),... 159 | xi*0+probePos(3),... 160 | imageProbe); 161 | line([-1 1]*probeRadius+probeSites(a0,2),... 162 | [0 0]+probeSites(a0,1),... 163 | probePos([1 3]),... 164 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 165 | line([-1 1]*probeRadius+probeSites(a0,2),... 166 | [0 0]+probeSites(a0,1),... 167 | probePos([3 1]),... 168 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 169 | line(ct*probeRadius+probeSites(a0,2),... 170 | st*probeRadius+probeSites(a0,1),... 171 | probePos(3)+ct*0,... 172 | 'linewidth',linewidthProbes,'color',[0 0.8 1]) 173 | 174 | end 175 | colormap(gray(256)) 176 | caxis(probeIntRange) 177 | 178 | hold off 179 | axis equal off 180 | 181 | camtarget(cTar([2 1 3])) 182 | campos(cPos([2 1 3])+cTar([2 1 3])) 183 | camva(cAngle) 184 | camproj('perspective') 185 | 186 | % camlight right 187 | % light('style','infinite','position',[0 -6 1]*1e3) 188 | % light('style','infinite','position',[0 -6 -1]*1e3) 189 | % lighting phong 190 | % material shiny 191 | 192 | % camlight left 193 | % light('style','infinite','position',[1-15 -6 1+1 + 5]*1e3) 194 | % light('style','infinite','position',[0-15 -6 -1+1 + 5]*1e3) 195 | 196 | 197 | % figure(678) 198 | % clf 199 | % imagesc(imageProbe) 200 | % axis equal off 201 | % colormap(gray(256)) 202 | 203 | % toc 204 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/animStrain02.m: -------------------------------------------------------------------------------- 1 | function [] = animStrain02(fbase) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example - Animation to show interaction of STEM probe with a 5 | % crystalline sample, where the sample has been 6 | % compressed on one side, and stretched on the other. 7 | % 02 - This script repeatedly calls 01, with different probe positions. 8 | 9 | % Ordering animation 10 | Nc = 120; 11 | v = linspace(45,5,Nc+1)'; 12 | probeSitesArray = [ ... 13 | [ones(Nc,1)*5 v(1:(end-1))]; 14 | [ones(Nc,1)*5 flipud(v(2:end))] 15 | ]; 16 | % rScale = 0.0015; 17 | 18 | for a0 = 1:size(probeSitesArray,1) 19 | probeSites = probeSitesArray(a0,:); 20 | animStrain01(probeSites); 21 | 22 | if nargin > 0 23 | fname = [fbase sprintf('%04d',a0) '.png']; 24 | eval(['export_fig -nocrop -r110 ' fname]); 25 | else 26 | drawnow; 27 | end 28 | end 29 | 30 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/colorComplex.m: -------------------------------------------------------------------------------- 1 | function [imageRGB] = colorComplex(EW,ampRange,ampPower) 2 | 3 | % Colin Ophus - 2021 March 4 | % HSV version of exit wave coloring 5 | 6 | imageRGB = ones(size(EW,1),size(EW,2),3); 7 | imageRGB(:,:,1) = mod(angle(EW)/(2*pi),1); 8 | imageRGB(:,:,3) = min(max( .... 9 | (abs(EW) - ampRange(1)) / (ampRange(2) - ampRange(1)),0),1); 10 | if nargin > 2 11 | imageRGB(:,:,3) = imageRGB(:,:,3).^ampPower; 12 | end 13 | imageRGB(:) = hsv2rgb(imageRGB); 14 | 15 | if nargout == 0 16 | figure(11) 17 | clf 18 | imagesc(imageRGB) 19 | axis equal off 20 | set(gca,'position',[0 0 1 1]) 21 | end 22 | 23 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/colorComplexLAB.m: -------------------------------------------------------------------------------- 1 | function [imageRGB] = colorComplexLAB(EW,ampRange,ampPower) 2 | 3 | % Colin Ophus - 2021 March 4 | % L*a*b version of exit wave coloring 5 | 6 | % abRange = 64; 7 | 8 | p = angle(EW); 9 | amp = abs(EW); 10 | amp = min(max((amp - ampRange(1)) / (ampRange(2) - ampRange(1)),0),1); 11 | if nargin > 2 12 | amp = amp.^ampPower; 13 | end 14 | 15 | imageRGB = ones(size(EW,1),size(EW,2),3); 16 | imageRGB(:,:,1) = mod(p/(2*pi),1); 17 | imageRGB(:,:,3) = amp; 18 | imageRGB(:) = hsv2rgb(imageRGB); 19 | 20 | 21 | imageRGB(:) = rgb2lab(imageRGB); 22 | % min(min(imageRGB(:,:,1))) 23 | imageRGB(:,:,1) = 100 * amp; 24 | imageRGB(:) = lab2rgb(imageRGB); 25 | 26 | % % rgb = lab2rgb(lab) 27 | % % abRange = 200; 28 | % % t = repmat(linspace(-abRange,abRange,size(imageRGB,2)),[size(imageRGB,1) 1]); 29 | % % imageRGB(:,:,2) = t; 30 | % imageRGB = zeros(size(EW,1),size(EW,2),3); 31 | % imageRGB(:,:,1) = 100 * amp; 32 | % imageRGB(:,:,2) = cos(p) * abRange; 33 | % imageRGB(:,:,3) = sin(p) * abRange; 34 | % imageRGB(:) = lab2rgb(imageRGB); 35 | 36 | 37 | if nargout == 0 38 | figure(11) 39 | clf 40 | imagesc(imageRGB) 41 | axis equal off 42 | set(gca,'position',[0 0 1 1]) 43 | end 44 | 45 | 46 | end 47 | -------------------------------------------------------------------------------- /matlab/part_05_06_physics/makeFourierCoords.m: -------------------------------------------------------------------------------- 1 | function [qx,qy] = makeFourierCoords(N,pixelSize) 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % Generate Fourier space coordinates in x and y directions. 5 | 6 | if mod(N(1),2) == 0 7 | qx = circshift(((-N(1)/2):(N(1)/2-1))/(N(1)*pixelSize),[0 -N(1)/2]); 8 | else 9 | qx = circshift((((1-N(1))/2):((N(1)-1)/2))/(N(1)*pixelSize),[0 (1-N(1))/2]); 10 | end 11 | if nargout == 2 12 | % Check to see if second dimension length is same as first 13 | if length(N) == 1 14 | [qy,qx] = meshgrid(qx); 15 | else 16 | % Add second dimension 17 | if mod(N(2),2) == 0 18 | qy = circshift(((-N(2)/2):(N(2)/2-1))/(N(2)*pixelSize),[0 -N(2)/2]); 19 | else 20 | qy = circshift((((1-N(2))/2):((N(2)-1)/2))/(N(2)*pixelSize),[0 (1-N(2))/2]); 21 | end 22 | [qy,qx] = meshgrid(qy,qx); 23 | end 24 | end 25 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/makeSpiralEW.m: -------------------------------------------------------------------------------- 1 | function [EW] = makeSpiralEW(numOAM) 2 | 3 | % Make a spiral phase EW image 4 | 5 | imageSize = [1 1] * 1000; 6 | qRange = [-1 1] * 0.01; 7 | if nargin == 0 8 | numOAM = 0; 9 | end 10 | 11 | 12 | [qxa,qya] = makeFourierCoords(imageSize,1); 13 | q2 = qxa.^2 + qya.^2; 14 | q1 = sqrt(q2); 15 | qt = atan2(qya,qxa); 16 | dq = qxa(2,1) - qxa(1,1); 17 | 18 | % Make EW 19 | PsiAmp1 = 1 - min(max( (qRange(1) - q1)/dq + 0.5,0),1); 20 | PsiAmp2 = min(max( (qRange(2) - q1)/dq + 0.5,0),1); 21 | PsiAmp = PsiAmp1 .* PsiAmp2; 22 | PsiPhase = numOAM*qt; 23 | Psi = PsiAmp .* exp(1i*PsiPhase); 24 | EW = fftshift(ifft2(Psi)); 25 | EW = EW / max(abs(EW(:))); 26 | 27 | % figure(11) 28 | % clf 29 | % imagesc(abs(EW)) 30 | % % imagesc(angle(EW)) 31 | % % imagesc(fftshift((PsiPhase))) 32 | % % imagesc(fftshift((PsiAmp))) 33 | % axis equal off 34 | % colorbar 35 | 36 | 37 | 38 | 39 | 40 | 41 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/schematic01.m: -------------------------------------------------------------------------------- 1 | function [] = schematic01() 2 | 3 | % Colin Ophus - clophus@lbl.gov - 2020 February 4 | % APS tutorial example 02 - plotting atoms from the FePt sample 5 | 6 | zBox = [1.5 0.1 -0.1 -1.5]; 7 | % zMid = linspace(-1.5,1.5,6); 8 | % zMid = zMid*0.7 + 0.1*zMid.^3; 9 | % zMid = zMid*0.9 + 0.08*zMid.^3; 10 | zMid = (linspace(0,1,5).^0.9)*3-1.5; 11 | mxy = [0 -2.5]; 12 | 13 | cTar = [0 0 0] + [0 -1.0 0]; 14 | cPos = [-2 -0.5 1]*6; 15 | cAngle = 15; 16 | 17 | 18 | ampRange = [0 0.5e-4]; 19 | 20 | imageSize = [1 1]*512*2; 21 | pixelSize = 0.02; 22 | [qxa,qya] = makeFourierCoords(imageSize,pixelSize); 23 | q2 = qxa.^2 + qya.^2; 24 | prop = exp(-1i*pi*q2*0.4); 25 | qMax = 0.8; 26 | Psi = double(q2 <= qMax^2); 27 | s = 0.8; 28 | pot = (cos(qxa*s).^4) .* (cos(qya*s).^4) ... 29 | + (sin(qxa*s/2).^4) .* (sin(qya*s/2).^4); 30 | pot = circshift(pot,[1 1]*16); 31 | trans = exp(1i*pot*0.5*2); 32 | 33 | 34 | % Testing plotting of the potential 35 | % figure(56) 36 | % clf 37 | % imagesc(fftshift(pot)) 38 | % axis equal off 39 | % colormap(gray(256)) 40 | 41 | 42 | p = [ ... 43 | -1 -1 0; 44 | 1 -1 0; 45 | 1 1 0; 46 | -1 1 0]; 47 | f = 1:4; 48 | 49 | 50 | 51 | figure(1) 52 | clf 53 | % Uncomment these lines to fix the position and colour of the axes 54 | % set(gcf,'outerposition',[1000 500 576 512],'color','w') 55 | % set(gcf,'outerposition',[1000 500 576 512],'color','k') 56 | hold on 57 | 58 | for a0 = 1:length(zBox) 59 | patch('vertices',p(:,[2 1 3]).*[1 1 1] + [0 0 zBox(a0)],... 60 | 'faces',f,'linewidth',1,... 61 | 'facecolor',[1 1 1],'edgecolor',[0 0 0]); 62 | end 63 | 64 | x = linspace(0,1,imageSize(1)/2); 65 | y = linspace(0,1,imageSize(2)/2); 66 | [ya,xa] = meshgrid(y,x); 67 | v = [(1:(imageSize(1)/4)) ((1-imageSize(1)/4):0)+imageSize(1)]; 68 | vec = fliplr(1:length(zMid)); 69 | scale = linspace(1,1.8,length(vec)); 70 | % bb = 8; 71 | for a0 = 1:length(vec) 72 | ind = vec(a0); 73 | 74 | xyz = p(:,[2 1 3]).*[0.5 0.5 1] + [mxy zMid(ind)]; 75 | % patch('vertices',xyz,... 76 | % 'faces',f,'linewidth',1,... 77 | % 'facecolor',[1 1 1],'edgecolor',[0 0 0]); 78 | 79 | yy = [xyz(1,1) xyz(3,1)-xyz(1,1)]; 80 | xx = [xyz(1,2) xyz(3,2)-xyz(1,2)]; 81 | 82 | psi = ifft2(Psi); 83 | psi = fftshift(psi(v,v)); 84 | Irgb = colorComplex(abs(psi),-angle(psi),ampRange); 85 | % Irgb(1:bb,:,:) = 1; 86 | % Irgb(:,1:bb,:) = 1; 87 | % Irgb(((1-bb):0)+end,:,:) = 1; 88 | % Irgb(:,((1-bb):0)+end,:) = 1; 89 | 90 | h = abs(psi).^0.8 * 100 * scale(a0); 91 | 92 | warp(ya*yy(2)+yy(1), ... 93 | xa*xx(2)+xx(1),... 94 | xa*0+xyz(1,3) + h,Irgb); 95 | 96 | Psi = Psi.*prop; 97 | Psi = fft2(ifft2(Psi) .* trans); 98 | end 99 | 100 | hold off 101 | axis equal off 102 | box on 103 | 104 | camtarget(cTar) 105 | campos(cPos + cTar) 106 | camva(cAngle) 107 | camproj('perspective') 108 | set(gca,'ydir','normal') 109 | 110 | caxis([0 1]) 111 | camlight left 112 | material shiny 113 | 114 | 115 | 116 | 117 | end -------------------------------------------------------------------------------- /matlab/part_05_06_physics/tukeywinMake.m: -------------------------------------------------------------------------------- 1 | function [windowOutput] = tukeywinMake(windowSize,windowFrac) 2 | 3 | % Colin Ophus - 2020 Sept 4 | % Quick re-definition of Tukey / Hann window function 5 | 6 | 7 | if nargin == 1 8 | windowFrac = [0 0]; 9 | elseif length(windowSize) == 2 && length(windowFrac) == 1 10 | windowFrac = [1 1]*windowFrac; 11 | end 12 | 13 | % 1D window 14 | windowOutput = min(1/(1 - windowFrac(1)) * (1 - ... 15 | abs((windowSize(1)+1)/2 - (1:windowSize(1))') * 2 / windowSize(1)),1); 16 | windowOutput(:) = sin(windowOutput*(pi/2)).^2; 17 | 18 | % 2D window 19 | if length(windowSize) == 2 20 | wy = min(1/(1 - windowFrac(2)) * (1 - ... 21 | abs((windowSize(2)+1)/2 - (1:windowSize(2))) * 2 / windowSize(2)),1); 22 | wy(:) = sin(wy*(pi/2)).^2; 23 | 24 | windowOutput = windowOutput * wy; 25 | end 26 | 27 | 28 | end -------------------------------------------------------------------------------- /python/atoms_plot_output_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/python/atoms_plot_output_01.png -------------------------------------------------------------------------------- /python/diffraction_movie_02.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/python/diffraction_movie_02.mp4 -------------------------------------------------------------------------------- /python/schematic_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cophus/Programmatic_Figures_Tutorial/dcd02dd51ff36538e474233f978f85c82a19c758/python/schematic_03.png --------------------------------------------------------------------------------