I would like to mark some peaks in a graph which has a logarithmic x-axis. I was thinking of using patch
since I need a callback that responds when the user clicks on the marker. The Vertices
property of patch
is in units of data, not pixels. However, I'd like the patches to appear with the same visual width and height, but I cannot find a way to compute the width (in units of data) that leads to the same width (in pixels).
I thought it could not be too complicated, but I got totally stuck and maybe tried too much to see the easy answer.
I know this is not purely related to Matlab, but I'm happy to use something else than patch
, as long as it provides the functionality to respond on a mouse click.
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
Okay, as I thought, it was not too complicated. I do not know where exactly I got stuck, but one thing which was a little bit confusing was that setting the XScale
property of an axes to log
makes the axes use decadic logarithms, while the log()
function is the natural logarithm.
After plotting log10(x)
at a linear scale, the solution was quite obvious:
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