@@ -227,7 +227,7 @@ function renderTag_(obj)
227227
228228 % Outer 5-row grid: title + table + sparkline + range-label + button.
229229 g = uigridlayout(obj .hContent_ , [5 1 ]);
230- g.RowHeight = {28 , ' 1x' , 78 , 14 , 32 };
230+ g.RowHeight = {28 , ' 1x' , 92 , 14 , 32 };
231231 g.ColumnWidth = {' 1x' };
232232 g.Padding = [16 16 16 16 ]; g.RowSpacing = 6 ;
233233 g.BackgroundColor = t .WidgetBackground ;
@@ -350,21 +350,27 @@ function renderTag_(obj)
350350
351351 function renderSparkline_(obj , tag )
352352 % RENDERSPARKLINE_ Render the trailing SparkWindowSec_ window of (X,Y).
353- % Filters samples to the last 30 minutes, then plots. Stores
354- % hSparkLine_ so refreshSparklineInPlace_ can update in place.
353+ % Shows 2-point X-axis ticks (start / end time) and 2-point Y-axis
354+ % ticks (min / max value). Stores hSparkLine_ so refreshSparklineInPlace_
355+ % can update XData/YData and tick labels in place.
355356 t = obj .Theme_ ;
356357 try
357358 if ~ismethod(tag , ' getXY' ); obj .renderNoData_(' No data' ); return ; end
358359 [tv , y ] = tag .getXY();
359360 if isempty(tv ) || isempty(y ); obj .renderNoData_(' No data' ); return ; end
360361 [tv , y ] = obj .windowSparkData_(tv , y );
361362 obj.hSparkAxes_ = axes(' Parent' , obj .hSparkPanel_ , ...
362- ' Units' , ' normalized' , ' Position' , [0 0 1 1 ], ...
363- ' Color' , t .WidgetBackground , ' XColor' , t .WidgetBackground , ...
364- ' YColor' , t .WidgetBackground , ' Box' , ' off' , ' XTick' , [], ' YTick' , []);
363+ ' Units' , ' normalized' , ' Position' , [0.22 0.26 0.75 0.70 ], ...
364+ ' Color' , t .WidgetBackground , ...
365+ ' XColor' , t .PlaceholderTextColor , ...
366+ ' YColor' , t .PlaceholderTextColor , ...
367+ ' Box' , ' off' , ' FontSize' , 8 , ...
368+ ' TickLength' , [0.005 0.005 ], ...
369+ ' TickDir' , ' out' );
365370 obj.hSparkLine_ = plot(obj .hSparkAxes_ , tv , y , ' -' , ...
366371 ' Color' , t.LineColors{1 }, ' LineWidth' , 1 );
367372 obj .fitSparkAxes_();
373+ obj .updateSparkTicks_(tv , y );
368374 try ; obj.hSparkAxes_.Toolbar.Visible = ' off' ; catch ; end
369375 try ; obj.hSparkAxes_.Interactions = []; catch ; end
370376 obj .updateRangeLabel_(tv );
@@ -373,6 +379,65 @@ function renderSparkline_(obj, tag)
373379 end
374380 end
375381
382+ function updateSparkTicks_(obj , tv , y )
383+ % UPDATESPARKTICKS_ Set 2-point X (start/end time) and Y (min/max) ticks.
384+ if isempty(obj .hSparkAxes_ ) || ~isvalid(obj .hSparkAxes_ ); return ; end
385+ if isempty(tv ) || isempty(y ); return ; end
386+ try
387+ if numel(tv ) >= 2 && tv(1 ) ~= tv(end )
388+ obj.hSparkAxes_.XTick = [tv(1 ), tv(end )];
389+ obj.hSparkAxes_.XTickLabel = {obj .formatXTick_(tv(1 )), obj .formatXTick_(tv(end ))};
390+ else
391+ obj.hSparkAxes_.XTick = tv(1 );
392+ obj.hSparkAxes_.XTickLabel = {obj .formatXTick_(tv(1 ))};
393+ end
394+ yMin = min(y ); yMax = max(y );
395+ if yMin < yMax
396+ obj.hSparkAxes_.YTick = [yMin , yMax ];
397+ obj.hSparkAxes_.YTickLabel = {obj .formatYTick_(yMin ), obj .formatYTick_(yMax )};
398+ else
399+ obj.hSparkAxes_.YTick = yMin ;
400+ obj.hSparkAxes_.YTickLabel = {obj .formatYTick_(yMin )};
401+ end
402+ catch
403+ end
404+ end
405+
406+ function txt = formatXTick_(~, x )
407+ % FORMATXTICK_ Time-format an X value (posixtime / datenum / seconds).
408+ try
409+ if x > 1e9 % posixtime (Unix epoch seconds)
410+ txt = char(datetime(x , ' ConvertFrom' , ' posixtime' , ...
411+ ' Format' , ' HH:mm:ss' ));
412+ elseif x > 7e5 % MATLAB datenum (days since 0000-01-01)
413+ txt = datestr(x , ' HH:MM:SS' );
414+ elseif x >= 60
415+ mm = floor(x / 60 ); ss = mod(x , 60 );
416+ txt = sprintf(' %d :%05.2f ' , mm , ss );
417+ else
418+ txt = sprintf(' %.1f s' , x );
419+ end
420+ catch
421+ txt = sprintf(' %g ' , x );
422+ end
423+ end
424+
425+ function txt = formatYTick_(~, y )
426+ % FORMATYTICK_ Compact numeric format for the Y min/max ticks.
427+ a = abs(y );
428+ if a == 0
429+ txt = ' 0' ;
430+ elseif a >= 1000 || a < 0.01
431+ txt = sprintf(' %.2g ' , y );
432+ elseif a >= 100
433+ txt = sprintf(' %.0f ' , y );
434+ elseif a >= 10
435+ txt = sprintf(' %.1f ' , y );
436+ else
437+ txt = sprintf(' %.2f ' , y );
438+ end
439+ end
440+
376441 function [tv , y ] = windowSparkData_(obj , tv , y )
377442 % WINDOWSPARKDATA_ Filter (X,Y) to the trailing SparkWindowSec_ horizon.
378443 % Assumes X is in seconds (datenum-day fallback handled below by
@@ -435,6 +500,7 @@ function refreshSparklineInPlace_(obj, tag)
435500 obj.hSparkLine_.XData = tv ;
436501 obj.hSparkLine_.YData = y ;
437502 obj .fitSparkAxes_();
503+ obj .updateSparkTicks_(tv , y );
438504 obj .updateRangeLabel_(tv );
439505 catch
440506 end
0 commit comments