Setting physical (screen) size of an axis in MATLAB - matlab

I thought this problem would be trivial but I haven't been able to figure it out. I have two 3D figures, representing two data sets that are of different physical size (ie. one might represent something 10cm wide, one 20cm wide). I non-dimensionalize everything (so width goes from 0 to 1) and then I use daspect to change the aspect ratio of the plot so that the width appears to change between the plots, even though the axis limits do not (I set these to be constant).
When I plot them, in different figures, however, MATLAB automatically scales the axis to fit in the figure. This means that my objects change size slightly, whilst I want them to keep the x and z scales exactly the same.
Is there some way I can manually set how many pixels one unit of an axis takes up? You can see in the images that the scales on the z axis of the two figures are different, ie. the same length in zaxis units takes up different lengths in pixels.
The code I used for the axes, view, and aspect ratio is:
xlim([-0.3 .6])
ylim([-.8 .8])
zlim([-0.2 1.3])
view([60 15])
daspect([1/268.3 1/(99.9730*width) 1/74])
James

Related

Limit of Decreasing Plot Size in MATLAB

I use MATLAB R2021b. I have a 10x10 data array and I am using contourf function to plot the data. By default, MATLAB gives me a figure with 1120x840 pixels.
I know that I can use the command set(gcf, 'position', [700, 700, 100, 100]) to decrease the size of the figure. And I get a figure with 200x200 pixels. I decided to shrink the value in the set function by half to get a 100x100 figure.
However, when I try to do set(gcf, 'position', [700, 700, 50, 50]) , I got a figure with size 100x160. No matter how much further I decrease the value in the set function, the second dimension of the figure remained at 160 pixels. And there's no problem with the first dimension -- it can shrink with the value in the set function.
Does anyone know what's the problem here? My goal is to get a figure with 100x100 pixels.
Thank you very much for any advice!
MATLAB has always had a minimal size for figure windows. A smaller window cannot contain the minimal set of menus and toolbar buttons.
But you don’t need a small window to export a small plot.
When exporting a plot, MATLAB uses the “PaperPosition” and “PaperUnits” figure properties. Set the units to pixels and the size to your required sizes to export the figure in those sizes.
There are of course other alternatives:
Set the axes to your required sizes, then export only the axes area (or crop the produced image to size).
Export a figure at twice (or four times) the size, then resample by a factor 1/2 (or 1/4).
If you’re not exporting, and just want a small display on the screen, consider putting multiple things in the same figure window, all you need to do is control the axes’s “Position” property.
I am the original poster. I think there is a minimum window size in both Windows and Mac operating systems. 100 pixels are smaller than the minimum windows size, so I cannot generate such a small figure.
This should be the answer for my question.

Rounded corner rectangle coordinate representation

Simple rounded corner rectangle code in Matlab can be written as follows.
rectangle('Position',[0,-1.37/2,3.75,1.37],...
'Curvature',[1],...
'LineWidth',1,'LineStyle','-')
daspect([1,1,1])
How to get the x and y coordinates arrays of this figure?
To get the axes units boundaries, do:
axisUnits = axis(axesHandle) % axesHandle could be gca
axisUnits will be an four elements array, with the following syntax: [xlowlim xhighlim ylowlim yhighlim], it will also contain the zlow and zhigh for 3-D plots.
But I think that is not what you need to know. Checking the matlab documentation for the rectangle properties, we find:
Position four-element vector [x,y,width,height]
Location and size of rectangle. Specifies the location and size of the
rectangle in the data units of the axes. The point defined by x, y
specifies one corner of the rectangle, and width and height define the
size in units along the x- and y-axes respectively.
It is also documented on the rectangle documentation:
rectangle('Position',[x,y,w,h]) draws the rectangle from the point x,y
and having a width of w and a height of h. Specify values in axes data
units.
See if this illustrate what you want. You have an x axis that goes from −100 to 100 and y axis that goes from 5 to 15. Suppose you want to put a rectangle from −30 to −20 in x and 8 to 10 in y.
rectangle('Position',[-30,8,10,2]);
As explained by the comments there appears to be no direct way to query the figure created by rectangle and extract x/y coordinates. On the other hand, I can think of two simple strategies to arrive at coordinates that will closely reproduce the curve generated with rectangle:
(1) Save the figure as an image (say .png) and process the image to extract points corresponding to the curve. Some degree of massaging is necessary but this is relatively straightforward if blunt and I expect the code to be somewhat slow at execution compared to getting data from an axes object.
(2) Write your own code to draw a rectangle with curved edges. While recreating precisely what matlab draws may not be so simple, you may be satisfied with your own version.
Whether you choose one of these approaches boils down to (a) what speed of execution you consider acceptable (b) how closely you need to replicate what rectangle draws on screen (c) whether you have image processing routines, say for reading an image file.
Edit
If you have the image processing toolbox you can arrive at a set of points representing the rectangle as follows:
h=rectangle('Position',[0,-1.37/2,3.75,1.37],...
'Curvature',[1],...
'LineWidth',1,'LineStyle','-')
daspect([1,1,1])
axis off
saveas(gca,'test.png');
im = imread('test.png');
im = rgb2gray(im);
figure, imshow(im)
Note that you will still need to apply a threshold to pick the relevant points from the image and then transform the coordinate system and rearrange the points in order to display properly as a connected set. You'll probably also want to tinker with resolution of the initial image file or apply image processing functions to get a smooth curve.

Correct scaling of circular markers in scatter plot

I have a system of finite size circular particles (say r=5cm) which I need to plot in a given domain (say L=5m). Since they are many, scatter is faster than any cyclic use of rectangle.
What is unclear to me is the correct way to define the diameter/radius of the circles/marker so to scale correctly with the domain geometry which is plotted as well. (By using rectangle, the diameter of the particle can be easily defined.)
Based on this answer, it is possible to have fine control of the marker size, although the real scaling is obscure to me.
Can anyone shed some light?
The SCATTER function expects its 'S' parameter to contain the marker
area in points squared. This area corresponds to the area of a square
bounding box around the marker.
The source is the technical solution "How do I specify the size of the markers created by the SCATTER plot in units proportional to the data being plotted in MATLAB 7.6 (R2008a)?"
Check out the code in the link.
The official documentation states:
MarkerSize
Marker size. Size of the marker in points. The default value is 6.
Note that one point is 1/72 of an inch, so it's an absolute measurement unit.
If you want to tune the marker sizes according to the axis scale of your plot, do a simple unit conversion: calibrate 1 tick in one of the axes to points (you can do it by trial and error), and then normalize all your marker sizes by it (it doesn't, however, occur to me how you'd keep the marker sizes relative to the plot's zoom level in a straightforward manner).
By the way, you can specify the sizes of the markers directly as the third parameter in the scatter command. With this, you can avoid the get and set manipulations mentioned in the answer to which have linked your question.

Core Plot: How to scale to fit a plot while scaling axes equally?

I'm using Core Plot to graph linear equations. I have two data points; the X and Y intercept of the line.
I want to scale the the plot area to fit the plot in view.
I tried using
[plotspace scaleToFitPlots: [NSArray arrayWithObject:mainPlot]];
which worked, except that the axes were scaled independently:
The X axis is stretched relative to the Y axis. So that the slope of the line is shown accurately, it is important that both axes be scaled together.
How can I scale a plot area to fit a plot while maintaining an equal relationship between axes?
To be clear, the range of the axes can vary, but the physical amount of onscreen space between 0 and 1 needs to be the same on both axes.
After calling -scaleToFitPlots:, inspect the resulting plot ranges and adjust them as needed to achieve the effect you want. Compare the length of each range to the corresponding dimension of the plot area bounds (compute the ratio between the length and bounds size), determine if one ratio is larger than the other, and adjust the ranges as needed so the ratios match.

Plot of mean square error [EDIT]

If this be the formula for MSE for RGB images A,B of same size 256*200, then how to obtain a line plot for every pixel with x axis representing pixels and y axis representing the MSE values
MSE = reshape(mean(mean((double(A) - double(B)).^2,2),1),[1,3])
There are only two images A ,B. The plot should illustrate change between each pixel of A and B which is meant by MSE.
If you want to display the changes "between each pixel" then what you're showing is not mean squared errors any more -- there's no averaging going on. (Unless you intend to average across the three colour planes, but I don't recommend that: changes in R,G,B are not equally salient to the human visual system. If you really must do this, you might want to weight them, say, 2:4:1 for something a bit more representative, but this is still ad hoc and not likely to give a very accurate idea of what differences will look biggest.)
Of course it's perfectly reasonable to want to see the per-pixel errors, but I wouldn't recommend using a line plot to display them; it's likely to be confusing rather than informative. Rather, display them as an image:
errs = (double(A)-double(B)).^2;
image(errs / max(errs(:)));
axis image;
which you can then compare by eye with A and B to see what image regions/features/... correspond to worse errors. The brightness and colour of each pixel indicate the amount of error and how it's distributed across the R, G, and B planes.
On the other hand, perhaps what you actually need is mean squared error over individual rows, or columns, of the image. In that case, after creating errs as above, use mean to compute the row or column means; that will give you a 256-by-1-by-3 image or a 1-by-200-by-3 image; now I would suggest plotting R,G,B curves separately unless you (probably foolishly in my opinion, as mentioned above) insist on averaging the planes.
row_errs = mean(errs,2); % this is now of size [n,1,3]
now row_errs(:,:,1) is a vector of MS-across-rows red errors, row_errs(:,:,2) is a vector of MS-across-rows green errors, etc. You can feed these to plot.