How to make matlab graphs look better - matlab

I have to use these graphs for a powerpoint presentation and I wanted to know how I could spruce it up to make it look more presentable and inviting. I can't even change the fontsize. Anything that can make the graph look more inviting will get the thumbs up as the answer.This is done in matlab by the way.
a = load('2small1big_heating');
m = load('2small1big_cooling');
xdata = m(:,5)
ydata = m(:,4)
pPoly = polyfit(xdata, ydata, 1); % Linear fit of xdata vs ydata
linePointsX = [min(xdata) max(xdata)]; % find left and right x values
linePointsY = polyval(pPoly,[min(xdata),max(xdata)]); % find y valuesfigure(1)
plot(m(:,5),m(:,4)/6269,'bo')
hold on
plot(a(:,5),a(:,4)/6269,'ro')
title('2Small1Big- Heating and Cooling')
legend('Cooling','Heating')
ylabel('Potential Energy (eV)');
xlabel('Temperature (K)');
Thanks.

Here's a few things that I find myself doing every time I need a plot to look presentable.
Change the fontsize to 14.
set(gca,'fontsize',14);
Make linewidth larger and/or markersize larger
plot(x,y,'r','linewidth',2);
plot(x,2*y,'b.','Markersize',18);
Sometimes turn grid on
grid on
To put it all together
x = 1:20;
y = rand(1,20).*x;
figure; hold on;
set(gca,'fontsize',14);
a = plot(x,y,'r','linewidth',2);
plot(x,2*y,'b.','Markersize',18);
grid on
xlabel('X (x units)');
ylabel('Important Stuff');
title('VERY IMPORTANT PLOT');

Most importantly - change to the still undocumented and yet not officially supported HG2-Graphics-Engine. The improvements you get are better than anything else you could achieve with the "old" functionality.
It already works really nice, I'm not seeing a lot of bugs. There are issues, but they are solvable.
Apart from that, you could use nicer fonts, especially if you want to use the plots in combination with Latex. You can set it globally, as well as the fontsize:
set(0,'defaultAxesFontName', 'CMU Serif Roman')
set(0,'defaultAxesFontSize', 12)
Also use the Latex-Interpreter for your labels:
y_label = {'$$ \mathrm{Mag} ( G ) \rm ~in~ dB$$','interpreter','latex';
x_label = {'$$ f \rm ~in~ Hz$$','interpreter','latex'};
With some easy steps, you get much better results. Mostly apparent for plots with logarithmic scale:

Related

Logarithmic x axis in a stackplot MatLab

I'm trying to make a stack plot from a table, to present several variables with the same x-axis. however, I want the x-axis to be logarithmic. I couldn't find any way in stackplot documentation. Does anyone have any suggestions on how I can solve this?
I have tried using subplots instead, however, that way my graphs would not fit all on one page and I would have a lot of white space between the subplots. Therefore, I chose stackplot to make it more nice and less space-consuming.
tbl = readtable('usage.csv');
newYlabels = {'Heating (kWh/year)','Cooling (kWh/year)','Electricity (kWh/year)'};
stackedplot(tbl,[{2:16},{17:27},{28:35}],'XVariable',[1],'DisplayLabels',newYlabels);
Here is the output of the code:
Here is an image of what I'm trying to make, but the x-axis needs to be the real variable (\beta) in logarithmic scale
stackedplot has unfortunately no logarithmic axes option, and since it creates a StackedAxes instead of a normal Axes object, there is no way to changes this.
If the only reason you want to use stackedplot is to have less white-space, you might want to check out tight_subplot on the Matlab FEX. This would allow you to just do: set(ax, 'XScale', 'log').
You can however take the log of your x-data, and add that to the table:
tbl = readtable('outages.csv'); % sample data
tbl = sortrows(tbl, 'OutageTime'); % sort by date
% make x vector; for example just row numbers
x = (1:size(tbl,1)).';
xlog = log10(x);
% add x to table
tbl.Xlog = xlog;
tbl.X = x;
% plot normal x
f = figure(1); clf;
s = stackedplot(tbl, {'Loss'}, 'XVariable', 'X');
xlabel('rows');
% plot log(x)
f = figure(2); clf;
s = stackedplot(tbl, {'Loss'}, 'XVariable', 'Xlog');
xlabel('log(rows)')
Normal:
Log:

Matlab : save a spectrogram in a variable and display it

What I want is quite simple, or so I thought. I have many spectograms to compute and display which is time consuming to compute, so I want to save them in variables to display them without redoing the computation. The problem is that I can't find a way to plot them like they appear if I directly use the function spectogram().
Example :
sampling_rate = 100;
spectrogram(data,100,20,[],sampling_rate,'yaxis');
caxis([-20 60])
This displays a spectogram exactly as I want it :
I read the doc and I understand that I can save the results by doing something like this :
[S,F,T] = spectrogram(data,100,20,[],sampling_rate);
Also, I know that the function spectogram internally calls surf().
I found this post that seems to give a solution to my problem by doing this :
[S,F,T] = spectrogram(data,100,20,[],sampling_rate);
surf(T,F,abs(S),'EdgeColor','none');
axis tight; view(0,90);
But I get this plot, which is far from what I expected:
The axis labels and colorbar are gone, and the colors are completely not scaled. If I do this manually by adding colorbar; caxis([-20 60]); as previously, I get this thing:
Isn't there a simple solution to save a spectogram and display it on command ?
Like S = spectogram(...) then plot(S)?
If the OP's answer works more or less as expected, then the following shorter code should do the same:
[S,F,T,P] = spectrogram(data(1:3000),100,20,[],sampling_rate);
h = imagesc(T,F,10*log10(P),[-20,60]);
xlabel('Time (secs)')
ylabel('Frequency (Hz)')
colorbar;
(I don't have the data to test it with.) Note that here the x and y ticks are set automatically. If you want to select seconds, minutes, hours depending on the scale of T, you could do:
lab = 'Time (secs)';
if T(end) > 60*60*3
T = T/(60*60);
lab = 'Time (hours)';
elseif T(end) > 60*3
T = T/60;
lab = 'Time (mins)'
end
h = imagesc(T,F,10*log10(P),[-20,60]);
xlabel(lab)
ylabel('Frequency (Hz)')
colorbar;
I found a beginning of solution.
If I write :
[S,F,T,P] = spectrogram(data(1:3000),100,20,[],sampling_rate);
P saves the spectral power density in a matrix, which is quite convenient to plot without forgetting to add 10*log10(P):
h = pcolor(10*log10(P));
colorbar;
caxis([-20 60]);
set(h,'EdgeColor','none')
And I get this which is much better:
But I'm still missing the time and frequency axis, because it currently displays the dimension of the matrix P.
Edit:
I finally found some sort of solution which would be dealing with the axis manually. The display of the time is still terrible and I'm certain there is a better way but here we go:
[S,F,T,P] = spectrogram(data(1001:3000),100,50,[],sampling_rate);
h = pcolor(10*log10(P));
cb = colorbar;
caxis([-20 60]);
ylabel(cb, 'Power/frequency (dB/Hz')
set(h,'EdgeColor','none')
xticks(0:round(size(P,2)/6):size(P,2))
xt = xticks;
xticklabels([T(xt(2)) T(xt(2:end))]);
xlabel('Time (secs)');
yticks([0:13:size(P,1) size(P,1)])
yt = yticks;
yticklabels(0:5:50);
ylabel('Frequency (Hz)')
The time is saved in the vector T which is decently convenient in order to apply it on the x label. The frequency is stored F but in my case it'll always be between 0-50Hz so I wrote it manually.
I hope it'll help some people, and if you know how to properly set the time axis with automatic labelisation (sec, min, hours set automatically depending on the duration), by all means I would love to know.

Rescaling Y axis in a plot

I am trying to adjust the y axis and change it to be from [0 2.5] and to show that it has to be multiplied by a factor of 1000.
Obviously setting the limit with ylim=([0 25]) doesn't work and I can't find a way to do it.
Using to plot:
AveTime = 1.0e+03 * [0.0020, 0.0291, 0.1279, 0.3061, 2.0599];
STDtime = [0.0519, 0.0117, 0.0166, 0.0071, 0.0165];
errorbar([10,25,50,75,100], AveTime, STDtime);
I believe this is what you need, it should work for Matlab versions >= 2014b:
ax = gca;
ax.YAxis.Exponent = 3;
Here's a code example:
clear;
close all;
clc;
x=1:10:1000;
y=3*x;
plot(x,y);
ax = gca;
ax.YAxis.Exponent = 3;
And the plot:
Here is a workaround:
Get the YTick𝘴, divide them by 1000 and set them as YTickLabel𝘴.
set(gca,'YTickLabel',get(gca,'YTick')/1000);
In MATLAB R2014b or later, you can also use:
ax=gca;
ax.YTickLabel= ax.YTick/1000;
On the downside, as Hoki mentioned in the comments,
This is good but only for the final rendering of the figure (if you just want to look/print it). Once you override the YTickLabel, their mode change from auto to manual and any zoom/pan or modification of the axis limit will keep the existing tick labels which may be obsolete after the figure modification.

How to let the figure be displayed completely when we plot using MATLAB?

I plot using the following code in MATLAB. But the figure cannot be displayed completely as the picture shows below (the legend is hidden). What kind of parameters should I change to let the figure be shown completely?
clear;
clc;
close all;
y_lim = 1.5e9;
front_size = 20;
front_size2 = 16;
leg_font = 18;
leg_font2 = 12;
white_x = 0.06;
white_y = 0.105;
size_y = 0.87;
size_x = 0.9;
time_comp = figure('Name','Time Comparison');
set (time_comp,'Position',[0,0,700,500]);
hold on;
t = [6.335, 592.26, 2978, 19553.09, 736377, 2310000, 5808011.95, 1067732740];
time = [t; t; t; t];
box on
ylim([1 y_lim]);
bar_time = bar(time,'group','LineWidth',1,'BarWidth',1);
set(gca,'yscale','log');
xlabel_name = {'Data1', 'Data2', 'Data3', 'Data4'};
set(gca,'xtick', 1:1:4,'xticklabel', xlabel_name, 'FontSize', front_size2);
ylabel('Running time (in msec)', 'FontSize', front_size2);
set(gca,'position',[white_y white_x size_y size_x])
set(bar_time(1),'DisplayName','Method1');
set(bar_time(2),'DisplayName','Method2');
set(bar_time(3),'DisplayName','Method3');
set(bar_time(4),'DisplayName','Method4');
set(bar_time(5),'DisplayName','Method5');
set(bar_time(6),'DisplayName','Method6');
set(bar_time(7),'DisplayName','Method7');
set(bar_time(8),'DisplayName','Method8');
legend_time = legend(bar_time(1:8), 'Location','Northwest');
set(legend_time,'YColor',[1 1 1],'XColor',[1 1 1], 'Position',[1.005 0.045 0.155 0.926],'FontSize', leg_font2);
When you are setting the properties of the legend, the value of 'position' you are defining it as [1.005 0.045 0.155 0.926], the values are normalized to the size of the plot, that means that 1.005 is going to be slightly outside of your plot. Modify this value and you should be good
Edit: also change the value of your size_y if you want to avoid overlapping
To things that come to mind:
-1st) You should check if the legend's position is indeed normalized, so you can use the 0-1 range in the figure.
-2nd) You may want to squeeze the rest of the graphic by changing the ActivePositionProperty to 'OuterPosition' and then change the OuterPosition property according to your will. This should neatly resized the plot and provide space to show the legend
I hope it clears some things for you.
The position property of legend takes normalized value to the aspect of current figure size. Four-element vector of the form [left, bottom, width, height] defined the size and location of your legend.
Imagining the size of your figure is 1, the position you set for your legend [1.005 0.045 0.155 0.926] is very tall and out of figure's display boundary. You have a number a approaches to resolve this issue.
Set a new position. Use values that is rather smaller and well-placed at the corner. This solution is usually not ideal because you have to experiment various times to your satisfaction.
Increase figure size. By setting new size of your figure, the problem can sometimes be solved. You may use set(gcf,'Position',[0 0 800 600]) to gain more space to accommodate you legend. This solution may be convenient but not ideal to use alone if you have a lot of groups to display in one graph. We can, however, use this option to fine-tune our final production.
Use Location and Orientation property. Matlab already has several good preset locations. Why not let Matlab give you a hand so we can focus on other more important staff? Location properties with Outside values is especially helpful. In some cases that vertical legend display does not fit the figure, we can set the Orientation property to horizontal.
Let try replace the following code for you last line
set(legend_time,'FontSize', leg_font2,'Orientation','vertical','Location','EastOutside','Box','off');
or we can combine method 2 and 3 in different way with horizontal orientation.
set (time_comp,'Position',[0,0,1000,500]);
set(legend_time,'FontSize', leg_font2, 'Orientation', 'Horizontal', 'Location', 'northoutside','Box', 'off');
By the way, you may found more clues using their well-written documentation Legend Properties

Figure legend is being cut off MATLAB

I'm trying to plot 81 variables into one plot in MATLAB and I need a legend with 81 respective labels. I've managed to separate the legend into several lines such that it would fit the figure better but still, being this large, the legend apears cut off:
is there any way to solve this problem, so that all the legend appears in the figure?
Thank you in advance
In my experience, the legend is not manageable once the number of plots becomes so large.
You could try and hack this out by hand by trying to make a compact legend my manually moving the legend lines and text boxes around individually--but I fear this way will ultimately make you unhappy. If you want, you could start playing with the legend pieces by writing something like:
hl = legend(uniqueHandles, myNames);
hlc = get(hl, 'children');
This may not be possible and MATLAB will resist you. Instead, consider that a legend with 81 different colors becomes very hard to manage and you can't really tell the colors apart anyway. Instead of trying to get them all to fit I recommend grouping them into different colors and styles and then only showing 3-7 different sets like this:
This could be further improved by customizing the data tip so that when you click on a line it gives you more detail.
I put together some basic code to show how you might do this. It has some shortcomings. Regardless, in this example I plot everything at once then go back and group the colors together. I then pick out a representative line from each grouping and use it as an example in the legend. You could also plot everything, color it correctly, and then plot a new line in the existing axis with a value nan and use THOSE in the legend.
(edit) I also noted that you have grouped the colors already for some of them, so this should flow naturally from the work you've already done. If nothing else, you could grab the handles from every third entry and then only have 27 items in your legend... but best if you can reduce it further.
The example to create the above image is as follows:
%% Setup the problem:
nd = 81;
nx = 256;
data = zeros(nx,nd);
t = linspace(0, 2*pi, nx);
%% We divide the data into 3 groups and set a color for each. This calculation then notes what group each line belongs to:
myCategory = ceil((1:nd)/27);
myColor = myColors(myCategory)';
myColors = ['r', 'b', 'g'];
myNames = {'1 to 27', '28 to 54', '55 to 81'};
%% Make a simple set of data:
randn('seed', 1982);
dt = 0;
for ind = 1:nd
dt = dt+randn/5;
data(:, ind) = sin(t+dt) + dt*cos(t);
end
%% Plot all at once:
figure(33);
clf;
h = plot(data);
%% find the unique entries and choose one representative line for the legend.
%% We then use the handles of these lines to create the legend:
lastColor = -1;
uniqueHandles = [];
for ind = 1:nd
set(h(ind), 'color', myColor(ind));
if lastColor ~= myColor(ind)
lastColor = myColor(ind);
uniqueHandles(end+1) = h(ind);
end
end
% make the legend:
legend(uniqueHandles, myNames);