How can I rescale a patternCustom plot?

72 views (last 30 days)
Scott
Scott on 15 Oct 2025 at 18:53
Edited: dpb on 18 Oct 2025 at 23:59
I'm plotting multiple patternCustom plots in a tiledlayout, and would like to rescale the individual plots so that they all have the same magnitude. I've tried many things (I don't remember all what I tried, it was over a month ago) and couldn't get anything to work. The patternCustom function does not support the typical name-value pair arguments and seems really inflexible.
  9 Comments
dpb
dpb on 17 Oct 2025 at 16:45
Edited: dpb on 17 Oct 2025 at 17:58
If it isn't a major effort, then sure, no argument.
I think you would not need to replot, however, the things you would be messing with would be the details that the axis and handles of the various lines, etc., have, though, not the name-value pairs going in. I don't have the TB so can't play with it locally, but if the scaling does work as desired with one of those as @Umar suggests, then it would be the better solution, agreed.
Umar
Umar on 17 Oct 2025 at 23:42

@Scott,

One more thing I wanted to share — @dpb was genuinely trying to help you out. There are so many talented contributors on this platform, like @Stephen23, @ImageAnalyst, @Star Strider, @John D Errico, @Walter Robertson, @Torsten — and @dpb is certainly among them.

I’ve always respected his thoughts and opinions. We're all here to learn, grow, and make a difference — not just in our own work, but in the lives of students, scholars, and fellow contributors.

I won’t be on this platform much longer, but I’m grateful for the memories and the chance to make a positive impact. I hope you understand where I’m coming from.

Sign in to comment.

Answers (3)

dpb
dpb on 15 Oct 2025 at 19:53
Moved: dpb on 15 Oct 2025 at 19:53
%helixdata = readmatrix("antennadata_test.csv");
%hL=patternCustom(helixdata(:,3),helixdata(:,2),helixdata(:,1));
h = helix;
[D,az,el] = pattern(h,2e9);
phi = az';
theta = (90-el);
MagE = D';
tl=tiledlayout(2,2);
iax=1;
hAx(iax)=nexttile;
hL=patternCustom(MagE, theta, phi,CoordinateSystem="rectangular",Slice="phi", SliceValue=0);
[hAx(iax).XLim hAx(iax).YLim hAx(iax).ZLim]
ans = 1×6
0 200 -15 10 -1 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
iax=iax+1;
hAx(iax)=nexttile;
L=patternCustom(MagE/10, theta, phi,CoordinateSystem="rectangular",Slice="phi", SliceValue=0);
[hAx(iax).XLim hAx(iax).YLim hAx(iax).ZLim]
ans = 1×6
0 200.0000 -1.5000 1.0000 -1.0000 1.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ylim(hAx(iax),ylim(hAx(iax-1)))
Takes a stab at it from one of the examples using rectangular coordinates.
You didn't provide anything to go on about your specific case, but the above should give the idea -- save the tiled axes handles and adjust the plot axes limits to match what you want.
  4 Comments
dpb
dpb on 16 Oct 2025 at 18:41
Edited: dpb on 16 Oct 2025 at 23:20
I don't have time to actually poke at it at the moment, but you'll have to map the colormap to match the same magnitude as the largest and set it for each as I noted before. The size appears to always be scaled to fit the axes by default.
Truthfully, @Umar's idea of drawing directly with primitives and then wrapping that into your own function may be easier than trying to beat the special graphics object into submission in ways it just wasn't designed for.
I'll try to get back again when I do have a little time to poke at it...
Umar
Umar on 17 Oct 2025 at 5:03

@dpb - You nailed it with the colormap mapping insight. Turns out `clim()` does the trick for forcing uniform color limits across the 3D spherical plots, and `PatternPlotOptions` with `MagnitudeScale` also works as an alternative. Appreciate you pointing in the right direction - saved @Scott from having to rebuild with primitives!

Sign in to comment.


Umar
Umar on 15 Oct 2025 at 23:10

Hi @Scott,

Thanks for the additional information! It sounds like you're trying to plot multiple `patternCustom` plots in a tiled layout while ensuring that all the plots share the same magnitude scaling. I totally get that `patternCustom` can be a bit tricky when it comes to scaling the magnitude consistently across multiple plots.

In your case, since you're not using the default `'CoordinateSystem', 'rectangular'` or `'polar'`, you're likely working with *spherical coordinates* (phi and theta). And since `patternCustom` doesn't offer a straightforward way to rescale the magnitude across multiple plots, let me offer you two approaches: one without any toolbox (using basic MATLAB functions) and the other with the *Antenna Toolbox* if you still want to stick to `patternCustom`.

Solution Without Toolbox

If you're looking for a toolbox-free approach, here's a simple solution using *basic MATLAB functions* that rescale the magnitude and visualize it in a tiled layout. The code uses `surf`, `meshgrid`, and `normalize` to ensure the magnitude is consistent across subplots.

Example Code (No Toolbox)

% Example data (replace with actual data)
az = linspace(0, 360, 100);  
el = linspace(-90, 90, 100);  
[Az, El] = meshgrid(az, el);  
MagE = sin(Az) .* cos(El);  % Example E-field pattern data
% Normalize the magnitude to [0, 1]
MagE_normalized = normalize(MagE, 'range');
% Create a tiled layout
figure;
tiledLayout = tiledlayout(2, 2);  % Create a 2x2 layout for 4 plots
% Loop through each subplot
for iax = 1:4
  nexttile;  % Move to the next subplot
    % Select pattern data for each subplot
    if iax == 1
        surf(Az, El, MagE);  % Plot original data
        title('Original Magnitude');
    elseif iax == 2
        surf(Az, El, MagE_normalized);  % Plot normalized data
        title('Normalized Magnitude');
    elseif iax == 3
        surf(Az, El, MagE * 0.1);  % Scaled data
        title('Scaled by 0.1');
    else
        surf(Az, El, MagE * 0.01);  % Another scaling factor
        title('Scaled by 0.01');
    end
    % Ensure the axes are consistent across plots
    axis([-180 180 -90 90 0 1]);  % Set common axis limits
    colormap jet;
    colorbar;  % Show color scale
  end

See attached results without using toolbox.

This approach doesn't require any special toolboxes and should give you the consistent scaling across subplots that you're looking for. If this works for you, it could be a very clean solution.

Solution With Antenna Toolbox (Using `patternCustom`)

If you're still relying on the Antenna Toolbox and want to use `patternCustom`, here’s how you can manage multiple radiation pattern plots with consistent scaling.

Rescale the Data: You can normalize the magnitude before passing it to `patternCustom`, just like we did in the example above. This ensures that each plot has the same scaling.

Adjust Plot Settings: Use the CoordinateSystem, Slice and SliceValue options to control the plot’s appearance.

Multiple Plots in a Single Figure: patternCustom allows plotting multiple radiation patterns in the same figure by passing in different data sets.

Here’s an example of how you could use `patternCustom` with normalized data for consistent scaling:

Antenna Toolbox (Using `patternCustom`)

% Assuming you already have MagE, theta, and phi
MagE_normalized = normalize(MagE, 'range');  % Normalize the magnitude
% Create a tiled layout for 4 plots
figure;
tiledLayout = tiledlayout(2, 2);  % Create a 2x2 layout
% Plotting the patterns
for iax = 1:4
  nexttile;  % Move to the next subplot
  if iax == 1
      patternCustom(MagE, theta, phi);  % Original data
      title('Original Magnitude');
  elseif iax == 2
      patternCustom(MagE_normalized, theta, phi);  % Normalized data
      title('Normalized Magnitude');
  elseif iax == 3
      patternCustom(MagE * 0.1, theta, phi);  % Scaled data
      title('Scaled by 0.1');
  else
      patternCustom(MagE * 0.01, theta, phi);  % Another scaling factor
      title('Scaled by 0.01');
  end
end

I just went through the Relevant Documentation for Toolbox Functions to find solution to your problem, here are the references:

patternCustom: Pattern Custom Documentation https://www.mathworks.com/help/antenna/ref/patterncustom.html

normalize: Normalize Documentation https://www.mathworks.com/help/matlab/ref/normalize.html

tiledlayout: Tiled Layout Documentation https://www.mathworks.com/help/matlab/ref/tiledlayout.html

If you're comfortable using basic MATLAB functions (like `surf` and `normalize`), you can achieve the same visual results without needing the Antenna Toolbox. However, if you still want to use `patternCustom`, you can normalize your data before passing it into the function to maintain consistent scaling across plots.

Let me know if you need further clarification on any part of this or if you’d like to explore other methods!

  3 Comments
Scott
Scott on 16 Oct 2025 at 18:24
Thank you for your response. Your first proposal using surf() isn't what I'm looking for--I want a spherical plot. I copied/pasted your code and got 3D plots but they were not spherical-looking...but maybe they could be made to behave spherically with the right massaging. I'm not against using other 3D plotting styles or even coordinate systems if they can provide my desired behavior. So far pattternCustom has gotten the closest to what I want. Sorry I haven't done a good job of communicating exactly what that behavior is so far (it's frustrating when people do that to me!), I've added more details to my original post.
Your second proposal will suffer from the same problem that I want to avoid, see my example above.
Umar
Umar on 17 Oct 2025 at 21:53

Hi @Scott,

I owe you an apology - You were right to be frustrated. So, I do completely understand about what actually happened after going through your posted comments. So, let me first address the caxis approach: You nailed it - this only fixed the colormap, not the physical size of the patterns. The 0.5-scale sphere still filled the entire plot when it should've been half the size. Now, the PatternPlotOptions disaster: I called it a "confirmed solution" but you systematically proved it doesn't work:

  • The PatternOptions=po syntax failed (your MATLAB version)
  • Passing po directly failed (wrong argument type)
  • Using 'MagnitudeScale' failed (not a valid parameter)

But after looking closer at the docs and your plots, I was curious about what I was missing and the key thing was MagnitudeScale only works with the pattern() method from antenna objects, not patternCustom. Even if syntax worked, it would've been ignored. You were absolutely right about patternCustom being inflexible. Since you mentioned being open to other approaches, here's what actually works. And good news - you don't need to refactor much. The code calculates global limits first, then plots everything with consistent scaling:

clear; clc; close all;
%% Setup
num_plots = 2;
num_azimuth_idxs = 100;
num_zenith_idxs = 100;
scales = [1, 0.5];
phi = linspace(-180, 180, num_azimuth_idxs);
theta = linspace(0, 180, num_zenith_idxs);
[PHI, THETA] = meshgrid(phi, theta);
%% Generate data and find global max
magE_all = cell(num_plots, 1);
max_mag = -Inf;
for ii = 1:num_plots
  magE = abs(scales(ii) * cos(deg2rad(PHI + THETA)));
  magE_all{ii} = magE;
  max_mag = max(max_mag, max(magE(:)));
end
%% Plot
figure('Position', [100, 100, 1200, 500]);
tiled_plot = tiledlayout(1, num_plots, 'TileSpacing', 'compact');
for ii = 1:num_plots
  nexttile;
  magE = magE_all{ii};
    % KEY: Use magnitude as radius - this is what makes it work
    theta_rad = deg2rad(THETA);
    phi_rad = deg2rad(PHI);
    r = magE;  % Smaller magnitude = smaller sphere
    x = r .* sin(theta_rad) .* cos(phi_rad);
    y = r .* sin(theta_rad) .* sin(phi_rad);
    z = r .* cos(theta_rad);
    surf(x, y, z, magE, 'EdgeColor', 'none', 'FaceColor', 'interp');
    caxis([0 max_mag]);  % Uniform color scale
    axis equal; axis vis3d;
    colormap jet; colorbar;
    view(3);
    % Add coordinate axes
    hold on;
    plot3([0 max_mag*1.2], [0 0], [0 0], 'r-', 'LineWidth', 2);
    plot3([0 0], [0 max_mag*1.2], [0 0], 'g-', 'LineWidth', 2);
    plot3([0 0], [0 0], [0 max_mag*1.2], 'b-', 'LineWidth', 2);
    hold off;
    xlabel('X'); ylabel('Y'); zlabel('Z');
    title(sprintf('Pattern %d (Scale: %.1f)', ii, scales(ii)));
    axis_limit = max_mag * 1.3;
    xlim([-axis_limit axis_limit]);
    ylim([-axis_limit axis_limit]);
    zlim([-axis_limit axis_limit]);
    lighting gouraud;
    camlight('headlight');
    material dull;
  end
title(tiled_plot, 'Spherical 3D Radiation Patterns with Uniform 
Magnitude Scaling');

Results: please see attached.

So, I executed the code and it worked because of r = magEl By using magnitude directly as the radius:

  • The 0.5-scale pattern is physically half the size (extends to ±0.5 instead of ±1)
  • With uniform caxis([0 max_mag]), it uses middle-range colors (blues/cyans/greens) instead of the full spectrum

This solves exactly what you showed in your image - where both spheres were the same size but shouldn't have been. Now the right plot will be visibly smaller and use middle colors like you wanted.

No toolbox needed, just standard MATLAB functions.

Hope this finally works for you!

Sign in to comment.


dpb
dpb on 18 Oct 2025 at 14:29
Edited: dpb on 18 Oct 2025 at 23:59
OK, I had some time to try to play around a little this morning when didn't have to interact with the local community college Foundation staff ladies I've been doing pro bono work for to let them keep moving...
Try the following that fixes up the sizes of the images by scaling the plotted X, Y, ZData arrays that internally are scaled to full axes dimensions. It also finds the bounding circles and scales them as well as the surface data.
num_plots = 2;
num_azimuth_idxs = 100;
num_zenith_idxs = 100;
phi = linspace(-180, 180, num_azimuth_idxs);
theta = linspace(0, 180, num_zenith_idxs);
scales = [1, 0.5];
%patternCustom uses a strange input format, accomodate...
pattern_phi = repmat(phi, 1, num_zenith_idxs);
pattern_theta = repelem(theta, num_azimuth_idxs);
tiled_fig = figure;
tiled_plot = tiledlayout(tiled_fig, 1, num_plots);
% Prepare dummy E-field data
magE = zeros(num_azimuth_idxs * num_zenith_idxs, 1);
ax_handles = gobjects(1, num_plots);
hS=gobjects(1, num_plots); % going to need the surface handles, too...
for ii = 1:num_plots
pattern_idx = 1;
for az_idx = 1 : num_azimuth_idxs
for ze_idx = 1 : num_zenith_idxs
magE(pattern_idx) = abs(scales(ii) * cos(deg2rad(phi(az_idx) + theta(ze_idx))));
pattern_idx = pattern_idx + 1;
end
end
% Throw it up on a plot
ax_handles(ii) = nexttile(tiled_plot);
% Adjust the magnitude of the pattern plot to reflect the scaling
hS(ii)=patternCustom(magE, pattern_theta, pattern_phi); % save the handle, too...
hS(ii).XData=scales(ii)*hS(ii).XData; % and apply the scale factor
hS(ii).YData=scales(ii)*hS(ii).YData;
hS(ii).ZData=scales(ii)*hS(ii).ZData;
hL=findobj(ax_handles(ii),'-regexp','tag','.Circle'); % find the bounding circles
for h=hL.' % and scale them, too...
h.XData=scales(ii)*h.XData;
h.YData=scales(ii)*h.YData;
h.ZData=scales(ii)*h.ZData;
end
end
% the default formatting with '%g' is unspeakedly ugly when not all data are same precision
% NB: uses undocumented/hidden 'Ruler' property of the colorbar to set formatting string
hCB=findobj(gcf,'tag','Colorbar'); % find the colorbar handles
cellfun(@(h)set(h,'TickLabelFormat','%0.1f'),get(hCB,'Ruler')); % set to one decimal
% Now scale all of the plots to be the same scale
max_mag = -Inf;
% Loop through each axis handle to find the maximum magnitude
for tile_idx = 1:num_plots
current_mag = caxis(nexttile(tile_idx));
max_mag = max(max_mag, current_mag(2));
end
% Set the same limit for all plots
for tile_idx = 1:length(ax_handles)
caxis(nexttile(tile_idx), [0 max_mag]);
end
For data that aren't exactly scaled replicas of each other, one will have to compute a scale factor for each dimension based on the data ranges to apply; here it's easy since you have a factor defined.
I think this would be a valid use case to submit as an enhancement request in that it does make sense to be able to show the relative magnitudes as an option as well as the builtin default of trying to show the most detail possible.
This is the approach I had in mind that doesn't require replotting and why I suggested to save the object handles. I had initially thought the returned handles would also include the lines, not just the surface, but they're not hard to find since they did conveniently tag them. You could wrap that section of code into an internal function to clean up the appearance of the top level code a little if desired.
NOTA BENE: I didn't experiment with whether after rescaling the plotted data you might be able to do away with the extra color limits stuff as they just might be scaled as you want once the data themselves are.

Products


Release

R2020a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!