Cannot get imagesc to work in Matlab - matlab

Would someone kindly please tell me why imagesc is not doing what I want it to:
I am trying to get a grid of chars out like:
http://wetans.net/word-search-worksheets-for-kids
Here is the code:
A = [5,16,18,4,9;
9,10,14,3,18;
2,7,9,11,21;
3,7,2,19,22;
4,9,10,13,8]
AAsChars = char(A + 96);
imagesc(AAsChars);

The short answer is - you are using the wrong function for your job. imagesc will take a map of values and convert it to intensities - one pixel per value. You want it to magically take a character value and turn it into the representation (many pixels) of the character that this represents (without regard to font, etc).
You probably want to create an empty background, then put text characters at the locations you want. Something like (not tested):
figure
imagesc(ones(5,5))
axis off
for t = 1:5
for k = 1:5
text(t, k, sprintf('%c', A(t,k) + 96))
end
end
This should put the string (character) at the location (i,j). Experiment a bit - not sure I have the syntax of text() and the formatting of the string (with "%c") right and can't check right now.

I think you are overcomplicating, this should simply do the trick:
char(A + 96)

Related

How can I build custom xticklabels using numbers and strings?

I am trying to customize the Xticklabels of my bar graph to have a format of 'number (units)'
So far I have a vector:
scanrate = [2;4;6;8;10];
I want my bar graph to have an x axis of:
2mv/s 4mv/s 6mv/s 8mv/s 10mv/s
If I use xticklabels(num2str(scanrate))
the xticklabels change to the numbers in the scanrate vector. I want to put mv/s after each Xtick.
You can also use strcat :
xticklabels(strcat(num2str(scanrate),' mv/s'))
Please note that it works only when scanrate is a column vector.
Fun fact :
num2str(scanrate) + " mv/s"
also works, but
num2str(scanrate) + ' mv/s'
does not
Build your strings using sprintf(), where the %d flag is for an unsigned integer:
my_labels = {};
for ii = 1:numel(scanrate)
my_labels{ii} = sprintf('%dmv/s', scanrate(ii));
end
figure;
% (...) make your plot
xticklabels(my_labels)
Alternative one-liner, thanks to Wolfie's comment:
my_labels = arrayfun(#(x)sprintf('%dmv/s',x),scanrate,'uni',0);
As a side note: that's normally not what you'd do when creating these type of plots. You'd just have numbers on the axes and a label stating something as "Velocity [mv/s]", rather than having the unit on every single tick label.

How to make a legend continue onto more rows when no room?

I have a plot with mutliple lines and I want to display the legend below the box (southoutside). The problem is that currently my legend is too long to fit on a single line. Therefore the question is how do I get a line break in my legend?
Currently I generate the legend as follows:
hLegend = legend([l1,l2,l3,l4], 'This is a very, very long legend text', 'Test2', ...
'A bit longer', 'This is quite long');
set(hLegend,'Fontsize',8,'Location', 'southoutside', 'Orientation','horizontal');
then this occurs:
As you can see I have four lines (there might come more) and the first one has a very long name.
I want to keep the orientation this way to reduce figure space needed and I want to put an automatic line break if the legend exceeds the picture width (i.e. before l3 or l4, here illustrated by the yellow or purple line).
Any ideas on this? I am using a plot width of 15.75 cm.
Edit
Thanks a lot for the answers so far. Although both of the answers provide some opportunities in splitting the legend into two lines, my main problem still occurs. If assuming now that the plot had more then four lines, lets say 20 and I want to have the legend southside horizontal in a way that it uses the least space, is there a way to split the legend not within one legend text, but after one entry. I generated a new figure generally depicting what I am looking for (its made in Paint so it really just shows the general idea).
Edit 2
The columnlegend package available in the Matlab File Exchange unfortunately does not support legends outside of the figure (at least the options are not specified in the description it only names the following possible locations: 'NorthWest', 'NorthEast', 'SouthEast', 'SouthWest'
Help is appreciated.
Intro:
Here's a proof-of-concept of legend text wrapping, using some undocumented outputs of legend and the MATLAB -> python interface. I will first show the code and then provide a brief explanation of why/how it works.
This is done in MATLAB 2016a.
Code:
function q39456339
%% Definitions:
MAX_LENGTH_IN_CHARS = 20;
OPTION = 2;
%% Plot something:
x = 1:10;
figure('Position',[450 400 800 270]);
plot(x,x,x,2*x,x,10-x,x,20-2*x);
%% Using python's TextWrapper to wrap entries:
% web(fullfile(docroot, 'matlab/matlab_external/call-python-from-matlab.html'))
switch OPTION
case 1
[~,hT] = legend({'This is a very, very long legend text', 'Test2', 'A bit longer', ...
'This is quite long'},'Location', 'SouthOutside', 'Orientation','Horizontal',...
'Fontsize',8,'Box','Off');
texts = hT(arrayfun(#(x)isa(x,'matlab.graphics.primitive.Text'),hT));
wrapLegendTexts(texts,MAX_LENGTH_IN_CHARS);
case 2
hL = legend({'This is a very, very long legend text', 'Test2', 'A bit longer', ...
'This is quite long'},'Location', 'SouthOutside', 'Orientation','Horizontal',...
'Fontsize',8,'Interpreter','tex');
TEX_NEWLINE = '\newline';
addNewlinesThroughPython(hL, MAX_LENGTH_IN_CHARS, TEX_NEWLINE);
end
end
%% Helper functions:
function wrapLegendTexts(textObjs,maxlen)
tw = py.textwrap.TextWrapper(pyargs('width', int32(maxlen)));
for ind1 = 1:numel(textObjs)
wrapped = cellfun(#char,cell(wrap(tw,textObjs(ind1).String)), 'UniformOutput', false);
textObjs(ind1).Text.String = reshape(wrapped,[],1);
end
end
function addNewlinesThroughPython(hLeg, maxlen, newlineStr)
tw = py.textwrap.TextWrapper(pyargs('width', int32(maxlen)));
for ind1 = 1:numel(hLeg.PlotChildren)
hLeg.PlotChildren(ind1).DisplayName = char(...
py.str(newlineStr).join(wrap(tw,hLeg.PlotChildren(ind1).DisplayName)));
end
end
Result:
Option 1:
Option 2:
Explanation (Option 1):
First, let's look at the signature of legend:
>> dbtype legend 1
1 function [leg,labelhandles,outH,outM] = legend(varargin)
We can see that the 2nd output returns some sort of handles. When we investigate further:
arrayfun(#class, hT, 'UniformOutput', false)
ans =
'matlab.graphics.primitive.Text'
'matlab.graphics.primitive.Text'
'matlab.graphics.primitive.Text'
'matlab.graphics.primitive.Text'
'matlab.graphics.primitive.Line'
'matlab.graphics.primitive.Line'
'matlab.graphics.primitive.Line'
'matlab.graphics.primitive.Line'
'matlab.graphics.primitive.Line'
'matlab.graphics.primitive.Line'
'matlab.graphics.primitive.Line'
'matlab.graphics.primitive.Line'
And:
hT(1)
ans =
Text (This is a very, very long legend text) with properties:
String: 'This is a very, very long legend text'
FontSize: 9
FontWeight: 'normal'
FontName: 'Helvetica'
Color: [0 0 0]
HorizontalAlignment: 'left'
Position: [0.0761 0.5128 0]
Units: 'data'
Show all properties
Aha! This is the first legend text entry. We see several interesting properties in the above list (more here), but what we care about is String.
Then it's a question of how to wrap said string. Fortunately, this is exactly the example provided in the MATLAB documentation for using the python interface, so I will not go into any details of that. Here's a link to the docs of python's textwrap. The correct version of the page (selectable by a dropdown on the top left) should correspond to your local python version (see output of pyversion).
The rest of my code is just a wrapper around the python interface, to process all legend entries.
Explanation (Option 2):
Here we don't use any extra outputs of legend, and instead modify hLeg.PlotChildren.DisplayName. This property doesn't accept cell arrays of strings (the way for multi-line strings are usually defined in MATLAB), so we need to insert newline "marks" based on syntax the interpreter recognizes (..or character 10 - the ASCII value of a "newline", as shown in excaza's answer). Finding the correct positions for the line break is still done using python, but this time the strings are joined (with the newline mark in between) instead of being converted to a cell column.
Notes:
The 1st option probably provides more control at the expense of some additional required tweaking. One may need to play around with the Texts' Position parameters after wrapping the strings to make the legend look a bit nicer
Assigning the 2nd output of legend changes it behavior slightly (you can see it from the overlapping legend entries in the top figure).
For an automated approach that does not require a local Python installation you can specify a maximum character width and use a regular expression to wrap your text strings accordingly.
For example:
function testcode
x = 1:10;
y1 = x;
y2 = 2*x;
y3 = 3*x;
y4 = 4*x;
l = plot(x, y1, x, y2, x, y3, x, y4);
maxwidth = 20; % Maximum character width of each legend string line
ls = {'This is a very very long legend text', 'Test2', 'A bit longer', 'This is quite long'};
ls = cellfun(#(x)wrapstr(x,maxwidth), ls, 'UniformOutput', false);
legend([l(1),l(2),l(3),l(4)], ls, 'Location', 'SouthOutside', 'Orientation', 'horizontal');
end
function [output] = wrapstr(s, width)
% Split input string s into:
% \S\S{width-1,}: sequences of 1 non-whitespace character followed by
% width-1 or more non-whitespace characters OR
% .{1, width}: sequences of 1 to width of any character.
%
% (?:\\s+|$): Each group is followed by either whitespace or the end of the string
exp = sprintf('(\\S\\S{%u,}|.{1,%u})(?:\\s+|$)', width-1, width);
tmp = regexp(s, exp, 'match');
output = strjoin(deblank(tmp), '\n');
end
Which produces:
The regexp matches Steve Eddin's FEX submission: linewrap

How do I display full equations when calling for a function in Matlab?

I have a problem about displaying the output in the way I need it to, first let me show what I'm trying to do
The problem I'm trying to solve:
Write a function called printaltsum that takes an integer and prints the sum from 1 to the integer, where the addition and subtraction are alternated.
For example- printaltsum(4) MUST display exactly the following:
1=1
1+2=3
1+2-3=0
1+2-3+4=4
Please guide me in the right direction, I have been able to solve this problem to get final values, but I just can't get it to display the format it needs (all I get is the Right hand side of the equation and final value as answer).
When I call for my function it displays :
printaltsum(4)
1
3
0
4
ans =
4
as you can see I can't display the equations, but only the Right hand side of it and the final answer
Here is my code:
function sum = printaltsum(n)
sum=0;
for i=1:n;
if i==1
sum=1;
end
if rem(i,2)==0 && i ~=1
sum=sum+i;
end
if rem(i,2)==1 && i ~=1
sum=sum-i;
end
disp(sum)
end
end
you need to assembel the String to display yourselve, matlab wont do it.
So just add to every Operation the same in text.
first initialize an empty string:
str='';
When ever you do something to the sum, you do the same to the string in text, for example:
sum=1; % setting sum to 1
str='1'% the same in text
or for inside the loop:
sum=sum+i; % adding i to sum
str=[str '+' num2str(i)]% the same in text
at the end of the loop you can display the string:
disp(str)
Hope this helps

Using imfreehand within your program

For instance, I start my program as follows reading some image:
I=input('image name: ','s');
img=double(imread(I));
I'm planning to work only on some portion of that image. So, I noticed that I may need h=imfreehand for this purpose.
Thus, I have inserted h=imfreehand under the two lines above. What I got is a white screen. So, how can I get the image and select the region I want? The other thing is, how can I tell my program to work only on that region I have selected?
Thanks.
UPDATE
I did the following in a portion of my code:
figure, imshow(img);
h = imfreehand;
position = wait(h);
% post processing
se=strel('disk',3);
erosion=imerode(h,se);
result_image=imsubtract(h,erosion);.
But, I got the following error:
Error using imerode
Expected input number 1, IM, to be one of these types:
numeric, logical
Instead its type was imfreehand.
Error in morphop>CheckInputImage (line 335)
validateattributes(A, {'numeric' 'logical'}, {'real' 'nonsparse'}, ...
Error in morphop>ParseInputs (line 166)
A = CheckInputImage(A, func_name);
Error in morphop (line 14)
[A,se,pre_pad,...
Error in imerode (line 123)
B = morphop(A,se,'erode',mfilename,varargin{:});
Error in program (line 155)
erosion=imerode(h,se);
Is it to do with erosion? What can be done in this case?
`
Following the advice in the matlab documentation try this:
I=input('image name: ','s');
img=imread(I);
figure, imshow(img);
h = imfreehand;
position = wait(h);
Edit:
The documentation suggests as an alternative
figure, imshow(img);
h = imfreehand(gca);
Try passing the handle of the plot to imfreehand()
I=input('image name: ','s');
img=double(imread(I));
figure;
ih=image(img);
h=imfreehand(ih)
Sorry, I don't have the image processing toolbox to test this.
Seems like converting your image (possibly uint8) to double causes a problem.
I would either do:
use the original coding of the image (for example img_uint8 = imread('coins.png') is coded using integers). The problem is that you won't probably be able to use imfreehand as it needs to read double or single precision float.
convert the image using img_double = double(imread('coins.png')) so that imfreehand will work. The conversion however causes a display problem that you can bypass with imshow(img_double,[]) that is an analogue of imshow(img_double, [min(min(img_double)), max(max(img_double))]). It forces imshow to correctly use the full range of data (255 Vs. 255.0)
The best option is therefore the second one.
To use imfreehand, #Try Hard gave a nice code h = imfreehand or h = imfreehand(gca)

Matlab Title Formatting

For matlab script, when I create a title for a plot, I use the following command:
title(['Input ', x, '; Output', y]);
However, this returns a newline character whenever I use ',' on the above string. So it looks like the following:
Input
xValue
Output
yValue
Anyone knows how to make these strings appear on the same line? Thanks.
From the output shown, I'm inferring that x and y are cell values. If so, you could use something like:
title(strcat('Input=>', num2str(cell2mat(x)), '; Output=>', num2str(cell2mat(y))))
The result would be as follows for x={1} and y={2}:
The reason you got the output as you did initially was that, since x and y were cells, MATLAB automatically converted your statement to
title([{'Input '}, x, {'; Output'}, y]);
meaning that you passed a cell array to title; as such, it displayed each part of the title in a separate line.
Now, if on the other hand, x and y were simple numbers, use:
title(strcat('Input=>', num2str(x), '; Output=>', num2str(y)))