このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。
2 つの対話型プロットを含むチャート クラス
次の例では、対話型機能をもつ 2 つの座標軸を使用して、timetable データを可視化するためのクラスを定義する方法を示します。上の座標軸では、x 次元に沿ってのパニングとズームが有効になっているため、ユーザーは関心領域を調べることができます。下の座標軸には、時間範囲全体にわたるプロットが表示されます。また、下の座標軸には薄い青の時間枠も表示され、これは上の座標軸の時間範囲を表します。このクラスは以下のプロパティ、メソッドおよびローカル関数を定義します。
プロパティ:
Data
- timetable を格納するパブリックな依存プロパティ。TimeLimits
- 上の座標軸の範囲と、下の座標軸の時間枠の幅を設定するパブリック プロパティ。SavedData
- ユーザーによるチャートのインスタンスの保存と読み込み、およびデータの保持を可能にするための保護されたプロパティ。TopAxes
、BottomAxes
- axes オブジェクトを格納するプライベート プロパティ。TopLine
、BottomLine
- line オブジェクトを格納するプライベート プロパティ。TimeWindow
- 下の座標軸に表示される patch オブジェクト。上の座標軸の時間範囲を表します。
メソッド:
set.Data
、get.Data
- ユーザーによるチャートのインスタンスの保存と読み込み、およびデータの保持を可能にします。setup
- チャートの作成時に 1 回実行されます。レイアウトと座標軸、line オブジェクト、および patch オブジェクトを構成します。update
-setup
メソッドの後と、ユーザーがチャートの 1 つ以上のプロパティを変更した後に実行されます。panZoom
- ユーザーが上の座標軸内でパニングまたはズームを行うとチャートの時間範囲を更新します。これにより、新しい範囲を反映するように時間枠が更新されます。click
- ユーザーが下の座標軸をクリックすると時間範囲を再計算します。
ローカル関数:
updateDataTipTemplate
-update
メソッド内から呼び出されます。timetable の変数に対応する行をデータヒントに作成します。mustHaveOneNumericVariable
—Data
プロパティを検証します。この関数は、ユーザーが指定した timetable に少なくとも 1 つの数値変数があることを確認します。
クラスを定義するには、以下のコードをエディターにコピーし、書き込み可能なフォルダーに TimeTableChart.m
という名前で保存します。
classdef TimeTableChart < matlab.graphics.chartcontainer.ChartContainer properties (Dependent) Data timetable {mustHaveOneNumericVariable} = ... timetable(datetime.empty(0,1),zeros(0,1)) end properties TimeLimits (1,2) datetime = [NaT NaT] end properties (Access = protected) SavedData timetable = timetable(datetime.empty(0,1),zeros(0,1)) end properties (Access = private, Transient, NonCopyable) TopAxes matlab.graphics.axis.Axes TopLine matlab.graphics.chart.primitive.Line BottomAxes matlab.graphics.axis.Axes BottomLine matlab.graphics.chart.primitive.Line TimeWindow matlab.graphics.primitive.Patch end methods function set.Data(obj, tbl) % Reset the time limits if the row times have changed. oldTimes = obj.SavedData.Properties.RowTimes; newTimes = tbl.Properties.RowTimes; if ~isequal(oldTimes, newTimes) obj.TimeLimits = [NaT NaT]; end % Store the new table. obj.SavedData = tbl; end function tbl = get.Data(obj) tbl = obj.SavedData; end end methods (Access = protected) function setup(obj) % Create two axes. The top axes is 3x taller than bottom axes. tcl = getLayout(obj); tcl.GridSize = [4 1]; obj.TopAxes = nexttile(tcl, 1, [3 1]); obj.BottomAxes = nexttile(tcl, 4); % Add a shared toolbar on the layout, which removes the % toolbar from the individual axes. axtoolbar(tcl, 'default'); % Create one line to show the zoomed-in data. obj.TopLine = plot(obj.TopAxes, NaT, NaN); % Create one line to show an overview of the data, and disable % HitTest so the ButtonDownFcn on the bottom axes works. obj.BottomLine = plot(obj.BottomAxes, NaT, NaN, ... 'HitTest', 'off'); % Create a patch to show the current time limits. obj.TimeWindow = patch(obj.BottomAxes, ... 'Faces', 1:4, ... 'Vertices', NaN(4,2), ... 'FaceColor', obj.TopLine.Color, ... 'FaceAlpha', 0.3, ... 'EdgeColor', 'none', ... 'HitTest', 'off'); % Constrain axes panning/zooming to only the X-dimension. obj.TopAxes.Interactions = [ ... dataTipInteraction; panInteraction('Dimensions','x'); rulerPanInteraction('Dimensions','x'); zoomInteraction('Dimensions','x')]; % Disable pan/zoom on the bottom axes. obj.BottomAxes.Interactions = []; % Add a listener to XLim to respond to zoom events. addlistener(obj.TopAxes, 'XLim', 'PostSet', @(~, ~) panZoom(obj)); % Add a callback for clicks on the bottom axes. obj.BottomAxes.ButtonDownFcn = @(~, ~) click(obj); end function update(obj) % Extract the time data from the table. tbl = obj.Data; t = tbl.Properties.RowTimes; % Extract the numeric variables from the table. S = vartype('numeric'); numericTbl = tbl(:,S); % Update the data on both lines. set([obj.BottomLine obj.TopLine], 'XData', t, 'YData', numericTbl{:,1}); % Create a dataTipTextRow for each variable in the timetable. updateDataTipTemplate(obj.TopLine, tbl) % Update the top axes limits. obj.TopAxes.YLimMode = 'auto'; if obj.TimeLimits(1) < obj.TimeLimits(2) obj.TopAxes.XLim = obj.TimeLimits; else % Current time limits are invalid, so set XLimMode to auto and % let the axes calculate limits based on available data. obj.TopAxes.XLimMode = 'auto'; obj.TimeLimits = obj.TopAxes.XLim; end % Update time window to reflect the new time limits. xLimits = ruler2num(obj.TimeLimits, obj.BottomAxes.XAxis); yLimits = obj.BottomAxes.YLim; obj.TimeWindow.Vertices = [xLimits([1 1 2 2]); yLimits([1 2 2 1])]'; end function panZoom(obj) % When XLim on the top axes changes, update the time limits. obj.TimeLimits = obj.TopAxes.XLim; end function click(obj) % When clicking on the bottom axes, recenter the time limits. % Find the center of the click using CurrentPoint. center = obj.BottomAxes.CurrentPoint(1,1); % Convert from numeric units into datetime using num2ruler. center = num2ruler(center, obj.BottomAxes.XAxis); % Find the width of the current time limits. width = diff(obj.TimeLimits); % Recenter the current time limits. obj.TimeLimits = center + [-1 1]*width/2; end end end function updateDataTipTemplate(obj, tbl) % Create a dataTipTextRow for each variable in the timetable. timeVariable = tbl.Properties.DimensionNames{1}; rows = dataTipTextRow(timeVariable, tbl.(timeVariable)); for n = 1:numel(tbl.Properties.VariableNames) rows(n+1,1) = dataTipTextRow(... tbl.Properties.VariableNames{n}, tbl{:,n}); end obj.DataTipTemplate.DataTipRows = rows; end function mustHaveOneNumericVariable(tbl) % Validation function for Data property. S = vartype('numeric'); if width(tbl(:,S)) < 1 error('TimeTableChart:InvalidTable', ... 'Table must have at least one numeric variable.') end end
クラス ファイルを保存した後、チャートのインスタンスを作成します。ここでは、チャートを使用して、ある年の数週間について自転車の交通量データを調べます。
bikeTbl = readtimetable('BicycleCounts.csv'); bikeTbl = bikeTbl(169:8954,:); tlimits = [datetime(2015,8,6) datetime(2015,8,27)]; TimeTableChart('Data',bikeTbl,'TimeLimits',tlimits);