How to add a gap between the axes and the plot in MATLAB - matlab-figure

I use code like this to make a plot in MATLAB 2015:
plot(rand(1,40))
box off
ax=gca;
ax.TickDir='out';
ax.TickLength=3*ax.TickLength;
]
I want to put a bit of distance between the axes and the plot like in the figure below, which I made using Photoshop:
How can I do this?

I can think of a way to do it, but:
I don't know if it's the "right" way.
It's only good for static images (i.e. if you zoom/pan the plot, the bounds won't change accordingly).
The idea is you create two more axes and specify their positions such that they're far enough from your data, then hide the original axes (either fully or partially), which gives the desired result:
%% // Create axes and plot something:
figure();
hA(1) = axes;
hA(2) = copyobj(hA(1),gcf);
hA(3) = copyobj(hA(1),gcf);
plot(hA(1),rand(1,40));
%% // Add the new axes:
%// Move them around
FRACTION_OF_POSITION = 0.6;
hA(2).Position(1) = FRACTION_OF_POSITION*hA(2).Position(1);
hA(3).Position(2) = FRACTION_OF_POSITION*hA(3).Position(2);
%// Change their style
hA(2).Color = 'none'; hA(3).Color = 'none';
hA(2).XTick = []; hA(3).YTick = [];
hA(2).XRuler.Axle.Visible = 'off';
hA(3).YRuler.Axle.Visible = 'off';
%% // Remove the box/ticks/labels of the original axes:
if true
%// Alternative 1 (Remove everything at once, including background):
set(hA(1),'Visible','off')
else
%// Alternative 2 (Remove only certain elements):
hA(1).Box = 'off';
hA(1).XRuler.Axle.Visible = 'off';
hA(1).YRuler.Axle.Visible = 'off';
end
Which results in:
Additional considerations:
If you copyobj the axes before plotting, the axis tick values would be default - you probably don't want that. You will have to set the ticks and labels manually, OR, copyobj after plotting but then delete the line child-objects of hA(2:3).
If you want to support zoom/pan behavior, this might be acheivable using linkaxes.
Credits: the idea to use .XRuler.Axle was taken from Dan here, who in turn took it from UndocumentedMatlab.

Related

Changing colors on dimple.js scatter plot

How can I change the color of the circles on a scatter plot based on one of the fields that I'm not using on neither of the axes?
Example, this code:
var myChart3 = new dimple.chart(svg3, data);
myChart3.addMeasureAxis("x", "salary");
myChart3.addMeasureAxis("y", "bonus");
var mySeries = myChart3.addSeries(["Index","a"], dimple.plot.scatter);
myChart3.draw();
produces this graph:
but I also would like to color the bubbles based on a third field called "department"
thanks
The first parameter of addSeries determines colours. In the case of an array the last element is used, so you just need to do:
var mySeries = myChart3.addSeries(["Index","a","department"], dimple.plot.scatter);

image stack display in matlab using a slider

I have a 3 dimension matrix of data (a stack of images across a dimension, time for example.
I want to display an image, and have a slider below to navigate across the images.
I wrote a piece of code which works, but it's bulky and kinda ugly I think...I want to write a clean function and so I would like to know if anyone know of a cleaner, nicer way to do it.
Here is my code:
interv = [min max]; % interval for image visualization
imagesc(Temps_visu,X*100,squeeze(X,Y,MyMatrix(:,:,1)),interv);
title('My Title');
xlabel('X (cm)');
ylabel('Y (cm)');
pos = get(gca,'position');
% slider position
Newpos = [pos(1) pos(2)-0.1 pos(3) 0.05];
pp = 1;
% callback slider
S = ['pp=floor(get(gcbo,''value''));imagesc(Temps_visu,X*100,squeeze(X,Y,MyMatrix(:,:,1)),interv));' ...
'set_axes_elasto;title(''My Title'');disp(pp);'];
Mz = size(MyMatrix,3);
% Creating Uicontrol
h = uicontrol('style','slider',...
'units','normalized',...
'position',Newpos,...
'callback',S,...
'min',1,'max',Mz,...
'value',pp,...
'sliderstep',[1/(Mz-1) 10/(Mz-1)]);
Here is a way to do it using a listener object for smooth visualization of your stack. I made up a dummy stack using grayscale variations of the same image (i.e. only 4 frames) but the principle will be the same for your application. Notice that I use imshow to display the images, but using imagesc as you do won't cause any problem.
The code is commented so hopefully this is clear enough. If not please don't hesitate to ask for help!
Code:
function SliderDemo
clc
clear all
NumFrames = 4; %// Check below for dummy 4D matrix/image sequence
hFig = figure('Position',[100 100 500 500],'Units','normalized');
handles.axes1 = axes('Units','normalized','Position',[.2 .2 .6 .6]);
%// Create slider and listener object for smooth visualization
handles.SliderFrame = uicontrol('Style','slider','Position',[60 20 400 50],'Min',1,'Max',NumFrames,'Value',1,'SliderStep',[1/NumFrames 2/NumFrames],'Callback',#XSliderCallback);
handles.SliderxListener = addlistener(handles.SliderFrame,'Value','PostSet',#(s,e) XListenerCallBack);
handles.Text1 = uicontrol('Style','Text','Position',[180 420 60 30],'String','Current frame');
handles.Edit1 = uicontrol('Style','Edit','Position',[250 420 100 30],'String','1');
%// Create dummy image sequence, here 4D sequence of grayscale images.
MyImage = imread('peppers.png');
MyMatrix = cat(4,rgb2gray(MyImage),MyImage(:,:,1),MyImage(:,:,2),MyImage(:,:,3));
%// Use setappdata to store the image stack and in callbacks, use getappdata to retrieve it and use it. Check the docs for the calling syntax.
setappdata(hFig,'MyMatrix',MyMatrix); %// You could use %//setappdata(0,'MyMatrix',MyMatrix) to store in the base workspace.
%// Display 1st frame
imshow(MyMatrix(:,:,:,1))
%// IMPORTANT. Update handles structure.
guidata(hFig,handles);
%// Listener callback, executed when you drag the slider.
function XListenerCallBack
%// Retrieve handles structure. Used to let MATLAB recognize the
%// edit box, slider and all UI components.
handles = guidata(gcf);
%// Here retrieve MyMatrix using getappdata.
MyMatrix = getappdata(hFig,'MyMatrix');
%// Get current frame
CurrentFrame = round((get(handles.SliderFrame,'Value')));
set(handles.Edit1,'String',num2str(CurrentFrame));
%// Display appropriate frame.
imshow(MyMatrix(:,:,:,CurrentFrame),'Parent',handles.axes1);
guidata(hFig,handles);
end
%// Slider callback; executed when the slider is release or you press
%// the arrows.
function XSliderCallback(~,~)
handles = guidata(gcf);
%// Here retrieve MyMatrix using getappdata.
MyMatrix = getappdata(hFig,'MyMatrix');
CurrentFrame = round((get(handles.SliderFrame,'Value')));
set(handles.Edit1,'String',num2str(CurrentFrame));
imshow(MyMatrix(:,:,:,CurrentFrame),'Parent',handles.axes1);
guidata(hFig,handles);
end
end
The figure looks like this:
Hope that helps!

How do I save an image in Matlab with axes but without plotting?

I have an image I that I want to save with axes on it.
imwrite(I,jet,'image.jpg');
will save the image.
I = image;
RI = imref2d(size(I));
RI.XWorldLimits = [xmin xmax];
RI.YWorldLimits = [ymin ymax];
figure(1);
imshow(I,RI,jet);
xlabel('x');
ylabel('y');
print(1,'-djpeg','image.jpg');
will plot the image with axes on a figure and then save it with axes.
I want to save the image with axes, without plotting it in a figure first. Is there a way to do this?
If what you want is for the figure not to be seen by the user, the easiest way is to create the figure and set its 'visible' property to 'off':
I = image;
RI = imref2d(size(I));
RI.XWorldLimits = [xmin xmax];
RI.YWorldLimits = [ymin ymax];
figure(1);
set(1,'visible','off') %// add this line to make figure not visible
imshow(I,RI,jet);
xlabel('x');
ylabel('y');
print(1,'-djpeg','image.jpg');

VBA Chart Manipulation Slow

I wrote some Excel VBA code that generates a scatterplot and changes a few properties of the chart. (Code is below for reference.) The code moves slowly through tasks like deleting the chart legend, removing horizontal/vertical gridlines, and changing the X and Y series. Excel's timer gives me the following duration for each task:
insert scatterplot: 0.01171875
delete series: 0
plot x vs y: 0.55859375
delete legend: 0.5703125
delete chart title: 0.66015625
remove grid: 1.3046875
format axes: 0
overall: 3.11328125
Removing the grid, changing the title, plotting the X and Y series, and deleting the legend seem to take a long time. I've googled for alternative ways to write the code, but haven't been able to find anything useful. The code works entirely as expected, except for the slow speed. Any ideas as to what's causing the bad performance, and how I can speed this up? Thanks in advance.
EDIT: I've already turned off screen updating while working with the chart. The chart is generated/formatted while a userform is open, if that makes any difference.
Here is the relevant snippet of code:
With ActiveChart
'Delete all series currently in plot
Do While .FullSeriesCollection.Count > 0
.FullSeriesCollection(1).Delete
Loop
'Plot Actual (Y) vs. Inverse Distribution (X)
.SeriesCollection.NewSeries
.FullSeriesCollection(1).XValues = "=" & tempSheetName & "!$C:$C"
.FullSeriesCollection(1).Values = "=" & tempSheetName & "!$A:$A"
'Delete legend
.Legend.Delete
'Delete chart title
.SetElement (msoElementChartTitleNone)
'Remove gridlines
.SetElement (msoElementPrimaryValueGridLinesNone)
.SetElement (msoElementPrimaryCategoryGridLinesNone)
'Format axes
Dim xAxis As Axis, yAxis As Axis
Set xAxis = .Axes(xlCategory)
Set yAxis = .Axes(xlValue)
With yAxis
'Title y axis "actual"
.HasTitle = True
.AxisTitle.Caption = "Actual"
'Add tick marks
.MajorTickMark = xlOutside
End With
With xAxis
'Title x axis by dist type
.HasTitle = True
.AxisTitle.Caption = dist.getDistType
'Add tick marks
.MajorTickMark = xlOutside
End With
End With
Without the data and machine specifics it can be hard to say why this is slow, although here are some alternatives to some of the code you have.
The first and foremost thing I'd change is not to Activate the chart. If you are creating the chart through code, do so but set it to a variable, eg Set wcChart = ThisWorkbook.Charts.Add. Then change With ActiveChart to With wcChart.
Also, delete the FullSeriesCollection and then delete the chart title, remove the gridlines and change the axes before filling up the new data. The chart manipulation should be quicker with less data in the chart. Be careful here though because changing aspects of the chart in different orders can produce different outputs (as an example the layout of a legend).
You fill the new FullSeriesCollection with the entire columns of A and C, specify the exact range of the data rather than the whole column.
Other changes to try, I'm not saying these will work but they are worth a shot if you haven't tried. Instead of checking for a FullSeriesCollection each time:
Do While .FullSeriesCollection.Count > 0
.FullSeriesCollection(1).Delete
Loop
The following may be quicker:
For ii = .FullSeriesCollection.Count To 1 Step -1
.FullSeriesCollection(ii).Delete
Next ii
Also, instead of .SetElement for the Chart title and Gridlines I use the following:
'You have to set the title to 'True' before it'll work with 'False'. Go figure.
.HasTitle = True
.HasTitle = False
.HasMajorGridlines = False
.HasMinorGridlines = False

Matlab: How can I display several outputs in the same image?

Let's say my image is img=zeros(100,100,3), my outputs are several ellipse which i get using a created function [ret]=draw_ellipse(x,y,a,b,angle,color,img), I can display one ellipse using imshow(ret).For the moment, I'm trying to show serval ellipse in the image. But i don't know how to code it. will ‘for loop’ work or I need to hold them?
If this is related to what you were doing in your previous question, then what you need to do is to pass the result of one iteration as input to the next.
So assuming that the function [ret]=draw_ellipse(x,y,a,b,angle,color,img) you mentioned takes as input an image img and returns the same image with an ellipse drawn on it, you could do this:
%# ellipses parameters
%#x = {..}; y = {..};
%#a = {..}; b = {..};
%#angle = {..}; color = {..};
img = zeros(200,100,'uint8'); %# image to start with
for i=1:10
img = draw_ellipse(x{i},y{i}, a{i},b{i}, angle{i}, color{i}, img);
end
imshow(img)
I'm a bit unsure of what you want. You want to show several ellipse in one image, like plotting several graphs with hold on?
There is no equivalent command for images, but a simple solution is to add the ellipses into one image and show that one:
several_ellipse = ellipse1 + ellipse2 + ellipse3;
imshow(several_ellipse)
Presumably you want to pass ret as the final input to the next call to draw_ellipse.

Resources