Matlab, high quality plot, two legends - matlab

I would like to produce a plot with two y-axis and two legends, looking something like this:
I have modified a code I found online to produce a high-quality plot to use in reports/papers. I was wondering how you add a second y-axis in such a code? I have attached the matrix and code to produce the high-quality plot: https://drive.google.com/file/d/1aKZLFeoO1wmQ1P2tEiiucvOFI7PehkGL/view?usp=sharing
https://drive.google.com/file/d/1aKZLFeoO1wmQ1P2tEiiucvOFI7PehkGL/view?usp=sharing

NOTE: This is basically a comment, however, it grew too long, and I felt it was too important not to mention properly.
Reporting plots from Matlab should always, unless you have some very good excuse, be done using vector graphics, i.e. pdf, ps, eps or similar format. The reason for this is the quality, e.g. here I have taken your high-quality and the similar pdf-version and zoomed in.
The png version has artifacts. The reason for this is that the png (similar for jpg and more) is that the picture is saved using pixels, thus when you zoom the quality deteriorate.
The pdf version, which is made with vector graphics, save the vectors, thus when I zoom the pdf viewer can regenerate the pixels and maintain the same quality. As an added bonus, the vector-graphic version is typically smaller in size.
This is made in Matlab using
saveas(gcf,'myfigure.pdf')

Use yyaxis to add another plot with an axis. Take a look at the following modified portion of your code.
yyaxis left
plot(N(:,1),N(:,3)/(27.5*2),'b-','DisplayName','Location','LineWidth',lw); %<- Specify plot properites
yyaxis right
plot(N(:,1),N(:,4)/(27.5*2),'r-', 'DisplayName','NorthEast','LineWidth',lw); %<- Specify plot properites
legend('Location', 'NorthEast');

Related

MATLAB: Digitizing a plot with multiple variables and implementing the data

I have 8 plots which I want to implement in my Matlab code. These plots originate from several research papers, hence, I need to digitize them first in order to be able to use them.
An example of a plot is shown below:
This is basically a surface plot with three different variables. I know how to digitize a regular plot with just X and Y coordinates. However, how would one digitize a graph like this? I am quite unsure, hence, the question.
Also, If I would be able to obtain the data from this plot. How would you be able to utilize it in your code? Maybe with some interpolation and extrapolation between the given data points?
Any tips regarding this topic are welcome.
Thanks in advance
Here is what I would suggest:
Read the image in Matlab using imread.
Manually find the pixel position of the left bottom corner and the upper right corner
Using these pixels values and the real numerical value, it is simple to determine the x and y value of every pixel. I suggest you use meshgrid.
Knowing that the curves are in black, then remove every non-black pixel from the image, which leaves you only with the curves and the numbers.
Then use the function bwareaopen to remove the small objects (the numbers). Don't forget to invert the image to remove the black instead of the white.
Finally, by using point #3 and the result of point #6, you can manually extract the data of the graph. It won't be easy, but it will be feasible.
You will need the data for the three variables in order to create a plot in Matlab, which you can get either from the previous research or by estimating and interpolating values from the plot. Once you get the data though, there are two functions that you can use to make surface plots, surface and surf, surf is pretty much the same as surface but includes shading.
For interpolation and extrapolation it sounds like you might want to check out 2D interpolation, interp2. The interp2 function can also do extrapolation as well.
You should read the documentation for these functions and then post back with specific problems if you have any.

Matlab: How to avoid artefacts in filled contour plots

I am trying to export filled contour plots from Matlab as vector graphics to include in a Latex file. My current methodology is:
contourf(x,y,v_mag,20), axis([0,width,0,height]),daspect('manual') ;
grid off
colormap jet
h = colorbar;
caxis([0 v_lid])
h.Label.String = 'Velocity Magnitude (m/s)';
set(gcf,'renderer','painters')
export_fig('-painters', '-transparent', 'pdf', 'filename.pdf');
The problem with this method is that it produces artefacts (the white lines) which look like the following:
I understand that these white lines are the polygons defining the shaded areas which have invisible edges, and don't quite overlap (according to here). The problem is caused by the pdf viewer itself which tries to smooth the lines displayed on the screen (according to here). My problem is that most people viewing the document will not know this and will not know how to prevent the viewer doing this. So my questions is:
Is it possible to create a vector graphic of a filled contour plot from Matlab without these artefacts?
Eps produces the same problems. I have tried to use the SVG function but have not had any luck. I am trying to avoid using raster graphics due to the pixelation caused by zooming in. Any advice would be much appreciated.
EDIT - Additional info - Using Matlab v.2014b and Ghostscript v.9.15
This is an extremely frustrating issue for which there seems to be no solution (or even, few attempts at a solution), and it has been many years now. In summary, Matlab cannot cope with outputting artefact-free contour or surface plots (anything with complicated meshes or transparencies).
I can suggest a simple workaround that will work in most cases, where the colours or details of the underlying contour plot do not need to be preserved perfectly.
Output a version of the figure without lines in png format with high enough resolution.
Output a version of the figure without colours in pdf format. This should be free of any artefacts. If your figure it complicated and has many transparencies, you may need to output multiple versions building up the 'levels'.
Use Adobe Illustrator (or some equivalent) to perform a vectorized trace of the raster image. You may lose some detail here, but for simple contour plots with limited details, it will be converted easily to vectorized form.
Overlay the two images within Illustrator. Output in vector format.
This also allows you to use things like Illustrator's ability to compress pdfs.
If you don't want to toy with vectorizing the raster output, you can also simply replace steps 3-4 and combine a raster colour image with a vectorized line image. This would work well for complicated contour plots giving you crisp lines, but the ability to compress the underlying colours.
Eventually, MatLab 2013b doesn't have this problem. Furthermore the files it produces has much less volume. That is because MatLab 2013b composes vectorized image of big overlapping figures, while MatLab 2014b makes that awful meshing.
Here the first file was got with 2013b and the second with MatLab 2014b (I highlighted one of the polygons with red stroke to show the difference). The volumes differ in approximately 22 times (38 Kb vs. 844 Kb).
So it is not the viewer problem, it's how the image is exported from MatLab.
The issue is also discussed here Triangular split patches with painters renderer in MATLAB 2014b and above, but still no direct solution.

MATLAB: Interactive tool to "draw" a Plot?

Do you know a simple way to draw arbitrary splines or lines in a plot-figure? I've got the following figure which I created in powerpoint with more or less arbitrary spline-curve (blue) but I'd like to do the same in MATLAB now because of a better look in the final plot-output.
I'm now wondering if I've got to manually "find" data-values to draw some sort of spline (which looks roughly like the blue one below) myself or if there's maybe a tool where I can simply insert some points into a plot interactively and there's a curve fitted though it to create something similar!?
The green and red lines I can figure out myself (probably also have to plot them manually, do I)?!?
Thanks in advance!
EDIT
Okay I found a way myself doing it in MATLAB to gnerate a nice spline: Use splinetool, then either use an example or import some data and then you can interactively add and delete points until your spline looks roughly like it should. Then file->print to figure and then tools->edit plot! You can then delete everything you don't need, add title, xlabel and ylabel etc. and then export it to latex with e.g. matlab2tikz :-) Very nice stuff!!
According the purpose, print nice plots for the thesis, I have some out-of-Matlab recommendations.
1) plot everything as usual, you get a figure handle and an axes handle
h = figure( ... )
a = gca
2) use the data cursor function of the figure window and interactively insert the base points for your later splines. You can additional points by right-click.
t = linspace(0,2*pi,1000);
[x y] = deal(sin(t),cos(t))
Later you delete the "visual" part of the data tip inside Illustrator/Inkscape, if you just want to keep the anchor point of the vector graphic to snap your splines.
There is also the possibility of custom data tips: Tutorial at Matlab Central
3) I once wrote a function to nicely plot Matlab figures as vector graphic based PDFs. You can specify height, width and how much white margin around you want. You just need to pass figure and axes handle and the name:
function saveFigure( fig_handle, axes_handle, name , height , width , margin)
set(axes_handle,'LooseInset',get(gca,'TightInset'));
set(fig_handle, 'Units','centimeters','PaperUnits','centimeters')
% the last two parameters of 'Position' define the figure size
set(fig_handle,'Position',[-margin -margin width height],...
'PaperPosition',[0 0 width+margin height+margin],...
'PaperSize',[width+margin height+margin],...
'PaperPositionMode','auto',...
'InvertHardcopy', 'on',...
'Renderer','painters'... %recommended if there are no alphamaps
);
saveas(fig_handle,name,'pdf')
end
4) You get a PDF you could directly use for Latex - for use in MS Office use 'emf' (
Enhanced metafile) rather than 'pdf'. Open this file with Adobe Illustrator (preferable as it offers layers) or Inkskape (Open Source).
5) The datatips are recognized as graphical objects, you can catch them and draw a spline on them. For Illustrator I'd recommend to put the spline in another layer than the actual figure. Later you can just swap the figure and give the spline new anchor points. In Inkscape you could use the grouping function to keep everything together.
6) I'd say you save a lot of time over a only-Matlab-solution. Good look!

Save Spectrogram as an Image in MATLAB

I'm analyzing some sound clips using the spectrogram() function in MATLAB. I would like to save the spectrogram as an image (jpg, png, etc). But regardless of what image format I save the figure in, the resulting image always looks different ("spotty") from what I see in the figure.
Here's an example of the spectrograms: Matlab Figure vs. Saved Image
All I want is to save exactly what I see in the figure as an image. I've already tried saving the figure in all the image formats possible but all of them are producing the same "spotting" effect. I've also tried both manual saving (click on file -> save as) and programmatically using the print() and the saveas() functions. Same result every time.
Any help would be appreciated!
What is the data range of your spectrogram?
One of reasons might be that your spectrogram range is out of the [0,1] region for double images or [0,255] for uint* images (your white spots on saved image are suspiciously close to the local minima on MatLab figure).
Another guess might be that you are using imwrite function, in particular its imwrite(X,map,filename,fmt) syntax. MatLab documentation explains:
imwrite(X,map,filename,fmt) writes the indexed image in X and its associated colormap map to filename in the format specified by fmt. If X is of class uint8 or uint16, imwrite writes the actual values in the array to the file. If X is of class double, imwrite offsets the values in the array before writing, using uint8(X–1). map must be a valid MATLAB colormap. Note that most image file formats do not support colormaps with more than 256 entries.
so the uint8(X–1) might be the source of the white spots.
Though have no idea why they appear after print()'ing.
I found a work-around for this problem by using the pcolor() function, which is essentially a rotated surf() function plotted in a grid format (doc). After tinkering with the spectrogram() function more, I'm convinced that these "spotting" artifacts have nothing to do with the data format, property, or scale. The problem seems to lie in the way MATLAB plots and visualizes 3D plots. I tried plotting with the mesh() function as well and it produced a different kind of "spotting" effect. pcolor() works because it's a 2D visualization of a 3D plot.
This is how spectrogram() plots the image using surf() (adapted from the doc):
[S,T,F,P] = spectrogram(X,256,250,256,2000);
surf(T,F,abs(S),'EdgeColor','none');
axis tight; view(0,90);
... and this is how to use pcolor() to plot a save-friendly image:
[S,T,F,P] = spectrogram(X,256,250,256,2000);
h = pcolor(T,F,abs(S));
set(h,'EdgeColor','none');
The white spots are an OpenGL issue, which is the renderer used in spectrogram()'s internal call to surf().
Since you are interested in plotting a 2D visualization, change the renderer for the current figure to zbuffer:
set(gcf, 'renderer', 'zbuffer');
where gcf means "get current figure". The white spots are now gone.
Note that you can also select the zbuffer renderer when you create the figure, before calling spectrogram():
myNewFig = figure('renderer','zbuffer');

Matlab: surface plot not working

I have a surface plot I'm trying to do. x is an 11 element vector, y a 300 element vector and z a 300*11 element matrix.
When I try to plot it like this:
surf(x y z)
The surface plot doesn't show up. The axes are there but there is no surface plot.
However, if for some reason I do a surface plot of a subset of the matrix like this:
surf(x y(1:31) z(1:31,:))
Then it works and the plot shows up.
As soon as I increase the number in the brackets to 32 it stops working. If I change the range from 2:32 then it works, so it's nothing to do with the data just the size of the matrices.
What's going on here? How do I fix it?
P.S I'd attach the code but it's a bit long and complex, and imports .txt files to load into the x and y vectors.
Sometimes, it can help to change Matlab's figure renderer, which is basically the backend that performs the drawing. Options are painters, zbuffer, and OpenGL.
Since it is a figure property, you can apply it to a specific figure, e.g.:
set(gcf(), 'Renderer', 'painters')
or update the default figure properties (if always needed, you could put it in your user-specific startup.m):
set(0, 'Renderer', 'painters')
Similarly, to get the current Renderer state, use get instead of set:
get(gcf(), 'Renderer')
Different renderers have different performance properties (e.g. OpenGL renderer can use hardware acceleration, if supported), but also different quirks (in my experience, frame capturing using getframe() works with some renderers while using remote desktop login, but not all). While I don't know the exact reason for your problem, it may be one of these weird quirks, so try changing the renderer.
From the Renderer property documentation:
Rendering method used for screen and printing.
Selects the method used to render MATLAB graphics. The choices are:
painters — The original rendering method used by MATLAB is faster when the figure contains only simple or small graphics objects.
zbuffer — MATLAB draws graphics objects faster and more accurately because it colors objects on a per-pixel basis and MATLAB renders only those pixels that are visible in the scene (thus eliminating front-to-back sorting errors). Note that this method can consume a lot of system memory if MATLAB is displaying a complex scene.
OpenGL — OpenGL is a renderer that is available on many computer systems. This renderer is generally faster than painters or zbuffer and in some cases enables MATLAB to access graphics hardware that is available on some systems.
Looks at the change in the min/max values of the axis along the left side (y-axis) and the top (z-axis). I think it's still there but it's just very very small.
Try setting the axis afterwards like this:
axis([6E-6 8E-6 9.2E14 10E14 0.96 1.06 -1 1])
Note: the E-6 might be E-8, I can't really tell from the image...
This is based off the code of: axis([xmin xmax ymin ymax zmin zmax cmin cmax])