octave-task-tracker
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Octave-task-tracker] [task #14243] Rewrite legend.m


From: Rik
Subject: [Octave-task-tracker] [task #14243] Rewrite legend.m
Date: Mon, 11 Nov 2019 19:17:50 -0500 (EST)
User-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko

Follow-up Comment #13, task #14243 (project octave):

I'm starting to recall that legend is a very intricate function with lots of
small behavior deviations.  The good news is that the second patch is much
faster, and about the same timing as what we have today when used on ordinary
plots.

Some additional corner cases that I discovered.

Corner case #1 (incorrectly handling multiple text strings)


x = linspace (0, 2*pi, 100);
plot (x, sin (x), 'o-', x, cos (x), '*-')
legend ("sine", "cosine");
error: binary operator '/' not implemented for 'cell' by 'scalar' operations
error: called from
    legend>__legend_textitem_array__ at line 841 column 14
    legend>__legend_update_layout__ at line 632 column 31
    legend at line 201 column 5
    /tmp/oct-tKWrbi at line 3 column 6


Corner case #2 (labeling more than 20 data objects)

The behavior quoted below is from the existing legend implementation.  Like
Matlab, if the default number of labels is greater than 20 then it issues a
warning and only labels the first 20.  This behavior is no longer present in
the patch.


octave:2> plot (rand (30));
octave:3> legend ()
warning: legend: labeling only first 20 data objects
warning: called from
    legend at line 450 column 11


Corner case #3 (doesn't accept a numeric value for "location")

This could be behavior that we just drop.  Specifying location with a numeric
value has been deprecated for a very long time, and is no longer supported in
Matlab either.


octave:1> plot (1:10, 'o-')
octave:2> legend ('abc', 'location', 3)
error: set: invalid value for radio property "location"
error: called from
    legend at line 195 column 5


Corner case #3 (legend object created even when function fails)

This is a problem because it creates an axes object with tag "legend" which
leaves a white rectangle on the plot.  If input validation fails there should
be no object created.  Maybe you want to surround the construction of the axes
object with a try/catch block, and if there is an error delete the created
axes legend object and then re-throw the error.


octave:5> plot (1:10, 'o-')
octave:6> h = legend ('abc', 'location', 'foobar')
error: invalid value = foobar
error: called from
    legend at line 195 column 5
octave:7> findall (gcf, 'tag', 'legend')
ans = -5.6867


Corner case #4 ("bestoutside" location property not implemented)

Current legend.m implements "bestoutside" so we shouldn't regress on that
behavior.


octave:10> plot (1:10, 'o-')
octave:11> h = legend ('abc', 'location', 'bestoutside')
error: invalid value = bestoutside
error: called from
    legend at line 195 column 5


Corner case #5 ("none" location property not implemented)

"none" turns off the default positioning algorithm and allows the user to set
the location directly with the "position" property of the legend object.


octave:10> plot (1:10, 'o-')
octave:11> h = legend ('abc', 'location', 'none')
error: invalid value = none
error: called from
    legend at line 195 column 5


Comment #6 (Octave prefers no Camel Case properties)

The following properties should probably be all lower case to match Octave's
other properties. 


 AutoUpdate = off
 NumColumns = 1
 NumColumnsMode = auto


Corner case #7 (listener on "numcolumns"?)

The "numcolumns" property works correctly when the legend is created, but
subsequent changes to the property don't re-format the legend.


x = linspace(0,pi);
y1 = cos(x);
plot(x,y1)

hold on
y2 = cos(2*x);
plot(x,y2)

y3 = cos(3*x);
plot(x,y3)

y4 = cos(4*x);
plot(x,y4)
hold off

hl =
legend({'cos(x)','cos(2x)','cos(3x)','cos(4x)'},'Location','northwest','NumColumns',2);

set (hl, 'numcolumns', 1)


Corner case #8 (legend show)

When called with the argument "show", legend should display a legend as if it
was called with no arguments.  This produces "data1", "data2", etc.  Instead,
the new legend code is treating "show" as a text label rather than a command. 
legend ("toggle") produces the same behavior.


octave:106> plot (rand (3,2))
octave:107> legend show
warning: legend: ignoring extra objects.
warning: called from
    legend>__legend_parse_opts__ at line 555 column 9
    legend at line 125 column 8


Corner case #9 (horizontal spacing)

Try


demo legend 6


and you will see that the text and keys are crowded when compared to the
current version of legend.

Corner case #10 (property "textcolor" not implemented?)

Try 


demo legend 9


The text should be magenta color rather than black.

Corner case #11 (demo #15, #16 produce warnings when they shouldn't)


legend example 15:
 clf;
 x = linspace (0, 10);
 plot (x, x);
 hold on;
 stem (x, x.^2, "g");
 title ("First created object gets first label");
 legend ("linear");
 hold off;

warning: legend: ignoring extra objects.
warning: called from
    legend>__legend_parse_opts__ at line 555 column 9
    legend at line 125 column 8
    __demo__ at line 9 column 2
    demo at line 147 column 7


Corner case #12 (demo #22 produces only one label)

Try


demo legend 22


It should produce a legend with "sin (x)" and "cos (x)" as labels.

Corner case #13 (callback execution error when running demo #28)

This occurred while running all of the demos in legend.m


Press <enter> to continue: 
execution error in graphics callback function
legend example 28:
 clf;
 x = 0:10;
 y1 = rand (size (x));
 y2 = rand (size (x));
 [ax, h1, h2] = plotyy (x, y1, x, y2);
 ylabel (ax(1), {"Blue", "Y", "Axis"});
 title ('plotyy legend test #2: "westoutside" adjusts to ylabel');
 drawnow ();
 legend ([h1, h2], {"Blue", "Orange"}, "location", "westoutside");


Corner case #14 (demo #29 fails)

Try


legend demo 29


The rightside axes is messed up.

Corner case #15 (demo #30)

In the new legend code, the subplots are all set to the same size which
accommodates the largest of the text strings.  In previous versions of Octave,
in Matlab, each subplot is re-sized to fit the length of the label it is
paired with.

Try


legend demo 30


Comment #16 (demo #36 missing)

Demo #36 is missing in the new code.  I think it is correct to include it
because it shows that the problem has now been fixed.  If there is a
regression in behavior this demo will show it.

Comment #17 (performance measure)

I used demo #14 which does not include subplots to show that the new code can
be significantly slower even in an ordinary case.


tic; demo ("legend", 14); toc


Old code: 0.5 seconds
New code: 2.3 seconds

Comment #18 (length of lines in legend key)

I used


demo legend 3


and then measured the length of the lines in the legend key.  In the old code
it is about 20 pixels and in the new code it is about 27 pixels.  I like the
shorter length.  Matlab uses long line lengths and I think it is ugly.

Comment #19 (hide __appdata__ property?)

The __appdata__ property is for internal use only.  It should probably be a
hidden property so that users don't have to see all the guts of the
implementation.


octave:149> plot (1:10, 'o-')
octave:150> hl = legend ('abc')
hl = -102.66
octave:151> get (hl)
ans =

  scalar structure containing the fields:

    __appdata__ =

      scalar structure containing the fields:

        __axes_handle__ = -108.94
        __next_label_index__ = 1
        __peer_objects__ = -103.14
        __updating_layout__ = 0
        __original_looseinset__ =

           0.130000   0.110000   0.095000   0.075000

        __original_units__ = normalized
        __peer_axes_position__ =

            54.587    34.641   325.420   256.662

        __listeners__ =
        {
          [1,1] =
          {
            [1,1] = 1
            [1,2] = position
            [1,3] =
            {
              [1,1] = @__maybe_update_layout__
              [1,2] = -102.66
            }

          }

          [1,2] =
          {
            [1,1] = -108.94
            [1,2] = position
            [1,3] =
            {
              [1,1] = @__maybe_update_layout__
              [1,2] = -102.66
            }

          }

          [1,3] =
          {
            [1,1] = -108.94
            [1,2] = tightinset
            [1,3] =
            {
              [1,1] = @__maybe_update_layout__
              [1,2] = -102.66
            }

          }

          [1,4] =
          {
            [1,1] = -108.94
            [1,2] = colormap
            [1,3] =

@(hax) set (hl, "colormap", get (hax, "colormap"))

          }

          [1,5] =
          {
            [1,1] = -108.94
            [1,2] = fontsize
            [1,3] =

@(hax) set (hl, "fontsize", 0.9 * get (hax, "fontsize"))

          }

          [1,6] =
          {
            [1,1] = -108.94
            [1,2] = children
            [1,3] =
            {
              [1,1] = @__legend_autoupdate__
              [1,2] = -102.66
            }

          }

        }


    AutoUpdate = off
    edgecolor =

       0.1500   0.1500   0.1500

    interpreter = tex
    itemhitfcn = [](0x0)
    location = northeast
    NumColumns = 1
    NumColumnsMode = auto
    orientation = vertical
    string =
    {
      [1,1] = abc
    }


Corner case #20 ("EdgeColor" not implemented?)

Using this property doesn't seem to work anymore.


plot (1:10, 'o-');
hl = legend ('abc');
set (hl, 'edgecolor', 'r')




    _______________________________________________________

Reply to this item at:

  <https://savannah.gnu.org/task/?14243>

_______________________________________________
  Message sent via Savannah
  https://savannah.gnu.org/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]