在对数刻度上绘制相同(视觉)大小的补丁
Plot patches of same (visual) size on logarithmic scale
我想在具有对数 x 轴的图表中标记一些峰值。我正在考虑使用 patch
,因为我需要一个在用户单击标记时响应的回调。 patch
的Vertices
属性是以数据为单位的,不是像素。但是,我希望补丁以相同的视觉宽度和高度出现,但我找不到计算导致相同宽度(以像素为单位)的宽度(以数据为单位)的方法。
我认为它不会太复杂,但我完全卡住了,也许尝试了太多才看到简单的答案。
我知道这不仅仅与 Matlab 相关,但我很乐意使用 patch
以外的东西,只要它提供响应鼠标点击的功能。
peakpos = [50 500 5000];
peakheight = [5000 7500 10000];
x = 0:5e4;
y = zeros(numel(x),1);
for k = 1:3
y(peakpos(k)) = peakheight(k);
end
ax = axes(figure());
plot(ax, x,y);
ax.XScale = 'log';
ax.Units = 'pixels';
dataperpx_y = diff(ax.YLim)/ax.Position(4);
ax.YLim = [0 1e4+30 * dataperpx_y];
ax.NextPlot = 'add';
for k = 1:3
patch(ax, ...
'Faces', [1 2 3], ...
'Vertices', ...
[ x(peakpos(k)) peakheight(k)+5*dataperpx_y
x(peakpos(k)) - 25 peakheight(k)+15*dataperpx_y
x(peakpos(k)) + 25 peakheight(k)+15*dataperpx_y
], ...
'ButtonDownFcn', @(h,e)display(h.Vertices));
end
好吧,和我想的一样,不是太复杂。我不知道我到底卡在哪里了,但有点令人困惑的是,将轴的 XScale
属性 设置为 log
会使轴使用十进制对数,而log()
函数是自然对数。
以线性比例绘制log10(x)
后,解决方案非常明显:
peakpos = [50 500 5000];
peakheight = [5000 7500 10000];
x = 0:5e4;
y = zeros(numel(x),1);
for k = 1:3
y(peakpos(k)) = peakheight(k);
end
ax = subplot(2,1,1);
plot(ax, log10(x),y);
%ax.XScale = 'log';
ax.Units = 'pixels';
dataperpx_y = diff(ax.YLim)/ax.Position(4);
dataperpx_x = diff(ax.XLim)/ax.Position(3);
ax.YLim = [0 1e4+30 * dataperpx_y];
ax.NextPlot = 'add';
for k = 1:3
patch(ax, ...
'Faces', [1 2 3], ...
'Vertices', ...
[ log10(x(peakpos(k))) peakheight(k)+5*dataperpx_y
log10(x(peakpos(k))) - 5*dataperpx_x peakheight(k)+15*dataperpx_y
log10(x(peakpos(k))) + 5*dataperpx_x peakheight(k)+15*dataperpx_y
], ...
'ButtonDownFcn', @(h,e)display(h.Vertices));
end
ax = subplot(2,1,2);
plot(ax, x, y);
ax.XScale = 'log';
ax.Units = 'pixels';
dataperpx_y = diff(ax.YLim)/ax.Position(4);
dataperpx_x = diff(log10(ax.XLim))/ax.Position(3);
ax.YLim = [0 1e4+30 * dataperpx_y];
ax.NextPlot = 'add';
for k = 1:3
patch(ax, ...
'Faces', [1 2 3], ...
'Vertices', ...
[ x(peakpos(k)) peakheight(k)+5*dataperpx_y
x(peakpos(k)) / 10^(5*dataperpx_x) peakheight(k)+15*dataperpx_y
x(peakpos(k)) * 10^(5*dataperpx_x) peakheight(k)+15*dataperpx_y
], ...
'ButtonDownFcn', @(h,e)display(h.Vertices));
end
我想在具有对数 x 轴的图表中标记一些峰值。我正在考虑使用 patch
,因为我需要一个在用户单击标记时响应的回调。 patch
的Vertices
属性是以数据为单位的,不是像素。但是,我希望补丁以相同的视觉宽度和高度出现,但我找不到计算导致相同宽度(以像素为单位)的宽度(以数据为单位)的方法。
我认为它不会太复杂,但我完全卡住了,也许尝试了太多才看到简单的答案。
我知道这不仅仅与 Matlab 相关,但我很乐意使用 patch
以外的东西,只要它提供响应鼠标点击的功能。
peakpos = [50 500 5000];
peakheight = [5000 7500 10000];
x = 0:5e4;
y = zeros(numel(x),1);
for k = 1:3
y(peakpos(k)) = peakheight(k);
end
ax = axes(figure());
plot(ax, x,y);
ax.XScale = 'log';
ax.Units = 'pixels';
dataperpx_y = diff(ax.YLim)/ax.Position(4);
ax.YLim = [0 1e4+30 * dataperpx_y];
ax.NextPlot = 'add';
for k = 1:3
patch(ax, ...
'Faces', [1 2 3], ...
'Vertices', ...
[ x(peakpos(k)) peakheight(k)+5*dataperpx_y
x(peakpos(k)) - 25 peakheight(k)+15*dataperpx_y
x(peakpos(k)) + 25 peakheight(k)+15*dataperpx_y
], ...
'ButtonDownFcn', @(h,e)display(h.Vertices));
end
好吧,和我想的一样,不是太复杂。我不知道我到底卡在哪里了,但有点令人困惑的是,将轴的 XScale
属性 设置为 log
会使轴使用十进制对数,而log()
函数是自然对数。
以线性比例绘制log10(x)
后,解决方案非常明显:
peakpos = [50 500 5000];
peakheight = [5000 7500 10000];
x = 0:5e4;
y = zeros(numel(x),1);
for k = 1:3
y(peakpos(k)) = peakheight(k);
end
ax = subplot(2,1,1);
plot(ax, log10(x),y);
%ax.XScale = 'log';
ax.Units = 'pixels';
dataperpx_y = diff(ax.YLim)/ax.Position(4);
dataperpx_x = diff(ax.XLim)/ax.Position(3);
ax.YLim = [0 1e4+30 * dataperpx_y];
ax.NextPlot = 'add';
for k = 1:3
patch(ax, ...
'Faces', [1 2 3], ...
'Vertices', ...
[ log10(x(peakpos(k))) peakheight(k)+5*dataperpx_y
log10(x(peakpos(k))) - 5*dataperpx_x peakheight(k)+15*dataperpx_y
log10(x(peakpos(k))) + 5*dataperpx_x peakheight(k)+15*dataperpx_y
], ...
'ButtonDownFcn', @(h,e)display(h.Vertices));
end
ax = subplot(2,1,2);
plot(ax, x, y);
ax.XScale = 'log';
ax.Units = 'pixels';
dataperpx_y = diff(ax.YLim)/ax.Position(4);
dataperpx_x = diff(log10(ax.XLim))/ax.Position(3);
ax.YLim = [0 1e4+30 * dataperpx_y];
ax.NextPlot = 'add';
for k = 1:3
patch(ax, ...
'Faces', [1 2 3], ...
'Vertices', ...
[ x(peakpos(k)) peakheight(k)+5*dataperpx_y
x(peakpos(k)) / 10^(5*dataperpx_x) peakheight(k)+15*dataperpx_y
x(peakpos(k)) * 10^(5*dataperpx_x) peakheight(k)+15*dataperpx_y
], ...
'ButtonDownFcn', @(h,e)display(h.Vertices));
end