1
votes

I am trying to create a plot in Octave (using v4.4.1 on Windows) using plotyy and putting the legend outside the plot (because the data covers all the usable space inside the graph). The following MVCE should reproduce the issue fairly well:

% Generate some random data to reproduce the issue
data = rand(1000,10);
data(:,1:8) = data(:,1:8)-0.5;
data(:,9:10) = data(:,9:10)+30;
timedate = linspace(737310,737313,size(data,1));
data_labels={'1';'2';'3';'4';'5';'6';'7';'8';'9';'10'};

% Plot the data
figure('Name','MVCE','Position',[300 200 1000 600])
[ax,h1,h2] = plotyy(timedate,data(:,1:8),timedate,data(:,9:10));
set(h2,'Visible','on'); 
datetick(ax(1),'x','HH:MM:SS')
datetick(ax(2),'x','HH:MM:SS')
ylim(ax(1),[-1 1])
ylim(ax(2),[20 50])
xlabel('Date & time')
ylabel(ax(1),'Something')
ylabel(ax(2),'Something else')
title('plotyy graph with legend problem')
[hl,hlo] = legend([h1;h2],data_labels,'location','eastoutside');
grid on

This the output of the code using the gnuplot graphics toolkit:

enter image description here

As you can see, the legend does not go outside the plot, and the second y axis is not visible (it looks like part of the plot is actually truncated).

I have tried using the qt and fltk graphics toolkits, which give issues of their own:

  1. With qt graphics toolkit

enter image description here

  1. With fltk graphics toolkit

enter image description here

Can anoybody suggest a fix or at least workaround? Does the same issue also happen in MATLAB or is it Octave-specific?

EDIT Using the suggestion in Tasos' answer, I managed to almost make it work with gnuplot:

% Plot the data
figure('Name','MVCE','Position',[300 200 1000 600])
[ax,h1,h2] = plotyy(timedate,data(:,1:8),timedate,data(:,9:10));
set(h2,'Visible','on'); 
datetick(ax(1),'x','HH:MM:SS')
datetick(ax(2),'x','HH:MM:SS')
ylim(ax(1),[-1 1])
ylim(ax(2),[20 50])

ax1Pos = get(ax(1), 'position');   
ax2Pos = get(ax(2), 'position');
ax1Pos(3) = ax1Pos(3) * 0.73;      
ax2Pos(3) = ax2Pos(3) * 0.73;
set(ax(1), 'position', ax2Pos);    
set(ax(2), 'position', ax2Pos);

xlabel('Date & time')
ylabel(ax(1),'Something')
ylabel(ax(2),'Something else')
title('plotyy graph with legend problem')
[hl,hlo] = legend([h1;h2],data_labels,'location','eastoutside');
pos = get(hl,'Position');
pos(1) = 0.9;
set(hl,'Position',pos)
grid on

Which produces:

enter image description here

Apart from the fact that the legend overlays with the second y axis label (which it doesn't on my screen, only when printing to jpg), the problem is that Octave appears to plot two legends on top of each other for some reason: one with the first set of data attached to the first set of axes, and one with the complete set of data, for both axes right on top of the first legend. This is obviously wrong, and trying to set the Visible property of hl to off deletes both legends, not just the one.

1
I think the MATLAB tag should be removed, since this issue is Octave-specific. Is there a reason for having this tag other than increasing exposure? - Dev-iL
@Dev-iL Fair comment - I thought it might also apply to MATLAB as the syntax is identical and should work on both platforms. Whether or not the same issue also occurs on MATLAB, I cannot say. Although this is probably Octave-specific some people with MATLAB knowledge may have valuable suggestions to solve the issue. If you really think the MATLAB tab isn't appropriate, feel free to remove it. - am304
In fact, if somebody has access to MATLAB, I'd be very interested to find out if the same thing happens in MATLAB. - am304
Cannot reproduce in MATLAB R2017b, legend appears outside the plot and the 2nd y axis is shown, with labels etc (although the 2nd y axis label is covered by the legend, but that's probably a different issue again). I've removed the MALTAB tag accordingly, reinstate it if you have a direct reason to link this to MATLAB. Perhaps tag the graphics toolkits instead - Wolfie

1 Answers

2
votes

UPDATED: deals with both legend placement and OpenGL precision affecting graph.

Regarding the problem of the legend not appearing exactly in the position you want it to, you can manually adjust the position of all axes involved in a figure, to place them exactly where you want.

Regarding the problem of OpenGL being unable to deal with the precision involved when adding small numbers to a large number, plot the graph with only the small numbers involved, and then simply adjust the xticklabels to correspond to the numbers you desire.

Full code below:

% Generate some random data to reproduce the issue
data = rand(1000,10);
data(:,1:8) = data(:,1:8)-0.5;
data(:,9:10) = data(:,9:10)+30;
t_offset = 737310;
timedate = linspace(0,3,size(data,1));
data_labels={'1';'2';'3';'4';'5';'6';'7';'8';'9';'10'};

% Plot the data
figure('Name','MVCE','Position',[300 200 1000 600])
[ax,h1,h2] = plotyy(timedate,data(:,1:8),timedate,data(:,9:10));
set(h2,'Visible','on'); 
ylim(ax(1),[-1 1])
ylim(ax(2),[20 50])
ylabel(ax(1),'Something')
ylabel(ax(2),'Something else')
title('plotyy graph with legend problem')
[hl,hlo] = legend([h1;h2],data_labels,'location','eastoutside');
set(hl, 'position', get(hl, 'position') .* [0.975, 1, 0.975, 1] )
grid on

ax1Pos = get(ax(1), 'position');   ax2Pos = get(ax(2), 'position');
ax1Pos(3) = ax1Pos(3) * 0.95;      ax2Pos(3) = ax2Pos(3) * 0.95;
set(ax(1), 'position', ax2Pos);    set(ax(2), 'position', ax2Pos);
XTicks = get(ax(1), 'xtick');
set(ax(1), 'xticklabel', datestr(XTicks + t_offset, 'HH:MM:SS'))
xlabel('Date & time')
set(ax(2), 'xtick', []);

Output:

enter image description here