Should Plotting Functions Implicitly Squeeze Inputs?

Paul on 1 Jun 2025 (Edited on 4 Jun 2025)
Latest activity Edit by Paul on 18 Jun 2025

Should plotting functions, such as plot, semilogx, etc. internally apply squeeze to inputs?
For example, the ubiquitous bode from the Control System Toolbox always returns 3D outputs
w = logspace(-1,3,100);
[m,p] = bode(tf(1,[1 1]),w);
size(m)
ans = 1×3
1 1 100
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
and therefore plotting requires an explicit squeeze (or rehape, or colon)
% semilogx(w,squeeze(db(m)))
Similarly, I'm using page* functions more regularly and am now generating 3D results whereas my old code would generate 2D. For example
x = [1;1];
theta = reshape(0:.1:2*pi,1,1,[]);
Z = [cos(theta), sin(theta);-sin(theta),cos(theta)];
y = pagemtimes(Z,x);
Now, plotting requires squeezing the inputs
% plot(squeeze(theta),squeeze(y))
Would there be any drawbacks to having plot, et. al., automagically apply squeeze to its inputs?
Paul
Paul on 2 Jun 2025 (Edited on 2 Jun 2025)
One issue I can envision is that code that uses try/catch to detect inputs to plot with more than two dimensions would no longer behave the same in some cases.
try
plot(X,Y)
catch ME
% if X or Y or both have more than two dimensions, then do something
end
If the extra dimension(s) in X or Y that cause the error in the above code are squeezed away, then that code would run silently with no error. Probably not an appropriate use of try/catch, but I've definitely seen try/catch essentially used in place of an if statement in other contexts.
Adam Danz
Adam Danz on 2 Jun 2025
👀
Great topic! I'm eager to hear people's thoughts.
Paul
Paul on 7 Jun 2025
Would you mind sharing your thoughts?
Adam Danz
Adam Danz on 13 Jun 2025
I've been in the same situation where I've had essencially 2D data stored in a 3D array with a singleton dimension and I'm left wondering, why doesn't MATLAB know what I want to do!? In those cirumstances my intentions seems so obvious that I wonder why the software can't read my mind.
Yesterday I was loading a draft of an upcoming Graphics and App Building blog article into WordPress by copying it from a carefully formatted Word document. Upon previewing the article, WordPress tried to be smarter than me and removed all line break tags requiring me to manually fix the end of each paragraph. Obviously this is what he wants, WordPress thought. WordPress was wrong. Fortunately I caught the error.
Should software try to interpret the user's intentions?
In some cases, yes (my opinion, of course). For example, MATLAB knows that 'r' should be interpreted as 'red' when specifying color properties in graphics objects. The uitextarea command will automatically wrap a 1xn character array based on the width of the text box, assuming the user didn't intend for the text to be cut off or extend beyond the text box (the text command, on the other hand, does not wrap).
In many other cases, particularly in areas of core math and data visualization where silent wrong answers can be dangerous, we try to catch nonsensical inputs and workflows by returning warnings or errors but we probably shouldn't be silently tweaking the user's input data. If an input has multiple dimensions, it is my opinion that we should assume that is intentional and if the function was not built for multiple dimensions, it shouldn't adapt the inputs "to make it work".
Problems with squeezing out singleton dimensions
MATLAB already implicitly reduces an infinite number of trailing singleton dimensions. For example,
t = rand(5,4,1,1,1,1);
size(t)
ans = 1×2
5 4
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Thus, plotting functions that accept matrices would accept this input since it would be trimmed prior to plotting execution.
Squeezing non-trailing singleton dimensions is where things get murky. Many plotting functions are sensitive to the shape of the inputs. For example, when M is a 2D matrix in plot(M), a line is plotted for each column of M and the number of rows of M determine the number of points per line. Here is an example where M is a 1x2x1x3 4D array and N is a 3x1x2 3D array, both of which have the same 6 values. M is squeezed to a 2x3 matrix and N is squeezed to a 3x2 matrix. The result is a different number of lines and coordinates.
Are these the intended results? -- It depeneds on the logic used to store those data.
Would the user be aware of what happened here? -- Maybe not. I've occasionally forgotten that a variable has more than two dimensions until an error message pops up.
vals = 1:6;
M = reshape(vals,[1 2 1 3]);
N = reshape(vals,[3,1,2]);
Msqueezed = squeeze(M)
Msqueezed = 2×3
1 3 5 2 4 6
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Nsqueezed = squeeze(N)
Nsqueezed = 3×2
1 4 2 5 3 6
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
figure()
tiledlayout(1,2)
plot(nexttile(),Msqueezed,'-o')
title('squeeze(M)')
plot(nexttile(),Nsqueezed,'-o')
title('squeeze(N)')
Conclusion
For these reasons, it is my opnion that a helpful error message is the correct response. I see MATLAB users as incredibly smart and also incredibly busy people. It's important that we find ways to simplify the use of MATLAB but for topics like this where simplifcation can lead to problems, it's better to rely on human brains.
Paul
Paul on 13 Jun 2025 (Edited on 18 Jun 2025)
Limiting my thoughts only to plot (and the family of plotting functions) ...
Plot already interprets user intentions. For two inputs, it will figure out how to make things work based on dimensions
X = 1:3;
Y = reshape(1:6,3,2);
figure()
tiledlayout(1,2)
plot(nexttile(),X,Y,'-o') % plot X vs Y-columns
plot(nexttile(),X,Y.','-o') % user must want to plot X vs Y-rows
As it stands today, if the user wants to plot M or N, then the user will need to squeeze and consider whether or not to subsequently reshape (or transpose, or permute) prior to or on input to plot (or reshape and then squeeze). If the auto-squeeze is implemented (and documented!), the user would still have to ensure the shape of the unsqueezed input yields the desired result. So I don't see (at present) a significant difference, if any, between the user applying squeeze or plot() applying squeeze. The user will either get the desired result, or they'll have to manipulate the inputs before calling (or on input to) plot as needs to be done today.
Some users may prefer to squeeze and then reshape prior to calling plot, and that approach will still work.