I am making a script to plot burst signal events on a pesudo-waterfall.
With x-axis being frequencyand y-axis being time I plot a line from
[event-frequency event-startTimeStamp] to [event-frequency event-endTimeStamp]
to represent each burst.
I am using the following code:
tstart = datenum(0,0,0,0,0,0);
tend = datenum(0,0,0,0,0,1);
timeInterval=tend-tstart;
xlim([0 10]);
hold on;
cla;
timeAxis = linspace(tstart, tend, 100);
set(gca,'YTick',timeAxis,'FontSize',6,'YDir','reverse');
datetick('y','HH:MM::SS.FFF','keepticks');
plot([1 1],[tstart tstart+timeInterval/4]);
plot([2 2],[tstart+timeInterval/8 tstart+timeInterval/2]);
tstart=tstart + timeInterval;
tend=tend + timeInterval;
The paragraph from the cla can be repeated to plot 'signals' in later time increments of one second. This works fine.
If I change the first two lines to the following: edit: using this value cuz it's the timestamp of the first burst
tstart = datenum(2011,6,13,15,10,40.999);
tend = tstart + datenum(0,0,0,0,0,1);
The plot looks horrible and the labels get messed up into a black mess. I can't work out why it's happening. Anybody know?
(copy-pastable code if you wanna try it out)
-Daniel
Try not showing all the tick marks, instead only a subset of them. Something along the lines:
set(gca,'YTick',timeAxis(1:10:end))
Also read up on DATETICK options: 'keepticks' and 'keeplimits'
Related
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.
I am having a trouble in showing a plot which runs from 0-10K.
Currently I have calculation running from 0-100 and it looks great.
Currently:
Now I want to add one X points which is 10K
And it looks this way:
How do I keep it from 0-100 and show only then the jumps to 10K ?
Is it even possible ?
The problem is that 0-100 is very small portion in 10K so it looks bad.
You could plot your one outlier point at a closer x coordinate, then adjust the XTick and XTickLabel properties to make it appear as though there is a break in the plot range. For example:
plot([1:20 25], 1./[1:20 10000]);
set(gca, 'XTick', [2:2:20 25], ...
'XTickLabel', strtrim(cellstr(int2str([2:2:20 10000].'))));
And here's the plot this creates:
Maybe you can try to sample the x points (for the second plot) in different gaps. You can combine two arrays of x sample points (each array with a fixed gap but the first gap is much smaller than the second gap). then you plot the combined points.
Here's a code example:
clear;
close all;
clc;
gap1 = 0.2;
x_left = 1:gap1:3;
gap2 = 0.5;
x_right = 3+gap2:gap2:6;
x_ticks_for_plot = [x_left x_right];
x=x_ticks_for_plot;
y = sin(x);
plot(x,y);
xticks(x_ticks_for_plot);
And the plot:
In your case the second gap should be much bigger than the first but it's the same idea.
I'm trying to have a textbox in MATLAB on a spinning plot, but I don't want the textbox to change its position relative to the figure. I thought that 'units','normalized' in the text function would do it, but it's not quite working, as the example below illustrates. I suppose I could use uicontrol but I'd like to use Greek letters and I can't get uicontrol looking quite as good as text. The following example recreates my problem. You'll notice the text box moves as the plot spins, but I'd like it to just stay in the top left region where it starts. Thank you!
part_x = rand(1000,3)-.5; %generate random 3D coordinates to scatter
fig1 = figure;
scatter3(part_x(:,1), part_x(:,2), part_x(:,3))
axis equal vis3d
axis([-1 1 -1 1 -1 1])
set(fig1,'color','w')
for tau = 1:150
view(tau+20,30); %spin the plot
pause(.01)
if tau~=1; delete(tau_text); end; %delete the previous text if it exists
tau_text = text(.1,.7,...
['\tau = ',num2str(tau)],...
'units','normalized',... %text coordinates relative to figure?
'Margin',3,... %these last 3 lines make it look nice
'edgecolor','k',...
'backgroundcolor','w');
end
Several things:
1) As you found out - using an annotation object instead of text object is the way to go. The difference is explained very nicely here.
2) You should only create the annotation once and then modify its string instead of deleting and recreating it on every iteration.
Finally:
part_x = rand(1000,3)-.5;
fig1 = figure;
scatter3(part_x(:,1), part_x(:,2), part_x(:,3))
axis equal vis3d
axis([-1 1 -1 1 -1 1])
set(fig1,'color','w')
%// Create the text outside the loop:
tau_text = annotation('textbox',[0.2 0.8 0.1 0.05],...
'string','\tau = NaN',...
'Margin',4,...
'edgecolor','k',...
'backgroundcolor','w',...
'LineWidth',1);
for tau = 1:150
view(tau+20,30);
pause(.01)
set(tau_text,'String',['\tau = ',num2str(tau)]); %// Modify the string
end
Notes:
1) It is interesting to note that #Otto's suggestion of using legend results in the creation of an axes (because this is what a legend object is - an axes with annotation children). You could then position the legend manually, and get its location using either get(gco,'position') (assuming it was the last thing you clicked) or more generally get(findobj('tag','legend'),'position'). Afterwards, whenever you create the legend, you can just set its position to the one you previously got. You could also get rid of the line\marker inside the legend by deleting the appropriate child of type line from the legend, e.g.:
ezplot('sin(x)');
hLeg = legend('\tauex\tau');
delete(findobj(findobj('Tag','legend'),'Type','line'));
hA1 = findobj(findobj('Tag','legend'),'Type','text');
set(hA1,'Position',[0.5,0.5,0],'HorizontalAlignment','center');
It is of course also possible to manipulate the legend's String using its handle (hA1) directly.
2) This post on UndocumentedMatlab discusses the behavior of annotation objects and some undocumented ways to manipulate them.
You could use
legend(['\tau = ',num2str(tau)],'Location','NorthWestOutside')
Thank you Dev-iL! annotation works much better for this purpose than text and the implementation is very similar. And thank you for the advice on modifying the string rather than deleting an recreating it.
Here is the code now, working much better:
part_x = rand(1000,3)-.5; %generate random 3D coordinates to scatter
fig1 = figure;
scatter3(part_x(:,1), part_x(:,2), part_x(:,3))
axis equal vis3d
axis([-1 1 -1 1 -1 1])
set(fig1,'color','w')
tau_text = annotation('textbox',[0.2 0.8 0.1 0.05],...
'string','',...
'Margin',4,... %these last 4 lines make it look nice
'edgecolor','k',...
'backgroundcolor','w',...
'LineWidth',1);
for tau = 1:150
view(tau+20,30); %spin the plot
pause(.01)
set(tau_text,'String',['\tau = ',num2str(tau)]);
end
I'm trying to find a way to nicely plot my measurement data of digital signals.
So I have my data available as csv and mat file, exported from an Agilent Oscilloscope. The reason I'm not just taking a screen shot of the Oscilloscope screen is that I need to be more flexible (make several plots with one set of data, only showing some of the lines). Also I need to be able to change the plot in a month or two so my only option is creating a plot from the data with a computer.
What I'm trying to achieve is something similar to this picture:
The only thing missing on that pic is a yaxis with 0 and 1 lines.
My first try was to make a similar plot with Matlab. Here's what I got:
What's definitely missing is that the signal names are right next to the actual line and also 0 and 1 ticks on the y-axis.
I'm not even sure if Matlab is the right tool for this and I hope you guys can give me some hints/a solution on how to make my plots :-)
Here's my Matlab code:
clear;
close all;
clc;
MD.RAW = load('Daten/UVLOT1 debounced 0.mat'); % get MeasurementData
MD.N(1) = {'INIT\_DONE'};
MD.N(2) = {'CONF\_DONE'};
MD.N(3) = {'NSDN'};
MD.N(4) = {'NRST'};
MD.N(5) = {'1V2GD'};
MD.N(6) = {'2V5GD'};
MD.N(7) = {'3V3GD'};
MD.N(8) = {'5VGD'};
MD.N(9) = {'NERR'};
MD.N(10) = {'PGD'};
MD.N(11) = {'FGD'};
MD.N(12) = {'IGAGD'};
MD.N(13) = {'GT1'};
MD.N(14) = {'NERRA'};
MD.N(15) = {'GT1D'};
MD.N(16) = {'GB1D'};
% concat vectors into one matrix
MD.D = [MD.RAW.Trace_D0, MD.RAW.Trace_D1(:,2), MD.RAW.Trace_D2(:,2), MD.RAW.Trace_D3(:,2), ...
MD.RAW.Trace_D4(:,2), MD.RAW.Trace_D5(:,2), MD.RAW.Trace_D6(:,2), MD.RAW.Trace_D7(:,2), ...
MD.RAW.Trace_D8(:,2), MD.RAW.Trace_D9(:,2), MD.RAW.Trace_D10(:,2), MD.RAW.Trace_D11(:,2), ...
MD.RAW.Trace_D12(:,2), MD.RAW.Trace_D13(:,2), MD.RAW.Trace_D14(:,2), MD.RAW.Trace_D15(:,2)];
cm = hsv(size(MD.D,2)); % make colormap for plot
figure;
hold on;
% change timebase to ns
MD.D(:,1) = MD.D(:,1) * 1e9;
% plot lines
for i=2:1:size(MD.D,2)
plot(MD.D(:,1), MD.D(:,i)+(i-2)*1.5, 'color', cm(i-1,:));
end
hold off;
legend(MD.N, 'Location', 'EastOutside');
xlabel('Zeit [ns]'); % x axis label
title('Messwerte'); % title
set(gca, 'ytick', []); % hide y axis
Thank you guys for your help!
Dan
EDIT:
Here's a pic what I basically want. I added the signal names via text now the only thing that's missing are the 0, 1 ticks. They are correct for the init done signal. Now I just need them repeated instead of the other numbers on the y axis (sorry, kinda hard to explain :-)
So as written in my comment to the question. For appending Names to each signal I would recommend searching the documentation of how to append text to graph. There you get many different ways how to do it. You can change the position (above, below) and the exact point of data. As an example you could use:
text(x_data, y_data, Var_Name,'VerticalAlignment','top');
Here (x_data, y_data) is the data point where you want to append the text and Var_Name is the name you want to append.
For the second question of how to get a y-data which contains 0 and 1 values for each signal. I would do it by creating your signal the way, that your first signal has values of 0 and 1. The next signal is drawn about 2 higher. Thus it changes from 2 to 3 and so on. That way when you turn on y-axis (grid on) you get values at each integer (obviously you can change that to other values if you prefer less distance between 2 signals). Then you can relabel the y-axis using the documentation of axes (check the last part, because the documentation is quite long) and the set() function:
set(gca, 'YTick',0:1:last_entry, 'YTickLabel',new_y_label(0:1:last_entry))
Here last_entry is 2*No_Signals-1 and new_y_label is an array which is constructed of 0,1,0,1,0,....
For viewing y axis, you can turn the grid('on') option. However, you cannot chage the way the legends appear unless you resize it in the matlab figure. If you really want you can insert separate textboxes below each of the signal plots by using the insert ->Textbox option and then change the property (linestyle) of the textbox to none to get the exact same plot as above.
This is the end result and all my code, in case anybody else wants to use the good old ctrl-v ;-)
Code:
clear;
close all;
clc;
MD.RAW = load('Daten/UVLOT1 debounced 0.mat'); % get MeasurementData
MD.N(1) = {'INIT\_DONE'};
MD.N(2) = {'CONF\_DONE'};
MD.N(3) = {'NSDN'};
MD.N(4) = {'NRST'};
MD.N(5) = {'1V2GD'};
MD.N(6) = {'2V5GD'};
MD.N(7) = {'3V3GD'};
MD.N(8) = {'5VGD'};
MD.N(9) = {'NERR'};
MD.N(10) = {'PGD'};
MD.N(11) = {'FGD'};
MD.N(12) = {'IGAGD'};
MD.N(13) = {'GT1'};
MD.N(14) = {'NERRA'};
MD.N(15) = {'GT1D'};
MD.N(16) = {'GB1D'};
% concat vectors into one matrix
MD.D = [MD.RAW.Trace_D0, MD.RAW.Trace_D1(:,2), MD.RAW.Trace_D2(:,2), MD.RAW.Trace_D3(:,2), ...
MD.RAW.Trace_D4(:,2), MD.RAW.Trace_D5(:,2), MD.RAW.Trace_D6(:,2), MD.RAW.Trace_D7(:,2), ...
MD.RAW.Trace_D8(:,2), MD.RAW.Trace_D9(:,2), MD.RAW.Trace_D10(:,2), MD.RAW.Trace_D11(:,2), ...
MD.RAW.Trace_D12(:,2), MD.RAW.Trace_D13(:,2), MD.RAW.Trace_D14(:,2), MD.RAW.Trace_D15(:,2)];
cm = hsv(size(MD.D,2)); % make colormap for plot
figure;
hold on;
% change timebase to ns
MD.D(:,1) = MD.D(:,1) * 1e9;
% plot lines
for i=2:1:size(MD.D,2)
plot(MD.D(:,1), MD.D(:,i)+(i-2)*2, 'color', cm(i-1,:));
text(MD.D(2,1), (i-2)*2+.5, MD.N(i-1));
end
hold off;
%legend(MD.N, 'Location', 'EastOutside');
xlabel('Zeit [ns]'); % x axis label
title('Messwerte'); % title
% make y axis and grid the way I want it
set(gca, 'ytick', 0:size(MD.D,2)*2-3);
grid off;
set(gca,'ygrid','on');
set(gca, 'YTickLabel', {'0'; '1'});
ylim([-1,(size(MD.D,2)-1)*2]);
I am about to present my work that I have created in MATLAB, but I am having trouble manipulating my data into a presentable form using the plot function.
My code looks like this:
[inputname, pathname] = uigetfile('*.wav', 'Select WAV-file');
thumb1 = inputname; %# Get filename information
fprintf('\n%s is being turned into a 30s thumbnail...\n', thumb1);
fprintf('Please wait..!\n\n');
%# load the signal
[y, fs, nb] = wavread(thumb1);
y = mean(y,2); %# stereo, take avrg of 2 channels
%# Calculate frame energy
fWidth = round(fs*10e-3); %# 10ms
numFrames = floor(length(y)/fWidth);
energy = zeros(1,numFrames);
for f=1:numFrames
energy(f) = sum( y((f-1)*fWidth+1:f*fWidth).^2 );
end
Basically I want to plot the energy of the track over time (in seconds).
plot(energy)
nearly does what I require, but I have an unusual amount of blank space at the end of the track which is not present in the .wav file. This blank space is the main issue that I'm having. Ideally I would like the x axis to be displayed in seconds! Any help would be much appreciated.
edit1:
Using the first suggested method:
There's also
axis tight
which sets "tight" limits for the axis. See doc: http://www.mathworks.com/help/techdoc/ref/axis.html
By default, Matlab uses some heuristic rules to choose the limits of graph scales. You can override them with the xlim and ylim functions (e.g. xlim([0 length(energy)])).
If you want to plot against actual time, you can do something like:
t = (0:length(energy)-1) / fs; % Timebase in seconds
plot(t, energy);