Skip to content

Initialise create.legend.labels so guideline = FALSE draws its legend - #60

Merged
braverock merged 1 commit into
braverock:masterfrom
sstoeckl:fix-efficient-frontier-compare-legend
Sep 19, 2026
Merged

braverock merged 1 commit into
braverock:masterfrom
sstoeckl:fix-efficient-frontier-compare-legend

Conversation

@sstoeckl

@sstoeckl sstoeckl commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

chart.EfficientFrontierCompare() stops with

object 'create.legend.labels' not found

whenever guideline = FALSE and legend.labels is left at its default. Nothing
is drawn; the error comes from the legend block at the end.

create.legend.labels is built only inside the guideline block, and then used
unconditionally:

if(guideline){
  ...
  create.legend.labels <- paste("% Increase in Risk =", ...)
  create.legend.labels <- append(create.legend.labels, paste("% Increase in Return =", ...))
}
...
if(is.null(legend.labels)){
  legend.labels <- paste("min", match.col, "Portfolio")
  legend.labels <- append(legend.labels, create.legend.labels)
}

guideline defaults to TRUE only when match.col has two entries, so the
failing path is the ordinary one for a single frontier, and it is reachable with
two as well by passing guideline = FALSE.

The change

One line: create.legend.labels <- NULL before the guideline block, with a
comment saying why.

NULL rather than character(0) or a placeholder, because append() drops it.
That leaves one label per match.col, which is exactly the number of colours,
line types and widths the guideline = FALSE branch sets a few lines above, so
the legend stays consistent with the lines it describes.

Measured

Four edhec columns, match.col = c("StdDev", "ES"), labels captured by
tracing graphics::legend, so this is what the function passes rather than what
it looks like it should:

master this branch
guideline = TRUE 4 labels, 4 colours identical
guideline = FALSE error, nothing drawn 2 labels, 2 colours

With guideline = TRUE both builds pass the same four labels: min StdDev Portfolio, min ES Portfolio, % Increase in Risk = 10.44, % Increase in Return = 11.78.

Tests

None added, none changed. tests/testthat/test-charts-roi.R already asserts
this behaviour in two tests, chart.EfficientFrontierCompare: guideline=FALSE produces no error and chart.EfficientFrontierCompare: legend.loc non-NULL branch produces no error, and both currently fail.

test-charts-roi.R PASS FAIL
master 67 2
this branch 69 0

Test suite

PASS FAIL ERROR
master 3550 2 2
this branch 3552 0 2

No failures left. The two errors are the objective() tests in
test-objective-branches.R, which #61 fixes; measured there, that file
goes to 33 passing with none. The two changes touch different files, so between
them the four problems run-all.R reports are accounted for.

Why this one and #61 are worth taking first

R-CMD-check and test-coverage have both been red on master since 24 July,
and both die at the same step, running the tests in 'run-all.R' failed. What
run-all.R reports there is four problems: the two fixed here, and two in
test-objective-branches.R, where ROI masks objective() in a full-suite
run. #61 fixes those.

With both merged, that step passes and the pipeline is green again. I can only
see that the workflows stop at that step, so if something else is broken behind
it, it is hidden by these four rather than absent.

This matters for the five pull requests that are already open, because their
checks are red for this reason and not for theirs. They do not need rebasing:
the workflows run on pull_request and actions/checkout@v4 checks out the
merge commit, so once master carries these two fixes, re-running the jobs on
each of them is enough.

Scope

One file, 7 insertions, of which 6 are the comment. This change stands on its
own and does not depend on any other.

🤖 Generated with Claude Code

chart.EfficientFrontierCompare() builds create.legend.labels only inside the
guideline block, and then uses it unconditionally:

  if(guideline){
    ...
    create.legend.labels <- paste("% Increase in Risk =", ...)
    create.legend.labels <- append(create.legend.labels, paste("% Increase in Return =", ...))
  }
  ...
  if(is.null(legend.labels)){
    legend.labels <- paste("min", match.col, "Portfolio")
    legend.labels <- append(legend.labels, create.legend.labels)
  }

With guideline = FALSE and legend.labels left at its default, the function
stops with

  object 'create.legend.labels' not found

before anything is drawn. guideline defaults to TRUE only when two entries are
given in match.col, so the failing path is the ordinary one for a single
frontier, and it is also reachable with two.

NULL is the right empty value rather than character(0) or a placeholder:
append() drops it, which leaves one label per match.col, and that is exactly
the number of colours, line types and widths the guideline = FALSE branch sets
a few lines above. Measured, on four edhec columns with two match.col:

  guideline = TRUE    master: 4 labels, 4 colours    this branch: identical
                      min StdDev Portfolio | min ES Portfolio |
                      % Increase in Risk = 10.44 | % Increase in Return = 11.78
  guideline = FALSE   master: error                  this branch: 2 labels, 2 colours
                      min StdDev Portfolio | min ES Portfolio

The labels were captured by tracing graphics::legend, so this is what the
function actually passes, not what it looks like it should.

No test is added or changed. tests/testthat/test-charts-roi.R already asserts
this exact behaviour in two tests, "guideline=FALSE produces no error" and
"legend.loc non-NULL branch produces no error", and both currently fail. That
file goes from 67 passing with 2 failures to 69 passing with none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change resolves the reported error while preserving existing guideline behavior.

Pull request overview

Fixes chart.EfficientFrontierCompare() when guideline = FALSE and default legend labels are used.

Changes:

  • Initializes create.legend.labels to NULL.
  • Preserves guideline labels and keeps legends aligned with plotted frontiers.
File summaries
File Description
R/charts.efficient.frontier.R Prevents the missing-object error during legend construction.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@braverock
braverock merged commit c44f111 into braverock:master Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants