function plotSmoothedContourOnPhaseDiagram(M, SCATTERING_LENGTH_RANGE, NUM_ATOMS_LIST, TitleString, varargin) interpMethod = 'makima'; showPoints = true; matFilePaths = {}; i = 1; while i <= numel(varargin) arg = varargin{i}; if ischar(arg) || isstring(arg) switch lower(arg) case {'interp', 'interpmethod'} interpMethod = varargin{i+1}; i = i + 2; case 'showpoints' showPoints = varargin{i+1}; i = i + 2; otherwise matFilePaths{end+1} = char(arg); i = i + 1; end else error('Unexpected argument type'); end end regionNames = ["Unmodulated", "SSD", "Stripe", "Labyrinth", "Honeycomb"]; regionColors = [ 0.8 0.8 0.8; 0.2 0.6 1.0; 0.2 0.8 0.2; 1.0 0.6 0.2; 0.8 0.2 0.8 ]; [X, Y] = meshgrid(NUM_ATOMS_LIST, SCATTERING_LENGTH_RANGE); [Xq, Yq] = meshgrid(linspace(min(NUM_ATOMS_LIST), max(NUM_ATOMS_LIST), 500), ... linspace(min(SCATTERING_LENGTH_RANGE), max(SCATTERING_LENGTH_RANGE), 500)); Mq = interp2(X, Y, M, Xq, Yq, 'nearest'); fig = figure('Color', 'w'); clf; set(fig, 'Position', [100, 100, 1050, 800], 'Renderer', 'opengl'); ax = axes('Parent', fig, 'Position', [0.1 0.15 0.75 0.8]); imagesc(ax, [min(NUM_ATOMS_LIST), max(NUM_ATOMS_LIST)], ... [min(SCATTERING_LENGTH_RANGE), max(SCATTERING_LENGTH_RANGE)], Mq); set(ax, 'YDir', 'normal'); colormap(ax, regionColors); colorbar(ax, 'Ticks', 0:4, 'TickLabels', regionNames, 'FontSize', 12); clim(ax, [0 4]); hold(ax, 'on'); contour(ax, Xq, Yq, Mq, 0.5:1:3.5, 'k', 'LineWidth', 1.2); xlabel(ax, 'Number of Atoms', 'FontSize', 16); ylabel(ax, 'Scattering Length (\times a_o)', 'FontSize', 16); t = title(ax, TitleString, 'FontSize', 18, 'Interpreter', 'tex'); t.Color = 'k'; % force title color to black set(ax, 'FontSize', 16, 'Color', 'none'); axis(ax, 'tight'); grid(ax, 'on'); % Storage pointData = {}; % {struct with .x, .y, .points, .curve, .orig} draggingPoint = []; currentSet = 1; % Load points for k = 1:numel(matFilePaths) data = load(matFilePaths{k}); if ~isfield(data, 'SelectedPoints') || ~isfield(data.SelectedPoints, 'values') warning('Skipping %s: missing SelectedPoints.values', matFilePaths{k}); continue; end rawPoints = data.SelectedPoints.values; if iscell(rawPoints) pointSets = rawPoints; else pointSets = {rawPoints}; end for i = 1:numel(pointSets) pts = pointSets{i}; x = pts(:,1) * 1e5; y = pts(:,2); pointData{end+1} = plotPointSet(ax, x, y, interpMethod, showPoints); end end % Add control panel uicontrol('Style', 'pushbutton', 'String', 'Save', 'FontSize', 12, ... 'Position', [860, 720, 150, 40], 'Callback', @(~,~) savePoints()); uicontrol('Style', 'pushbutton', 'String', 'Export As...', 'FontSize', 12, ... 'Position', [860, 670, 150, 40], 'Callback', @(~,~) exportPoints()); uicontrol('Style', 'pushbutton', 'String', 'Reset All', 'FontSize', 12, ... 'Position', [860, 620, 150, 40], 'Callback', @(~,~) resetPoints()); % Mouse interaction set(fig, 'WindowButtonDownFcn', @startInteraction); set(fig, 'WindowButtonUpFcn', @stopDrag); set(fig, 'WindowButtonMotionFcn', @doDrag); function s = plotPointSet(ax, x, y, method, showPts) [x, idx] = sort(x); y = y(idx); dist = sqrt(diff(x).^2 + diff(y).^2); t = [0; cumsum(dist)]; t = t / t(end); t_fine = linspace(0,1,500); x_smooth = interp1(t, x, t_fine, method); y_smooth = interp1(t, y, t_fine, method); s.x = x; s.y = y; s.orig = [x(:), y(:)]; s.points = gobjects(numel(x),1); if showPts for j = 1:numel(x) s.points(j) = plot(ax, x(j), y(j), 'ro', 'MarkerFaceColor', 'r', ... 'ButtonDownFcn', @(src,~) pointClick(src)); end end s.curve = plot(ax, x_smooth, y_smooth, 'w-', 'LineWidth', 2); end function pointClick(hPoint) modifiers = get(fig, 'CurrentModifier'); % get current key modifiers if any(strcmp(modifiers, 'shift')) % Shift+Click deletes point deletePoint(hPoint); else startDrag(hPoint); % normal click starts drag end end function deletePoint(hPoint) for i = 1:numel(pointData) idx = find(pointData{i}.points == hPoint); if ~isempty(idx) % Remove point data s = pointData{i}; delete(s.points(idx)); % delete point graphic s.points(idx) = []; s.x(idx) = []; s.y(idx) = []; updateCurve(s); pointData{i} = s; break; end end end function startInteraction(~, ~) click = get(ax, 'CurrentPoint'); if strcmp(fig.SelectionType, 'alt') % right click to add point pt = click(1,1:2); s = pointData{currentSet}; s.x(end+1) = pt(1); s.y(end+1) = pt(2); s.points(end+1) = plot(ax, pt(1), pt(2), 'ro', ... 'MarkerFaceColor', 'r', 'ButtonDownFcn', @(src,~) pointClick(src)); [s.x, I] = sort(s.x); s.y = s.y(I); s.points = s.points(I); updateCurve(s); pointData{currentSet} = s; end end function startDrag(h) draggingPoint = h; end function doDrag(~, ~) if isempty(draggingPoint), return; end pt = get(ax, 'CurrentPoint'); draggingPoint.XData = pt(1,1); draggingPoint.YData = pt(1,2); updateAssociatedCurve(draggingPoint); end function stopDrag(~, ~) draggingPoint = []; end function updateAssociatedCurve(hPoint) for i = 1:numel(pointData) idx = find(pointData{i}.points == hPoint); if ~isempty(idx) pointData{i}.x(idx) = hPoint.XData; pointData{i}.y(idx) = hPoint.YData; updateCurve(pointData{i}); break; end end end function updateCurve(s) [s.x, idx] = sort(s.x); s.y = s.y(idx); s.points = s.points(idx); dist = sqrt(diff(s.x).^2 + diff(s.y).^2); t = [0; cumsum(dist)]; if t(end) == 0, return; end t = t / t(end); t_fine = linspace(0,1,500); xs = interp1(t, s.x, t_fine, interpMethod); ys = interp1(t, s.y, t_fine, interpMethod); set(s.curve, 'XData', xs, 'YData', ys); end function savePoints() for i = 1:numel(pointData) pts = [pointData{i}.x(:)/1e5, pointData{i}.y(:)]; SelectedPoints.values = pts; save(sprintf('ModifiedSet_%d.mat', i), 'SelectedPoints'); end disp('Saved all modified point sets.'); end function exportPoints() [f,p] = uiputfile('*.mat', 'Save As...'); if isequal(f,0), return; end pts = cell(1, numel(pointData)); % Initialize as cell array for i = 1:numel(pointData) pts{i} = [pointData{i}.x(:)/1e5, pointData{i}.y(:)]; end SelectedPoints.values = pts; save(fullfile(p,f), 'SelectedPoints'); disp(['Exported to ', fullfile(p,f)]); end function resetPoints() for i = 1:numel(pointData) s = pointData{i}; delete(s.points); delete(s.curve); pointData{i} = plotPointSet(ax, s.orig(:,1), s.orig(:,2), interpMethod, true); end end end