フィルターのクリア

Scale patch objects relative to plot Zoom level

4 ビュー (過去 30 日間)
Robert Daly
Robert Daly 2023 年 12 月 1 日
編集済み: Robert Daly 2023 年 12 月 13 日
I have a function to plot wind speed with directional arrows overlayed on top.
Each arrow is created using a patch object.
To make the arrows a nice size to see, the patch is scaled relative to the current window and axis size.
It works great the first time you plot it, the problem is that when you zoom in on the graph the patches are no longer the correct scale and get distorted.
Is there a way I can get them to recalculate the scaling factor after each zoom and update?
Can I use a different coordinate system for the patches relative to the axis size?
Alternative to patches?
time = datetime("today")-14:datetime("today");
speed = rand(size(time));
dir = linspace(0,360,length(time));
figure
plot_wind(time,speed,dir);
figure
plot_wind(time,speed,dir);
zoom xon
zoom(5)
function h = plot_wind(varargin)
if size(varargin,2)==2
Time=1:length(varargin{1});
WindSpd=varargin{1};
WindDir=varargin{2};
h=axes;
Skip=1;
hl = plot(WindSpd);
elseif size(varargin,2)==3
Time=varargin{1};
WindSpd=varargin{2};
WindDir=varargin{3};
Skip=1;
h=axes;
hl = plot(Time,WindSpd);
elseif size(varargin,2)==4
h=varargin{1};
Time=varargin{2};
WindSpd=varargin{3};
WindDir=varargin{4};
Skip=1;
hl = plot(h,Time,WindSpd);
elseif size(varargin,2)==5
h=varargin{1};
Time=varargin{2};
WindSpd=varargin{3};
WindDir=varargin{4};
Skip=varargin{5};
hl = plot(h,Time,WindSpd);
end
set(hl,'ZData', zeros(size(Time)));
WindowSize=get(gcf,'Position');%[left bottom width height]
AxesSize=get(h,'Position');%[left bottom width height]
xscalefactor=1.5*diff(get(h,'xlim'))*0.03*WindowSize(4)/WindowSize(3)*AxesSize(4)/AxesSize(3);
yscalefactor=1.5*diff(get(h,'ylim'))*0.03;
[theta,rho]=cart2pol([1,0.5,0.5,-1,-1,0.5,0.5],[0,0.5,0.25,0.25,-0.25,-0.25,-0.5]);% Create the shape of the arrow and express in polar coordinates
for p=1:Skip:length(WindDir)
[u,v]=pol2cart(theta-pi/2+WindDir(p).* pi ./ 180,rho);% Add the rotation angle to the arrow and convert back to cartesian coordinates
c=hsv(361);
hp = patch(-u.*xscalefactor+Time(p),v.*yscalefactor+WindSpd(p),c(int16(WindDir(p)+1),:));% create the arrow patch scaled to size based on current window size
set(hp, 'ZData', ones(size(u))*p);
end
end
  1 件のコメント
Robert Daly
Robert Daly 2023 年 12 月 1 日
I am thinking maybe I can put some data in the axis "user data" property. Such as the handles to the patches.
set(gca,'UserData',hp)
And then set up a call back function to update the plot
set(zoom(gca),'ActionPostCallback',@(src,event) ZoomCallback(src,event))
since the WindowSize and AxesSize don't change. I imagine I would need to scale acording to the level of x and y zoom.
Is there a property for the current level of zoom? Or would I need to find the current XLim and Ylim and work out how much they changed?
I think then I can just edit the Vertices property of the patch handle.

サインインしてコメントする。

採用された回答

Robert Daly
Robert Daly 2023 年 12 月 12 日
編集済み: Robert Daly 2023 年 12 月 13 日
To answer my own question...
I modified the function to store the important data to recreate the arrows in each patch as "UserData".
Next I stored the handles to each patch in the axis UserData.
I created a sub function "ZoomCallback" that reads the userdata and updates the X & Y data for the patches.
Then set the ZoomCallback as 'ActionPostCallback' funtion for zoom.
So everytime you zoom, the ZoomCallback gets called and it resizes all of the patches in the plot.
Time = datetime("today")-14:datetime("today");
WindSpd = rand(size(Time));
WindDir = linspace(0,360,length(Time));
figure
plot_wind(Time,WindSpd,WindDir);
figure
plot_wind(Time,WindSpd,WindDir);
zoom xon
zoom(5)
function h = plot_wind(varargin)
if size(varargin,2)==2
Time=1:length(varargin{1});
WindSpd=varargin{1};
WindDir=varargin{2};
h=axes;
Skip=1;
hl = plot(WindSpd);
elseif size(varargin,2)==3
Time=varargin{1};
WindSpd=varargin{2};
WindDir=varargin{3};
Skip=1;
h=axes;
hl = plot(Time,WindSpd);
elseif size(varargin,2)==4
h=varargin{1};
Time=varargin{2};
WindSpd=varargin{3};
WindDir=varargin{4};
Skip=1;
hl = plot(h,Time,WindSpd);
elseif size(varargin,2)==5
h=varargin{1};
Time=varargin{2};
WindSpd=varargin{3};
WindDir=varargin{4};
Skip=varargin{5};
hl = plot(h,Time,WindSpd);
end
set(hl,'ZData', zeros(size(Time)));
WindowSize=get(gcf,'Position');%[left bottom width height]
AxesSize=get(h,'Position');%[left bottom width height]
xscalefactor=1.5*diff(get(h,'xlim'))*0.03*WindowSize(4)/WindowSize(3)*AxesSize(4)/AxesSize(3);
yscalefactor=1.5*diff(get(h,'ylim'))*0.03;
[theta,rho]=cart2pol([1,0.5,0.5,-1,-1,0.5,0.5],[0,0.5,0.25,0.25,-0.25,-0.25,-0.5]);
hp=gobjects(0);
for p=1:Skip:length(WindDir)
[u,v]=pol2cart(theta-pi/2+WindDir(p).* pi ./ 180,rho);
arrow.u = u;arrow.v = v;arrow.time = Time(p);arrow.WndSpd = WindSpd(p);
c=hsv(361);
hp(end+1) = patch(-u.*xscalefactor+Time(p),v.*yscalefactor+WindSpd(p),c(int16(WindDir(p)+1),:));
set(hp(end), 'ZData', ones(size(u))*p);
set(hp(end), 'UserData',arrow)
end
set(h,'UserData',hp)
set(zoom(h),'ActionPostCallback',@(src,event) ZoomCallback(src,event))
function ZoomCallback(src,event)
h = event.Axes;
hf = ancestor(h,'figure');
Patches = event.Axes.UserData;
WindowSize=get(hf,'Position');%[left bottom width height]
AxesSize=get(h,'Position');%[left bottom width height]
xscalefactor=1.5*diff(get(h,'xlim'))*0.03*WindowSize(4)/WindowSize(3)*AxesSize(4)/AxesSize(3);
yscalefactor=1.5*diff(get(h,'ylim'))*0.03;
for p = 1:length(Patches)
Patches(p).XData = -Patches(p).UserData.u * xscalefactor + Patches(p).UserData.time;
Patches(p).YData = Patches(p).UserData.v * yscalefactor + Patches(p).UserData.WndSpd;
end
end
end

その他の回答 (0 件)

カテゴリ

Help Center および File ExchangeGraphics Object Properties についてさらに検索

製品


リリース

R2022b

Community Treasure Hunt

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

Start Hunting!

Translated by