patchGNU Octave - Patches: patch #7752, Add support for saving and loading...


patch #7752: Add support for saving and loading figures

Submitted by:  Pantxo Diribarne <pantxo>
Submitted on:  Mon 26 Mar 2012 08:09:05 PM UTC  
Category:  None Priority:  5 - Normal
Status:  Ready For Test Privacy:  Public
Assigned to:  None Open/Closed:  Closed

Add a New Comment (Rich Markup)

You are not logged in

Please log in, so followups can be emailed to you.


( Jump to the original submission)

Tue 17 Jul 2012 12:50:56 AM UTC, comment #25: 


After some some minor editing, I pushed this change.

Ben Abbott <bpabbott>
Project Member
Sun 08 Jul 2012 12:45:58 PM UTC, comment #24: 

Here is a new set of files (
 - hdl2struct is unchanged
 - struct2hdl now accepts a third boolean argument to enable the use of high level function for legends, colorbars and hggroups. default is false (any callback/listener is lost).
 - copyobj uses the above default behaviour, so that legends and colobars become simple axes and hggroups are built from scratch and listeners (e.g baseline for stemp/bar ... is lost).

 - Using gnuplot backend, the final position of axes is not set properly
 - The first time hdl2struct/copyobj is used to copy patch objects, an error occurs, raised by "patch" function (see demo "copyobj" 1). Try again and it works.

(file #26164)

Pantxo Diribarne <pantxo>
Project Member
Mon 21 May 2012 10:13:13 PM UTC, comment #23: 

I'll go for the no high level of bug reports (hope so).


Pantxo Diribarne <pantxo>
Project Member
Mon 21 May 2012 09:47:31 PM UTC, comment #22: 

Sure, that sounds reasonable.

Ok, for the default to be no high level functions ?

I don't have a strong opinion on that. But if high level functions are avoided I expect there will be fewer bug reports ;-)


Ben Abbott <bpabbott>
Project Member
Mon 21 May 2012 09:32:55 PM UTC, comment #21: 

I still had in mind that I wanted to be able to save a figure and to work on it again after reloading. So, the reason why I use high level functions for hggroups, legend and colorbars is to retrieve as much listeners/callback functions as possible.

On the other hand copyobj seams to copy objects without previous links between them. To keep both functionnalities I will add an argument in struct2hdl.m to specify wether highlevel functions should be used. This flag will be set false by copyobj, and true by users interested in having a legend instead of an UFA (unidentified flying axes)

Does it seam reasonnable to you?

Pantxo Diribarne <pantxo>
Project Member
Fri 18 May 2012 05:55:31 PM UTC, comment #20: 

I notice you don't use the hggroup() function in struct2hdl(). Creating a hggroup() object isn't very obvious. In the event, it is helpful, the code below will produce an hggroup with patches and lines as children.

figure (1)
hb = bar (rand (1, 5));
hold all
hp = findobj (hb, "type", "patch");
hl = plot (rand (5));
hg = hggroup ();
set (hp, "Parent", hg)
set (hl, "Parent", hg)
delete (hb)

Also, to simplify maintenance, high level plot functions could be avoided.

For example, if a new error bar format is added to errorbar.m then struct2hdl will be broken.

That would imply that the cases to be considered are


Or maybe there is there something I'm missing? Is there are reason why high level plot functions are needed?

Ben Abbott <bpabbott>
Project Member
Fri 18 May 2012 08:53:03 AM UTC, comment #19: 

Attached a new set of files.

hdl2struct.m : unchanged
copyobj.m :
 - now accepts legends or colorbars as input handle. They are treated as simple axes.
 - now accepts hggroup as valid parent for lines, patches ...


struct2hdl.m :
 - stem, area, contour3 hggroups support have been added
 - legend visibility and textposition are now supported

It is now possible to save/restore the whole root environnement doing:

str = hdl2struct (0);
save "myfig_group.struct" -struct str

str = load ("myfig_group.struct");
h = struct2hdl (str);

 - user defined hggroup won't be recognized so that incoherent behaviour like the one bellow are expected :
figure (1);
li = plot (1:10);
figure (2);
hg = hggroup ();
copyobj (li, hg);
figure (3);
copyobj (hg, 3);
==>error: struct2hdl: couldn't guess the type of hggroup

 - produced colorbars do not behave as original. Manipulating them can even crash octave.


(file #25877)

Pantxo Diribarne <pantxo>
Project Member
Fri 20 Apr 2012 05:41:38 PM UTC, comment #18: 

The files produced by the script below are attached. It looks like none of the listeners/callbacks are active for the colorbar.

figure (1)
contour (peaks)
h1 = colorbar ();
figure (2)
h2 = copyobj (h1, gcf ())
set (h2, 'Location', 'WestOutside')

print_pdf (1, 'colorbar1.pdf')
print_pdf (2, 'colorbar2.pdf')

(file #25695, file #25696)

Ben Abbott <bpabbott>
Project Member
Fri 20 Apr 2012 05:23:44 PM UTC, comment #17: 

From the two tests, it appears that Matlab's copied objects no longer have any active listeners/callbacks.

So, I think it is ok to just copy both legends and colorbars as if they were normal axes ... but I'll test the colorbar just to be sure.

Ben Abbott <bpabbott>
Project Member
Fri 20 Apr 2012 04:33:29 PM UTC, comment #16: 

This test shows that we should be able to copy a legend as an ordinary axes to be consistant with ML. I think it's reasonnable and will implement that.

About listener/callback I am not shure I understand the test :
the fact that setting properties of the original object does not modify the copy is what I expect. The contrary would have surprised me. Can you explain me.

I will submit a new set of files in the next couple of days.

Pantxo Diribarne <pantxo>
Project Member
Thu 19 Apr 2012 07:52:51 PM UTC, comment #15: 

I just did a quick test in Matlab.

figure (1)
a = plot (rand (3));
h = legend ({'line 1', 'line 2', 'line 3'});
figure (2)
copyobj (h, 2)
set (a, 'linestyle', '--')
copyobj (1, 0)
b = findobj (gcf (), 'type', 'axes');
c = findobj (b(2), 'type', 'line');
set (c, 'linestyl', '-')

print -f1 figure1.eps -depsc
print -f2 figure2.eps -depsc
print -f3 figure3.eps -depsc

Then I converted the eps-files to pdf-files, which I've attached. It appears, from these example, that the listeners/callbacks are not active in the copied version.

(file #25689, file #25690, file #25691)

Ben Abbott <bpabbott>
Project Member
Thu 05 Apr 2012 06:05:40 PM UTC, comment #14: 

I don't think Octave or Matlab is able to tell us what listeners are present.

You may be able to infer the class type of each property by examining the output form "p = set (h)".

Ben Abbott <bpabbott>
Project Member
Thu 05 Apr 2012 04:26:33 PM UTC, comment #13: 

Double negative :
- root object can't be copied at the moment, but I think it should be fairly straighforward. It would make sense if one wants to retrieve all the figures he had in his work space.
- hggroup currently can't be parent.

I have chosen to try to guess the way hggroups where built by the user so that I can use high level functions (bar, contour ...) to rebuild theim. If the search criteria are not met, hdl2struct throws an error. The advantage of this method is obvious : special properties and listeners are automatically created. Next step I envisaged was to rebuild, child after child, the hggroup.

The difficulty is that I will have to add missing properties, and to store their type (radio or string, ...), but also listeners. What would be the best way to retrieve a property type? Is there a way to retrieve set listeners? Do you see an other way?

Pantxo Diribarne <pantxo>
Project Member
Thu 05 Apr 2012 03:51:02 PM UTC, comment #12: 

I encourage you to extend matlab compatibility to do the reasonable thing. I think supporting "hout = copyobj (hin)" is a reasonable extension.

I haven't looked to see if your implementation will handle it, but for objects that aren't axes or figures, please try to allow the parent to be an hggroup.

Also, for hdl2struct, are you able to copy the root object, and then restore it with struct2hdl ?

Ben Abbott <bpabbott>
Project Member
Thu 05 Apr 2012 02:37:44 PM UTC, comment #11: 

I had not read the ML documentation for copyobj, sorry. In ML, if one wants to copy a whole figure I suppose he has to specify 0 (root) as parent. I am not sure I understood your last sentence. May I overload copyobj so that hout = copyobj (hin) AND hout = copyobj (hin, hpar) are allowed? Or should I strictly stick to Matlab compatibility?

Pantxo Diribarne <pantxo>
Project Member
Wed 04 Apr 2012 10:47:28 PM UTC, comment #10: 

I made some more code style changes, and produced a preliminary changeset (files attached).

Then I noticed that copyobj doesn't accept the handle for the parent object.

This should be fixed before being committed. However, I don't see a problem with selecting a reasonable default if the parent's handle isn't present.

(file #25582)

Ben Abbott <bpabbott>
Project Member
Wed 04 Apr 2012 12:22:21 PM UTC, comment #9: 

I have moved some code from setprops to createhg, in hdl2struct.m, trying to stick to Octave syntax rules.

(file #25564)

Pantxo Diribarne <pantxo>
Project Member
Wed 04 Apr 2012 12:33:17 AM UTC, comment #8: 

I looked over the files and made some cosmetic changes to the code so that it would be more consistent with the style used for Octave's other m-files.

  1. Removed the separating lines in struct2hdl.m

- ################################################################

  1. Added a space between function names and (...)

- hdl2struct(lg);
+ hdl2struct (lg);

  1. Eliminated the "try" block in hdl2struct (getprops) using isprop().
  1. Avoided using "\" for line continuation.
  1. Removed references to other demos, as they may change, don't rely upon the demos from other functions.
  1. Modified the demos to be consistent with Matlab syntax. This allow us to run the demos with Octave and Matlab and compare the results.

I've attached "". Please the changes. If everything is ok, I think it is time to prepare a changeset.

(file #25556)

Ben Abbott <bpabbott>
Project Member
Tue 03 Apr 2012 03:30:05 PM UTC, comment #7: 

To avoid duplicate efforts ... I plan to go over this later today. If someone else gets to it earlier, please comment here. Thanks!

Ben Abbott <bpabbott>
Project Member
Tue 03 Apr 2012 01:56:46 PM UTC, comment #6: 

I added a "copyobj" function which simply performs successive "hdl2struct" and "struct2hdl" calls (see demos).

The help text of "hdl2struct" was modified for consistancy : input handle must be one of "figure" or "axes".


I added support for legends, colorbars and some hggroup objects : errorbar, bar, contour, quiver.

(file #25554)

Pantxo Diribarne <pantxo>
Project Member
Fri 30 Mar 2012 09:01:15 AM UTC, comment #5: 

Thanks for the texinfo help text.
About the function name : for the moment I'll keep hdl2struct/struct2hdl as it is more general. It can do fig->struct/struct->fig but also object->struct/struct/(new or provided)fig. I will thus add copyobj.m function.

About adding the possibility to specify the destination parent handle I think I'll go for it as it's pretty "natural" (this word makes sense in french). It implies to verify consistancy between parent and structure content.

I am currently implementing minimal hggroup support (errorbar, contour, bar, quiver). I will submit a version by the end of the week-end.

Pantxo Diribarne <pantxo>
Project Member
Fri 30 Mar 2012 03:17:21 AM UTC, comment #4: 

Another thought. Rather than worrying about copyobj(), another option is to rename the functions to fig2struct.m and struct2fig.m

Ben Abbott <bpabbott>
Project Member
Fri 30 Mar 2012 02:28:30 AM UTC, comment #3: 

Below is a texinfo string for struct2hdl.m Notice, I took some liberty in how it may work. I'm thinking that adding the parent object which will adopt the new child makes sense, and will simplify writing copyobj().

This doesn't have to be done now. If you prefer, continue with your intent of supporting saveas(). We can alwasy give this more thought and change things later.

## -*- texinfo -*-
## @deftypefn  {Function File} {@var{h} =} struct2hdl (@var{s})
## @deftypefnx {Function File} {@var{h} =} struct2hdl (@var{s}, @var{p})
## Constructs a object from the structure @var{s}. The structure must
## contain the fields; "handle", "type", "children", "properties", and
## "special".  If the handle of an existing object is specified,
## @var{p}, the new object will be created as a child to that object.
## If no object handle is provided, then a new figure and the necessary
## children will be constructed using the default object values from
## the root figure.
## @seealso{findobj, get, hdl2struct, set}
## @end deftypefn

## Author: pantxo diribarne <>
## Created: 2012-03-04

A textinfo doc-string for hdl2struct is below.

## -*- texinfo -*-
## @deftypefn  {Function File} {@var{s} =} hdl2struct (@var{h})
## Returns a structure, @var{s}, whose fields describe the properties
## of the object, and its children, associated with the handle, @var{h}.
## The fields of the structure, @var{s}, are "type", "handle", "properties",
## "children" and "special".
## @seealso{findobj, get, set, struct2hdl}
## @end deftypefn

## Author: pantxo diribarne <>
## Created: 2012-03-04

Ben Abbott <bpabbott>
Project Member
Mon 26 Mar 2012 09:20:27 PM UTC, comment #2: 

As you add new versions, feel free to delete the old ones.

Ben Abbott <bpabbott>
Project Member
Mon 26 Mar 2012 09:15:12 PM UTC, comment #1: 

Looks like a good start. The coding looks to be consistent with Octave's standard. I suggest you add a copyobj.m

And include some tests. That will allow both hdl2struct.m and struct2hdl.m to be tested simultaneously. You can also include tests you know will fail. For those be sure to mark them as expected failures so that the remaining tests will run.

I like how this is organized as handle-to-structure and structure-to-handle. That will permit a figure to be saved by.

fig = hdl2struct (gcf ());
save plot.fig -struct fig

When you have time, you may want to add the tex-info doc strings. If you're not familiar with tex-info you can look at some of Octave's functions. Experience with LaTeX will help. Or you can ask for some help on the maintainers list.

Also you may want to include a TODO list in the source of each file so that anyone looking, and inclined to help, out knows what else needs to be done.

I see in the "getprops()" function you list properties to avoid copying. I've thought about this problem myself. I'm not sure if it is best to list those not to copy, or list those that should be copied. In either case, it looks like there may be some difficulty with maintenance. I don't see any reason to question your choice, but I expect the question to come up. Maybe someone can come up with a way to construct the list automatically?

If there are any specifics you are unsure about, please ask.

I'll also respond on the mail-list.

Ben Abbott <bpabbott>
Project Member
Mon 26 Mar 2012 08:09:05 PM UTC, original submission:  

The aim is to store the objects of a figure into a structure (hdl2struct.m), so that it can be saved in any octave format, and to rebuild the figure from the struct (struct2hdl.m).

Pantxo Diribarne <pantxo>
Project Member


(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:

Attached Files
file #26164: added by pantxo (10KiB - application/zip)
file #25877: added by pantxo (9KiB - application/zip)
file #25695:  colorbar1.pdf added by bpabbott (8KiB - application/pdf)
file #25696:  colorbar2.pdf added by bpabbott (4KiB - application/pdf)
file #25689:  figure1.pdf added by bpabbott (4KiB - application/pdf)
file #25690:  figure3.pdf added by bpabbott (4KiB - application/pdf)
file #25691:  figure2.pdf added by bpabbott (3KiB - application/pdf)
file #25582: added by bpabbott (15KiB - application/zip)
file #25564: added by pantxo (8KiB - application/zip)
file #25556: added by bpabbott (8KiB - application/zip)
file #25554: added by pantxo (9KiB - application/zip)
file #25472:  hdl2struct.m added by pantxo (4KiB - application/octet-stream - hdl2struct.m , working version )
file #25471:  struct2hdl.m added by pantxo (10KiB - application/octet-stream)


Depends on the following items: None found

Items that depend on this one: None found


Carbon-Copy List
  • -email is unavailable- added by bpabbott (Posted a comment)
  • -email is unavailable- added by pantxo (Submitted the item)

    Do you think this task is very important?
    If so, you can add your encouragement to it.
    This task has 0 encouragements so far.

    Only logged-in users can vote.




    Follow 17 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2012-11-28 bpabbott Open/ClosedOpen => Closed
    2012-07-17 bpabbott StatusNone => Ready For Test
    2012-07-08 pantxo Attached File- => Added, #26164
    2012-05-18 pantxo Attached File- => Added, #25877
    2012-04-20 bpabbott Attached File- => Added colorbar1.pdf, #25695
        Attached File- => Added colorbar2.pdf, #25696
    2012-04-19 bpabbott Attached File- => Added figure1.pdf, #25689
        Attached File- => Added figure3.pdf, #25690
        Attached File- => Added figure2.pdf, #25691
    2012-04-04 bpabbott Attached File- => Added, #25582
    2012-04-04 pantxo Attached File- => Added, #25564
    2012-04-04 bpabbott Attached File- => Added, #25556
    2012-04-03 pantxo Attached File- => Added, #25554
    2012-03-30 bpabbott Attached File#25470 => Removed
    2012-03-26 pantxo Attached File- => Added hdl2struct.m, #25472
    2012-03-26 pantxo Attached File- => Added hdl2struct.m, #25470
        Attached File- => Added struct2hdl.m, #25471

    Back to the top

    Powered by Savane 3.5