Quiver plot of coordinate error with wrong arrow lengths

I'm working on a quiver plot that represents coordinate error in images.
However, the magnitude of the vectors is not being represented correctly: for example, some small erros are being draw as bigger lines.
The magnitudes seems to be calculated correctly, but 'idx' is always 0 or 1, although there are 4 magnitude classes; also, the lengths of arrows are wrong in the figures.
I'm plotting 5 figures, but magnitude thresholds are calculated considering the set of images to generate a common legend.
% data
x1 = xlsread('DSC03765.xlsx',1,'A14:A614');
y1 = xlsread('DSC03765.xlsx',1,'B14:B614');
errorx1 = xlsread('DSC03765.xlsx',1,'E14:E614');
errory1 = xlsread('DSC03765.xlsx',1,'F14:F614');
x2 = xlsread('DSC03765.xlsx',2,'A14:A614');
y2 = xlsread('DSC03765.xlsx',2,'B14:B614');
errorx2 = xlsread('DSC03765.xlsx',2,'E14:E614');
errory2 = xlsread('DSC03765.xlsx',2,'F14:F614');
x3 = xlsread('DSC03765.xlsx',3,'A14:A614');
y3 = xlsread('DSC03765.xlsx',3,'B14:B614');
errorx3 = xlsread('DSC03765.xlsx',3,'E14:E614');
errory3 = xlsread('DSC03765.xlsx',3,'F14:F614');
x4 = xlsread('DSC03765.xlsx',4,'A14:A614');
y4 = xlsread('DSC03765.xlsx',4,'B14:B614');
errorx4 = xlsread('DSC03765.xlsx',4,'E14:E614');
errory4 = xlsread('DSC03765.xlsx',4,'F14:F614');
x5 = xlsread('DSC03765.xlsx',5,'A14:A614');
y5 = xlsread('DSC03765.xlsx',5,'B14:B614');
errorx5 = xlsread('DSC03765.xlsx',5,'E14:E614');
errory5 = xlsread('DSC03765.xlsx',5,'F14:F614');
% calculate magnitude
magnitude1 = sqrt(errorx1.^2+errory1.^2);
magnitude2 = sqrt(errorx2.^2+errory2.^2);
magnitude3 = sqrt(errorx3.^2+errory3.^2);
magnitude4 = sqrt(errorx4.^2+errory4.^2);
magnitude5 = sqrt(errorx5.^2+errory5.^2);
magnitude_total = [];
magnitudes = {magnitude1, magnitude2, magnitude3, magnitude4, magnitude5};
% concatenate values of magnitude in one array
for i = 1:length(magnitudes)
magnitude_total = vertcat(magnitude_total, magnitudes{i});
end
% calculate min and max magnitude
mag_res = 0.05;
magnitudelim = [ ...
floor(min(magnitude_total)/mag_res) ...
ceil(max(magnitude_total)/mag_res) ...
]*mag_res;
% define a color map
n_colors = 4;
cmap = jet(n_colors);
% calculate the magnitude thresholds
mthresholds = linspace(magnitudelim(1),magnitudelim(2),n_colors+1);
% plot function
function plot_image(x, y, errorx, errory, magnitude, mthresholds, cmap, magnitudelim, n_colors, img_title)
figure
hold on
% for each color, find the indicies of the magnitudes at this color level
for ii = 1:n_colors
idx = magnitude >= mthresholds(ii) & magnitude < mthresholds(ii+1);
% generate an arrow of the corresponding color
quiver(x(idx), y(idx), errorx(idx), errory(idx), 0.5, 'Color', cmap(ii,:));
end
% set up the colorbar
colormap(cmap);
colorbar();
caxis(magnitudelim);
xlim([0 2836])
ylim([0 2778])
title(img_title);
hold off
end
% plot all figures
plot_image(x1, y1, errorx1, errory1, magnitude1, mthresholds, cmap, magnitudelim, n_colors, '570nm');
plot_image(x2, y2, errorx2, errory2, magnitude2, mthresholds, cmap, magnitudelim, n_colors, '525nm');
plot_image(x3, y3, errorx3, errory3, magnitude3, mthresholds, cmap, magnitudelim, n_colors, '850nm');
plot_image(x4, y4, errorx4, errory4, magnitude4, mthresholds, cmap, magnitudelim, n_colors, '490nm');
plot_image(x5, y5, errorx5, errory5, magnitude5, mthresholds, cmap, magnitudelim, n_colors, '550nm');

1 commentaire

By the way, here is a more succinct version, which uses readtable instead of xlsread (which is no longer recommended) and uses arrays (cell arrays, tables) instead of sequences of numbered variables (x1, x2, x3, ...):
sheet_names = sheetnames('DSC03765.xlsx');
N = numel(sheet_names);
C = cell(1,N);
for ii = 1:N
% read sheet
T = readtable('DSC03765.xlsx','Sheet',ii);
% rename table variables
T = renamevars(T,1:width(T),{'x','y','foo','bar','errorx','errory'});
% calculate magnitude
T.magnitude = sqrt(T.errorx.^2+T.errory.^2);
% store table in cell array
C{ii} = T;
end
% concatenate values of magnitude in one array
magnitude_total = vertcat(C{:}).magnitude;
% calculate min and max magnitude
mag_res = 0.05;
magnitudelim = [ ...
floor(min(magnitude_total)/mag_res) ...
ceil(max(magnitude_total)/mag_res) ...
]*mag_res;
% define a color map
n_colors = 4;
cmap = jet(n_colors);
% calculate the magnitude thresholds
mthresholds = linspace(magnitudelim(1),magnitudelim(2),n_colors+1);
nm = [570 525 850 490 550];
common_scale_factor = 50;
for ii = 1:numel(C)
plot_image(C{ii}.x, C{ii}.y, common_scale_factor*C{ii}.errorx, common_scale_factor*C{ii}.errory, ...
C{ii}.magnitude, mthresholds, cmap, magnitudelim, n_colors, nm(ii));
end
% plot function
function plot_image(x, y, errorx, errory, magnitude, mthresholds, cmap, magnitudelim, n_colors, nm)
figure
hold on
% for each color, find the indicies of the magnitudes at this color level
for ii = 1:n_colors
idx = magnitude >= mthresholds(ii) & magnitude < mthresholds(ii+1);
% generate an arrow of the corresponding color
quiver(x(idx), y(idx), errorx(idx), errory(idx), 'off', 'Color', cmap(ii,:));
end
% set up the colorbar
colormap(cmap);
colorbar();
caxis(magnitudelim);
xlim([0 2836])
ylim([0 2778])
title(sprintf('%d nm',nm));
hold off
end

Connectez-vous pour commenter.

 Réponse acceptée

Voss
Voss le 24 Mai 2024
Modifié(e) : Voss le 24 Mai 2024
"some small erros are being draw as bigger lines"
That's because each quiver plot scales its own arrows' lengths independently of any other quiver plots.
Using a scale factor of 0.5 means each quiver plot's arrows are half as long as they would be if they were automatically scaled not to overlap, as described in the documentation,
  • When scale is a positive number, the quiver function automatically adjusts the lengths of arrows so they do not overlap, then stretches them by a factor of scale. For example, a scale of 2 doubles the length of arrows, and a scale of 0.5 halves the length of arrows.
But this implies nothing about the relative length of one quiver plot's arrows compared to another quiver plot's arrows. Since each quiver plot's arrow lengths are scaled independently, it's impossible to enforce any relationship between multiple quiver plots' arrow lengths when using automatic scaling.
However, you can turn automatic scaling off, and manually apply a scale factor to the arrow magnitudes (i.e., multiply the U and V by some factor before sending them to quiver). Using the same factor for all quiver plots will scale them all together. See the variable common_scale_factor below, and adjust it until the plots look like what you want.
% data
x1 = xlsread('DSC03765.xlsx',1,'A14:A614');
y1 = xlsread('DSC03765.xlsx',1,'B14:B614');
errorx1 = xlsread('DSC03765.xlsx',1,'E14:E614');
errory1 = xlsread('DSC03765.xlsx',1,'F14:F614');
x2 = xlsread('DSC03765.xlsx',2,'A14:A614');
y2 = xlsread('DSC03765.xlsx',2,'B14:B614');
errorx2 = xlsread('DSC03765.xlsx',2,'E14:E614');
errory2 = xlsread('DSC03765.xlsx',2,'F14:F614');
x3 = xlsread('DSC03765.xlsx',3,'A14:A614');
y3 = xlsread('DSC03765.xlsx',3,'B14:B614');
errorx3 = xlsread('DSC03765.xlsx',3,'E14:E614');
errory3 = xlsread('DSC03765.xlsx',3,'F14:F614');
x4 = xlsread('DSC03765.xlsx',4,'A14:A614');
y4 = xlsread('DSC03765.xlsx',4,'B14:B614');
errorx4 = xlsread('DSC03765.xlsx',4,'E14:E614');
errory4 = xlsread('DSC03765.xlsx',4,'F14:F614');
x5 = xlsread('DSC03765.xlsx',5,'A14:A614');
y5 = xlsread('DSC03765.xlsx',5,'B14:B614');
errorx5 = xlsread('DSC03765.xlsx',5,'E14:E614');
errory5 = xlsread('DSC03765.xlsx',5,'F14:F614');
% calculate magnitude
magnitude1 = sqrt(errorx1.^2+errory1.^2);
magnitude2 = sqrt(errorx2.^2+errory2.^2);
magnitude3 = sqrt(errorx3.^2+errory3.^2);
magnitude4 = sqrt(errorx4.^2+errory4.^2);
magnitude5 = sqrt(errorx5.^2+errory5.^2);
magnitude_total = [];
magnitudes = {magnitude1, magnitude2, magnitude3, magnitude4, magnitude5};
% concatenate values of magnitude in one array
for i = 1:length(magnitudes)
magnitude_total = vertcat(magnitude_total, magnitudes{i});
end
% calculate min and max magnitude
mag_res = 0.05;
magnitudelim = [ ...
floor(min(magnitude_total)/mag_res) ...
ceil(max(magnitude_total)/mag_res) ...
]*mag_res;
% define a color map
n_colors = 4;
cmap = jet(n_colors);
% calculate the magnitude thresholds
mthresholds = linspace(magnitudelim(1),magnitudelim(2),n_colors+1);
% plot function
function plot_image(x, y, errorx, errory, magnitude, mthresholds, cmap, magnitudelim, n_colors, img_title)
figure
hold on
common_scale_factor = 50;
% for each color, find the indicies of the magnitudes at this color level
for ii = 1:n_colors
idx = magnitude >= mthresholds(ii) & magnitude < mthresholds(ii+1);
% generate an arrow of the corresponding color
quiver(x(idx), y(idx), common_scale_factor*errorx(idx), common_scale_factor*errory(idx), 'off', 'Color', cmap(ii,:));
end
% set up the colorbar
colormap(cmap);
colorbar();
caxis(magnitudelim);
xlim([0 2836])
ylim([0 2778])
title(img_title);
hold off
end
% plot all figures
plot_image(x1, y1, errorx1, errory1, magnitude1, mthresholds, cmap, magnitudelim, n_colors, '570nm');
plot_image(x2, y2, errorx2, errory2, magnitude2, mthresholds, cmap, magnitudelim, n_colors, '525nm');
plot_image(x3, y3, errorx3, errory3, magnitude3, mthresholds, cmap, magnitudelim, n_colors, '850nm');
plot_image(x4, y4, errorx4, errory4, magnitude4, mthresholds, cmap, magnitudelim, n_colors, '490nm');
plot_image(x5, y5, errorx5, errory5, magnitude5, mthresholds, cmap, magnitudelim, n_colors, '550nm');
(For the other question, "'idx' is always 0 or 1" because idx is a logical vector, which is used for (logical) indexing.)

2 commentaires

Oh, I see now.
I thought there was proportionality between each other lengths.
This was very helpful, I really appreciate it. Thanks!
You're welcome! Any questions, let me know. Otherwise, please "Accept" this answer. Thanks!

Connectez-vous pour commenter.

Plus de réponses (0)

Produits

Version

R2024a

Question posée :

le 23 Mai 2024

Commenté :

le 24 Mai 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by