make install_font() own function for clarity, add unit tests, work on Windows, macOS and Linux#1
make install_font() own function for clarity, add unit tests, work on Windows, macOS and Linux#1scivision wants to merge 8 commits intomarkagold1:masterfrom
Conversation
add continuous integration self-test
There was a problem hiding this comment.
Pull request overview
This PR refactors font installation into a dedicated install_font() helper, expands automated MATLAB unit tests for dark/undark/hand, and adds GitHub Actions CI to validate behavior across OSes.
Changes:
- Extract font installation/verification into
install_font.mand updatehand.mto check/register fonts more explicitly. - Add MATLAB
matlab.unittesttest classes fordark,undark, andhand, plus minor script/test tweaks for Octave/MATLAB compatibility. - Add
buildfile.mand a new GitHub Actions workflow to run code checks, font install, and unit tests.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
hand.m |
Adds fallback parameter and new font-check logic; refactors primitive styling logic. |
install_font.m |
New cross-platform font install helper (Windows/macOS/Linux) plus restart guidance. |
dark.m |
Refactors styling dispatch for MATLAB/Octave graphics objects. |
undark.m |
Suppresses global-variable analyzer warnings. |
test/TestHand.m |
Adds MATLAB unit tests for hand() styling and font behavior. |
test/TestDark.m |
Adds MATLAB unit tests for dark() styling across plot types. |
test/TestUndark.m |
Adds MATLAB unit tests for undark() restoration behavior. |
test_hand.m |
Uses 1j instead of i in a complex exponential example. |
buildfile.m |
Adds MATLAB buildtool plan and tasks (check/test/install). |
.github/workflows/ci.yml |
Adds CI workflow to run buildtool tasks on multiple OS/MATLAB versions. |
README.md |
Updates platform/version claims and documents buildtool usage; adds font install notes. |
.gitignore |
Ignores MATLAB .asv autosave files. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| switch class(h(kk)) | ||
| case 'matlab.graphics.chart.primitive.Line' | ||
| set(h(kk),'Color',colors(index,:)) | ||
| set(h(kk),'MarkerFaceColor',colors(index,:)) | ||
| set(h(kk),'MarkerEdgeColor',colors(index,:)) |
There was a problem hiding this comment.
Replacing isa(...) with switch class(...) means subclasses of these graphics primitives will no longer be styled. If you still want to cover derived chart objects, use isa checks instead of exact class matches.
| ok = ~system(cmd); | ||
| elseif ismac() | ||
| disp('Install XKCD Script with Font Book') | ||
| ok = ~system(sprintf('open -a "Font Book" %s', xkcd_ttf)); |
There was a problem hiding this comment.
The macOS install command does not quote the font path. If xkcd_ttf contains spaces, open -a "Font Book" ... will fail. Wrap the path in quotes and escape as needed when building the command string.
| ok = ~system(sprintf('open -a "Font Book" %s', xkcd_ttf)); | |
| ok = ~system(sprintf('open -a "Font Book" "%s"', xkcd_ttf)); |
| estr = sprintf('%s See help graphics_toolkit for more information.\n', estr); | ||
| error('%s', estr) | ||
| else | ||
| estr = sprintf('%s Restart GNU OCtave to refresh font list.\n', estr); |
There was a problem hiding this comment.
There is a typo in the restart message: "GNU OCtave" should be "GNU Octave".
| estr = sprintf('%s Restart GNU OCtave to refresh font list.\n', estr); | |
| estr = sprintf('%s Restart GNU Octave to refresh font list.\n', estr); |
| hand() | ||
|
|
||
| ax = gca; | ||
| if getenv('CI') == "true" |
There was a problem hiding this comment.
if getenv('CI') == "true" will fail because getenv returns a char vector in MATLAB; == with a string scalar is not a valid comparison here. Use strcmp(getenv('CI'), 'true') (or convert with string(getenv('CI')) == "true").
| if getenv('CI') == "true" | |
| if strcmp(getenv('CI'), 'true') |
|
|
||
| HAND renders a plot in a theme that emulates a hand-drawn plot in an engineering notebook. It works the same way as DARK, simply run the command "hand" on your current plot to render it in a hand-drawn thme. Once converted you may continue to modify properties, zoom, and pan as desired. | ||
| HAND renders a plot in a theme that emulates a hand-drawn plot in an engineering notebook. | ||
| It works the same way as DARK, simply run the command "hand" on your current plot to render it in a hand-drawn thme. |
There was a problem hiding this comment.
Typo: "thme" should be "theme".
| It works the same way as DARK, simply run the command "hand" on your current plot to render it in a hand-drawn thme. | |
| It works the same way as DARK, simply run the command "hand" on your current plot to render it in a hand-drawn theme. |
| function hand(colors_in, fallback) | ||
| % Usage: hand(colors_in) | ||
| % | ||
| % Hand-drawn-theme plots. |
There was a problem hiding this comment.
hand now accepts a second argument (fallback), but the usage line and parameter docs still only describe colors_in. Please update the header comment to document the new parameter and its behavior (e.g., how to disable fallback / force font install).
| function [font_name, font_size, font_angle] = check_font(fallback) | ||
| font_angle = 'normal'; | ||
| font_size = 20; | ||
| font_name = 'xkcd Script'; |
There was a problem hiding this comment.
check_font() calls listfonts(), which is not available in GNU Octave. Since hand() calls check_font() regardless of isoctave(), this will break Octave support. Please branch on isoctave() and use an Octave-compatible font detection strategy (or skip the font check in Octave).
| font_name = 'xkcd Script'; | |
| font_name = 'xkcd Script'; | |
| % In GNU Octave, listfonts() is not available; skip the font check there. | |
| if isoctave() | |
| % Octave will use 'xkcd Script' if installed, or fall back to its default. | |
| warning('Skipping font availability check on GNU Octave; using font "%s" if available.', font_name); | |
| return; | |
| end |
| fonts = {'Segoe Print', 'Pacifico', 'Times', 'default'}; | ||
| for i = 1:length(fonts) | ||
| if any(ismember(fonts_avail, fonts{i})) | ||
| font_name = fonts{i}; | ||
| break |
There was a problem hiding this comment.
If none of the fallback fonts are found, font_name remains 'xkcd Script' even though it’s missing, which can cause later font-setting to fail. Ensure this code always assigns a safe default (e.g., 'default') when no listed fallback font is available.
| HAND has been tested with MATLAB R2023b and R2026a and | ||
| GNU Octave versions 7.1.0, 8.3.0, 9.1.0, and 11.1.0 running on Windows 10, macOS, Linux RHEL 8 and Ubuntu 22.04. | ||
| HAND bundles the excellent "xkcd Script" font from [xkcd-font](https://github.com/ipython/xkcd-font). | ||
| Similar to DARK, HAND is coded using funtions native to MATLAB and GNU Octave without any dependencies on toolboxes or packages, making it highly portable. |
There was a problem hiding this comment.
Typo in README: "funtions" should be "functions".
| Similar to DARK, HAND is coded using funtions native to MATLAB and GNU Octave without any dependencies on toolboxes or packages, making it highly portable. | |
| Similar to DARK, HAND is coded using functions native to MATLAB and GNU Octave without any dependencies on toolboxes or packages, making it highly portable. |
| push: | ||
| paths: | ||
| - "**.m" | ||
| - ".github/workflows/ci.yml" |
There was a problem hiding this comment.
This workflow runs only on push. If the intent is to validate pull requests, add a pull_request trigger as well so CI executes for PRs before merge.
| - ".github/workflows/ci.yml" | |
| - ".github/workflows/ci.yml" | |
| pull_request: | |
| paths: | |
| - "**.m" | |
| - ".github/workflows/ci.yml" |
The buildfile.m is optional, uniform way to handle install, check and test.
I realize this is a lot of changes, but most are emphasizing the automated tests. The important feature is that your functions work across Octave and Matlab on macOS, Windows, and Linux now--the tests help validate this claim in automated fashion!