I have script handling figures so that I can print and input them in a latex document with scale = 1 and everything looks nice.
In this context I want to save the figure, axes and legend handles.
Is there a way to save them like when using fig = figure. I know two 'hacks'
1)
nfig = nfig+1; fig = figure(nfig);
plot()
ax = gca
leg = legend()
2)
nfig = nfig+1; fig = figure(nfig);
ax = subplot(1,1,1)
plot()
leg = legend()
My script
function fig_set(fig,ax,leg,width,heigth,font_size)
%% fig_set removes borders and set witdth and height of figure
%
% The function fig_set sets the border of a figure to 0
% and set the width as a scale of the width an a4 paper and the height
% as a scale of the previously set width of the figure.
%
% Syntax:
% fig_set(fig,ax,leg,width,heigth,font_size)
%
% Input:
% - fig: figure handl
% - ax: axes handle
% - leg: legend handle
% - width: width of figure, in scales of A4 paper width
% - height: height of figure, in scales of width of figure
% - font_size: font size of axes and text, it not set default=10
%
% Output:
% -figure of handel "fig" with set width, height and font
% size and Interpreters set to Latex
%
% Auther: Malthe Vibaek Eisum
% Version: 4.1
% Date: 15/3 - 2016
%% Setting font and font size
if nargin < 3
error('need figure and axes handle')
elseif nargin < 6
font_size = 10;
end
%% Setting figure, axes and legende Interpreters to Latex
set(fig,'DefaultTextInterpreter','Latex');
ax.TickLabelInterpreter='Latex';
if leg ~= 0
leg.Interpreter='Latex';
end
%% Setting width and height of figure
PaperSize = get(0,'defaultFigurePaperSize');
switch fix(PaperSize(1))
case 8
Unit = 'inches';
case 20
Unit = 'centimeters';
otherwise
error('defaultFigurePaperSize is not equivalent to a4 paper')
end
width = PaperSize(1) * width;
height = width * heigth;
set(fig,'Units',Unit,...
'Position',[2 5 width height],...
'PaperSize',[width height],...
'PaperPositionMode','auto',...
'Renderer','painters');
end
Example of creating and printing a figure
x = 1:3;
y = rand(1,3);
nfig = nfig+1; fig=figure(nfig);
ax = gca;
plot(x,y)
xlabel('$\rho$')
ylabel('more $latex_{math}$')
leg = legend('rand');
fig_set(fig,ax,leg,1,1)
print -depsc2 myplot.eps
Unless you close them, you shoudl be able to do
nfig = nfig+1;
fig{nfig} = figure(nfig);
plot()
ax{nfig} = gca
leg{nfig} = legend()
nfig=nfig+1; %// raise the counter
Fig{nfig}=figure(); %// create nfig-th figure
Ax{nfig}=axes('parent',Fig{Nfig}); %// create nfig-th axes and bind them to nfig-th figure
plot() %// plot a curve
Leg{nfig}=legend(Ax{nfig},'Label1',...);%// assign nfig-th label to nfig-th axes
%% Some other code %%
get(Ax{12},'TickLabelInterpreter') %// get the interpreter of 12-th axes (in 12-th figure)
set(Ax{5},'xlim',[-10,10]) %// set the x-limits of 5-th axes
I hope it is what you are looking for.
Related
I'd like to have the legend (of some contours) over the colorbar of a surf plot.
How can I have a layout similar to the image in a figure plot?
From the black
colorbar;
legend('label1','label2','Location','northeastoutside');
to the red one?
You can manually change the position of both the colorbar and the legend
% Make a demo plot
figure(); hold on
plot( rand(20,3) ); % lines for the legend
peaks(10); % surface for the colorbar
view(3); % 3D view
% Create a legend and colorbar, retain their handles
L = legend( 'show', 'location', 'eastoutside' );
C = colorbar();
% Get some key variables from the current position of the colorbar/legend
% -> avg mid point of colorbar and legend
x = ( L.Position(1) + (C.Position(1)+C.Position(3)) ) / 2;
% -> Max width of the two objects
w = max( L.Position(3), C.Position(3) );
% -> A nominal y value and padding to dictate the spacing
y = 0.1;
pad = 0.05;
% Move the legend and colorbar
% First move the x/y coords of the legend to be on top, centred around common x
L.Position(1:2) = [x - L.Position(3)/2, 1 - y - L.Position(4)];
% Then move the x/y coords of the colorbar to be on the bottom, centred around common x
C.Position(1:2) = [x - C.Position(3)/2, y];
% Then resize the colorbar to use the vertical space not utilised by the legend
C.Position(4) = L.Position(2) - pad - y;
% By moving the legend/colorbar the axes will have "popped" to use the full width
% Need to move it to span between the current left edge and the newly moved leg/colorbar
ax = gca();
ax.Units = 'Norm';
ax.Position(3) = (x-w/2) - pad - ax.Position(1) ;
Result:
You can do this interactively by clicking the "Cursor" icon in the top of the plot window and adjusting the legend/colorbar. Once you have finished editing choose "Generate Code" in the "File" menu of the plot window to have code generated so you can repeatedly create the plot.
I have the following figure
that I created using the following code
%% figures
DateNumObs=datenum(table2array(ADCPCRUM2(1:1678,ColumnYear)),table2array(ADCPCRUM2(1:1678,ColumnMonth)),table2array(ADCPCRUM2(1:1678,ColumnDay)),table2array(ADCPCRUM2(1:1678,ColumnHour)),table2array(ADCPCRUM2(1:1678,ColumnMinutes)),table2array(ADCPCRUM2(1:1678,ColumnSeconds)));
Flipecart=permute(ecart(1:1677,:),[2,1]);
Flipecartreel=permute(ecartreel(1:1677,:),[2,1]);
bottomVel=min(min(min(Magnitude)),min(min(velocityModel*1000)));
topVel=max(max(max(Magnitude)),max(max(velocityModel*1000)));
bottomVer=min(min(Flipecart))
topVer=max(max(Flipecart))
figure
subplot(4,1,1);
FlipMag=permute(Magnitude,[2,1]);
[C,h] =contourf(DateNumObs,1:1:22,FlipMag);
datetick('x','dd/mm/yy','keeplimits','keepticks')
caxis manual
caxis([bottomVel topVel])
c=colorbar;
c.Label.String = 'Horizontal velocity(mm/s)';
xlabel('Date');
ylabel('Depth(m from bottom)');
set(h,'LineColor','none')
title('Observation');
subplot(4,1,2);
[C,h] =contourf(DateNumObs(1:1677),1:1:22,MagMatrixH1*1000);
datetick('x','dd/mm/yy','keeplimits','keepticks')
caxis manual
caxis([bottomVel topVel])
c=colorbar;
c.Label.String = 'Horizontal velocity(mm/s)';
xlabel('Date');
ylabel('Depth(m from bottom)');
set(h,'LineColor','none')
title('Model D1');
subplot(4,1,3)
% x0=10;
% y0=10;
% width=550;
% height=400
gcf=plot(DateNumObs(1:1677),Flipecart(10,:))
% set(gcf,'LineWidth',1,'position',[x0,y0,width,height]) % Part giving the error
datetick('x','dd/mm/yy','keeplimits','keepticks')
caxis manual
caxis([bottomVer topVer])
subplot(4,1,4)
c=colorbar;
plot(DateNumObs(1:1677),Flipecartreel(10,:))
datetick('x','dd/mm/yy','keeplimits','keepticks')
caxis manual
caxis([bottomVer topVer])
I am trying to got the normal plot to be the same size as the (blue) contourf plots by using the code which is commented in the code I posted. I got this code from https://nl.mathworks.com/matlabcentral/answers/65402-how-to-set-graph-size .
However, when I try to run it it gives me the following error:
Error using matlab.graphics.chart.primitive.Line/set
There is no position property on the Line class.
Error in StatisticsSOLA (line 315)
set(gcf,'LineWidth',1,'position',[x0,y0,width,height])
I also tried is it possible to change the height of a subplot? but I get the same error. How do I prevent this error and change the width of the bottom two figures?
You are trying to set the position of the axes and the linewidth of the line object in one go, but are not providing the correct handles. Furthermore, don't store the handles of the lines in gcf, since this is a reference to the currently active figure.
Instead you can do:
data = rand(100,200); % some data
fig = figure(1); clf;
% first subplot with colorbar
ax(1) = subplot(211);
imagesc(data)
c = colorbar;
% second subplot without colorbar
ax(2) = subplot(212);
p = plot(data(1,:))
% set height and width of second subplot
drawnow % needed to get right position value of ax(1) and ax(2)
ax_pos = [ax(2).Position(1:2) ax(1).Position(3:4)]; % keep ax(2)'s left and bottom position, and set same width and height as ax(1)
set(ax(2), 'Position', ax_pos)
Alternative
Sometimes it is easier to create colorbar in the second axes, and hide it. This way you don't have to set the positions of the axes yourself.
data = rand(100,200); % some data
fig = figure(1); clf;
% first subplot with colorbar
ax(1) = subplot(211);
imagesc(data)
c = colorbar;
% second subplot without colorbar
ax(2) = subplot(212);
p = plot(data(1,:))
c = colorbar; % draw useless colorbar,
c.Visible = 'off'; % and hide it
Figure should look the same:
I am doing some analysis and need to produce a histogram plot. I know how to create the standard histogram plot but I need something like the image below, where each point is an interval on the x axis. Each bin is based on a value from x-x for example.
You can use the histogram function, and then set the XTick positions and XTickLabels accordingly. See the comments in the code for explanation.
% random normally distrubuted data
x = 1*randn(1000,1);
edges = -5:1:5;
% create vector with labels (for XTickLabel ... to ...)
labels = [edges(1:end-1); edges(2:end)];
labels = labels(:);
% plot the histogram
figure();
ax = axes;
h = histogram(x, 'BinEdges', edges, 'Normalization', 'Probability');
ax.XTick = edges + mean(diff(edges)/2);
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;
% set yticks to percentage
ax.YTickLabel = cellfun(#(a) sprintf('%i%%', (str2double(a)*100)), ax.YTickLabel, 'UniformOutput', false);
% text above bars
bin_props = h.BinCounts/numel(x); % determine probabilities per bin in axis units
bin_centers = ax.XTick(1:end-1); % get the bin centers
txt_heigts = bin_props + 0.01; % put the text slightly above the bar
txt_labels = split(sprintf('%.1f%% ', bin_props*100), ' ');
txt_labels(end) = []; % remove last cell, is empty because of split.
text(ax, bin_centers, txt_heigts, txt_labels, 'HorizontalAlignment', 'center')
% set ylim to fit all text (otherwise text is outside axes)
ylim([0 .4]);
Putting the text at the right location may require some tweaking. Most important is the 'HorizontalAlignment' option, and the distance to the bars. I also used the 'Normalization', 'probability' option from the histogram function, and set the y axis to also show percentages.
I figure you can make the addition below yourself when needed.
When your data can be outside of the defined binedges, you can clip your data, and set the XTickLabels with less than or greater than signs.
% when data can be outside of defined edges
x = 5*randn(1000,1);
xclip = x;
xclip(x >= max(edges)) = max(edges);
xclip(x <= min(edges)) = min(edges);
% plot the histogram
figure();
ax = axes;
h = histogram(xclip, 'BinEdges', edges);
ax.XTick = edges + mean(diff(edges)/2);
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;
% set boundary labels
ax.XTickLabel{1} = sprintf('\\leq %.1f', edges(2));
ax.XTickLabel{end-1} = sprintf('\\geq %.1f', edges(end-1));
You can also set the outer edges to -Inf and Inf, as user2305193 pointed out. Since the outer bins are then much wider (because they actually extend to Inf on the x axis), which you can correct by setting the axis xlim. By the default the XTickLabels will display -Inf to -5.0, which I personally don't like, so I set them to lesser (and equal) than and greater than signs.
step = 1;
edges = -5:step:5; % your defined range
edges_inf = [-Inf edges Inf]; % for histogram
edges_ext = [edges(1)-step edges]; % for the xticks
x = 5*randn(1000,1);
% plot the histogram
figure();
ax = axes;
h = histogram(x, 'BinEdges', edges_inf, 'Normalization', 'probability');
labels = [edges_inf(1:end-1); edges_inf(2:end)];
labels = labels(:);
ax.XTick = edges_ext + step/2;
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;
% show all bins with equal width (Inf bins are in fact wider)
xlim([min(edges)-step max(edges)+step])
% set boundary labels
ax.XTickLabel{1} = sprintf('\\leq %.1f', edges(1));
ax.XTickLabel{end-1} = sprintf('\\geq %.1f', edges(end));
I have a 576x576x150 matrix. Each 576x576 set represents an image. When I want to plot one frame I do it by using the plot command:
figure(1);
imshow(B(:,:,45),[]) % plots frame 45
title('45') % tells frame number
However I would like to add a slider to the plot, so I can move from 1-150 frame within the figure.I've seen examples of people using uicontrol but I don't know how to code it. In addition to that, I would like to have a title on top of the figure telling me the frame number.
Here is how I do it. I like to keep a single function that does the plotting so you don't recycle commands elsewhere. You could replace the first two lines by function test(B) to use you own B matrix. This code is pretty easy to extend. You will also want to play with the layout to suit your purpose.
function test
B=rand(576,576,150);
fig=figure(100);
set(fig,'Name','Image','Toolbar','figure',...
'NumberTitle','off')
% Create an axes to plot in
axes('Position',[.15 .05 .7 .9]);
% sliders for epsilon and lambda
slider1_handle=uicontrol(fig,'Style','slider','Max',150,'Min',1,...
'Value',2,'SliderStep',[1/(150-1) 10/(150-1)],...
'Units','normalized','Position',[.02 .02 .14 .05]);
uicontrol(fig,'Style','text','Units','normalized','Position',[.02 .07 .14 .04],...
'String','Choose frame');
% Set up callbacks
vars=struct('slider1_handle',slider1_handle,'B',B);
set(slider1_handle,'Callback',{#slider1_callback,vars});
plotterfcn(vars)
% End of main file
% Callback subfunctions to support UI actions
function slider1_callback(~,~,vars)
% Run slider1 which controls value of epsilon
plotterfcn(vars)
function plotterfcn(vars)
% Plots the image
imshow(vars.B(:,:,get(vars.slider1_handle,'Value')));
title(num2str(get(vars.slider1_handle,'Value')));
The idea is to use uicontrol() to enable sliding/scrolling.
The following code is for scrolling (created by Evan Brooks, you can modify it to sliding):
function scrollfigdemo
% create new figure window
f = figure;
set(f,'doublebuffer', 'on', 'resize', 'off')
% set columns of plots
cols = 2;
% create 5 data sets to plot
x=0:1e-2:2*pi;
y{1}=sin(x);
y{2}=cos(x);
y{3}=tan(x);
y{4}=x.^2;
y{5}=x.^3;
% determine required rows of plots
rows = ceil(length(y)/cols);
% increase figure width for additional axes
fpos = get(gcf, 'position');
scrnsz = get(0, 'screensize');
fwidth = min([fpos(3)*cols, scrnsz(3)-20]);
fheight = fwidth/cols*.75; % maintain aspect ratio
set(gcf, 'position', [10 fpos(2) fwidth fheight])
% setup all axes
buf = .15/cols; % buffer between axes & between left edge of figure and axes
awidth = (1-buf*cols-.08/cols)/cols; % width of all axes
aidx = 1;
rowidx = 0;
while aidx <= length(y)
for i = 0:cols-1
if aidx+i <= length(y)
start = buf + buf*i + awidth*i;
apos{aidx+i} = [start 1-rowidx-.92 awidth .85];
a{aidx+i} = axes('position', apos{aidx+i});
end
end
rowidx = rowidx + 1; % increment row
aidx = aidx + cols; % increment index of axes
end
% make plots
axes(a{1}), plot(x,y{1}), title('sine'), xlabel('x'), ylabel('sin(x)')
axes(a{2}), plot(x,y{2}), title('cosine'), xlabel('x'), ylabel('cos(x)')
axes(a{3}), plot(x,y{3}), title('tangent'), xlabel('x'), ylabel('tan(x)')
axes(a{4}), plot(x,y{4}), title('x^2'), xlabel('x'), ylabel('x^2')
axes(a{5}), plot(x,y{5}), title('x^3'), xlabel('x'), ylabel('x^3')
% determine the position of the scrollbar & its limits
swidth = max([.03/cols, 16/scrnsz(3)]);
ypos = [1-swidth 0 swidth 1];
ymax = 0;
ymin = -1*(rows-1);
% build the callback that will be executed on scrolling
clbk = '';
for i = 1:length(a)
line = ['set(',num2str(a{i},'%.13f'),',''position'',[', ...
num2str(apos{i}(1)),' ',num2str(apos{i}(2)),'-get(gcbo,''value'') ', num2str(apos{i}(3)), ...
' ', num2str(apos{i}(4)),'])'];
if i ~= length(a)
line = [line,','];
end
clbk = [clbk,line];
end
% create the slider
uicontrol('style','slider', ...
'units','normalized','position',ypos, ...
'callback',clbk,'min',ymin,'max',ymax,'value',0);
clear all; close all; clc;
A = im2double(imread('cameraman.jpg'));
figure(1)
imshow(A)
C = chunking(A,400,400) % separates picture;
[m n] = size(C);
k = 1;
figure(1)
for i = 1:m
for j = 1:n
subplot(m,n,k)
imshow(C{i,j})
axis off;
k = k + 1;
end
end
So In the above code, I am trying to separate a picture into 400x400 pixel chunks. Since the image is not a multiple of 400x400, it will have unequal sections on the border and bottom right corner (still a square image). However, when I use subplot, it resizes the last chunk to be the same size. I tried playing around with get and set position but it gives that the width and height for each subplot is the same?![enter image description here][1]
http://imgur.com/2VUYZr1
You want to resize the axes if you have less than 400 pixels to display. You should store the handle to each subplot and then resize it if it needs to be smaller.
Your call to subplot should look like this:
h = subplot(m,n,k);
num_rows = size(C{i,j}, 1);
num_cols = size(C{i,j}, 2);
set(h, 'units', 'pixels')
old_axes_pos = get(h, 'position');
new_axes_pos = old_axes_pos;
if num_cols < 400
new_axes_pos(3) = num_cols; % Make this axes narrower
end
% If the figure cannot be full height
if num_rows < 400
new_axes_pos(4) = num_rows; % Make this axes shorter
new_axes_pos(2) = old_axes_pos(2) + (400 - num_rows); % Move the bottom up
end
set(h, 'position', new_axes_pos) % Change the size of the figure