2%> This is the abstract
class for generating instances of axes
3%> with various types of plots from one or more columns of data.<br>
6%> While it can be directly used
for visualization tasks,
7%>
this class primarily serves as the superclass for the
8%> visualization subclasses accessible to the end users.<br>
12%> [pm.vis.SubplotContourf](@ref
SubplotContourf) visualization objects, the density of the input data
13%> is first computed and smoothed by a Gaussian kernel density estimator and then passed to the
14%> MATLAB intrinsic plotting functions ``contour``, ``contourf``, ``contour3``.<br>
16%> Dynamic
class attributes
17%> ------------------------
19%> This
class contains a set of attributes that are defined dynamically at runtime
20%>
for the output
object depending on its subclass (plot type it represents).<br>
21%> The following is the
list of all
class attributes that are dynamically added
22%> to the instantiated
class objects based on the specified input plot type.<br>
23%> See also the
explicit class and superclass attributes not listed below.<br>
26%> <li> ``colx`` (standing
for x-columns; available
for all axes types)<br>
28%> Optional property that determines the columns of
29%> the specified dataframe to serve as the x-values.
30%> It can have multiple forms:<br>
32%> <li> a numeric or cell array of column indices in the input ``dfref``.
33%> <li> a
string or cell array of column names in ``dfref.Properties.VariableNames``.
34%> <li> a cell array of a mix of the above two.
35%> <li> a numeric range.
37%> If ``colx`` is empty,<br>
39%> <li> it will be set to the row indices of ``dfref``
for line/scatter axes types.
40%> <li> it will be set to all columns of ``dfref``
for density axes types.
44%> In all cases, ``colx`` must have a length that is either
45%> 0 (empty), 1, or equal to the length of ``coly`` or ``colz``.<br>
46%> If the length is 1, then ``colx`` will be plotted against
47%> data corresponding to each element of ``coly`` and ``colz``.<br>
53%>
Subplot.colx = [
"sampleLogFunc",
"sampleVariable1"]
54%>
Subplot.colx = {
"sampleLogFunc", 9,
"sampleVariable1"}
55%>
Subplot.colx = 7:9 # every column in the data frame starting from column #7 to #9
56%>
Subplot.colx = 7:2:20 # every other column in the data frame starting from column #7 to #20
61%> <li> ``coly`` (standing
for y-columns; available
for all axes types except
64%> Optional
property that determines the columns of
65%> the specified dataframe to serve as the z-values.<br>
66%> It can have multiple forms:<br>
68%> <li> a numeric or cell array of column indices in the input ``dfref``.
69%> <li> a
string or cell array of column names in ``dfref.Properties.VariableNames``.
70%> <li> a cell array of a mix of the above two.
71%> <li> a numeric range.
73%> If ``coly`` is empty,<br>
75%> <li> it will be set to the row indices of ``dfref``
for line/scatter axes types.
76%> <li> it will be set to all columns of ``dfref``
for density axes types.
80%> In all cases, ``coly`` must have a length that is either
81%> 0 (empty), 1, or equal to the length of ``colx`` or ``colz``.<br>
82%> If the length is 1, then ``coly`` will be plotted against
83%> data corresponding to each element of ``colx`` and ``colz``.<br>
89%>
Subplot.coly = [
"sampleLogFunc",
"sampleVariable1"]
90%>
Subplot.coly = {
"sampleLogFunc", 9,
"sampleVariable1"}
91%>
Subplot.coly = 7:9 # every column in the data frame starting from column #7 to #9
92%>
Subplot.coly = 7:2:20 # every other column in the data frame starting from column #7 to #20
97%> <li> ``colz`` (standing
for z-columns; available only
for 3D plots, e.g.,
101%> Optional
property that determines the columns of
102%> the specified dataframe to serve as the z-values.<br>
103%> It can have multiple forms:<br>
105%> <li> a numeric or cell array of column indices in the input ``dfref``.
106%> <li> a
string or cell array of column names in ``dfref.Properties.VariableNames``.
107%> <li> a cell array of a mix of the above two.
108%> <li> a numeric range.
110%> If ``colz`` is empty,<br>
112%> <li> it will be set to the row indices of ``dfref``
for line/scatter axes types.
113%> <li> it will be set to all columns of ``dfref``
for density axes types.
117%> In all cases, ``colz`` must have a length that is either
118%> 0 (empty), 1, or equal to the length of ``colx`` or ``coly``.<br>
119%> If the length is 1, then ``colz`` will be plotted against
120%> data corresponding to each element of ``colx`` and ``coly``.<br>
126%>
Subplot.colz = [
"sampleLogFunc",
"sampleVariable1"]
127%>
Subplot.colz = {
"sampleLogFunc", 9,
"sampleVariable1"}
128%>
Subplot.colz = 7:9 % every column in the data frame starting from column #7 to #9
129%>
Subplot.colz = 7:2:20 % every other column in the data frame starting from column #7 to #20
134%> <li> ``colc`` (standing
for color-columns; available only
for 2D/3D line/scatter axes types, e.g.,
136%> [pm.vis.SubplotLineScatter3](@ref
SubplotLineScatter3), [pm.vis.SubplotLine](@ref SubplotTileLine),
139%> Optional property that determines the columns of the input ``dfref`` to
140%> use as the color mapping values
for each line/point element in the plot.<br>
141%> It can have multiple forms:<br>
143%> <li> a numeric or cell array of column indices in the input ``dfref``.
144%> <li> a
string or cell array of column names in ``dfref.Properties.VariableNames``.
145%> <li> a cell array of a mix of the above two.
146%> <li> a numeric range.
148%> The
default value is the indices of the rows of the input ``dfref``.<br>
153%>
Subplot.colc = [
"sampleLogFunc",
"sampleVariable1"]
154%>
Subplot.colc = {
"sampleLogFunc", 9,
"sampleVariable1"}
155%>
Subplot.colc = 7:9 # every column in the data frame starting from column #7 to #9
156%>
Subplot.colc = 7:2:20 # every other column in the data frame starting from column #7 to #20
163%> For example usage, see the documentation of the constructor of
164%> the
class [pm.vis.Subplot::
Subplot](@ref Subplot::Subplot).<br>
167%> While dynamic addition of class attributes is not ideal, the current
168%> design was deemed unavoidable and best, given the constraints of the
169%> MATLAB language and visualization tools.<br>
172%> [pm.vis](@ref \psldir/main/+pm/+vis)<br>
173%> [pm.vis.axes.
Axes](@ref Axes)<br>
174%> [pm.matlab.
Handle](@ref Handle)<br>
175%> [pm.vis.
Cascade](@ref Cascade)<br>
176%> [pm.vis.
Subplot](@ref Subplot)<br>
177%> [pm.vis.
Figure](@ref Figure)<br>
178%> [pm.vis.
Corner](@ref Corner)<br>
179%> [pm.vis.
Plot](@ref Plot)<br>
180%> [pm.vis.
Tile](@ref Tile)<br>
185%> \FatemehBagheri, May 20 2024, 1:25 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
186%> \AmirShahmoradi, May 16 2016, 9:03 AM, Oden Institute for Computational Engineering and Sciences (ICES), UT Austin<br>
189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 properties(Access = public)
195 %> A scalar object of class [pm.data.
DataFrame](@ref DataFrame)
196 %> containing the user-specified data to visualize.<br>
202 %> A MATLAB ``struct`` whose fields are the outputs of
203 %> various plotting tools used to make the current axis.<br>
209 %> A numeric vector that serves as a storage for an arbitrary subset of indices
210 %> of the rows of the input dataframe reference ``dfref`` to the class constructor .<br>
211 %> It can be either:<br>
213 %> <li> a numeric range, or,
214 %> <li> a
list of row indices of the ``dfref``.
220 %> s = pm.vis.Subplot();
222 %> s.rows = 15 : -2 : 8;
223 %> s.rows = [12, 46, 7, 8, 9, 4, 7, 163];
228 %> If ``rows`` is empty, the
default will be all rows of the ``dfref``.<br>
232 %>
this class can be used to generate logarithmically-spaced
233 %> row indices of the target dataframe.<br>
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 methods(Access =
public)
242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 %> Construct and
return an
object of
class [pm.vis.Subplot](@ref
Subplot).<br>
248 %> This is the custom constructor of the
class [pm.vis.Subplot](@ref
Subplot).<br>
250 %> \param[in] ptype : See the documentation of the corresponding input argument of the
251 %> superclass constructor [pm.vis.axes.Axes::Axes](@ref
Axes::Axes).<br>
252 %> \param[in] dfref : The input MATLAB matrix or table containing the data to plot or
253 %> a function handle that returns such a MATLAB matrix or table.<br>
254 %> Specifying a function handle is superior to specifying the
255 %> data directly, because the function handle will always use
256 %> the most updated
version of the user table or matrix.<br>
257 %> (**optional**. The
default is an empty table.)
260 %> ``self`` : The output scalar
object of
class [pm.vis.Subplot](@ref
Subplot).<br>
265 %> s = pm.vis.
Subplot(ptype, dfref);
266 %> s = pm.vis.Subplot(ptype, dfref, varargin);
271 %> In all cases, ``colc`` must have a length that is either
272 %> 0, or 1, or equal to the maximum lengths of ``(colx, coly, colz)``.<br>
273 %> If the length is 1, then all data will be plotted with the same color
274 %> mapping determined by values specified by the elements of ``colc``.<br>
275 %> If it is an empty
object having length 0, then the
default value will be used.<br>
278 %> In
case of [pm.vis.SubplotContour](@ref SuplotContour)/[pm.vis.SubplotContourf](@ref SuplotContourf)/[pm.vis.SubplotContour3](@ref SuplotContour3)
279 %> visualization objects, the density of the input data is first computed and smoothed
280 %> by a Gaussian kernel density estimator and then passed to the MATLAB intrinsic
281 %> plotting functions , ``contour``, ``contourf``, ``contour3``.<br>
284 %> \include{lineno} example/vis/
Subplot/main.m
307 %> \JoshuaOsborne, May 22 2024, 6:45 PM, University of Texas at Arlington<br>
308 %> \AmirShahmoradi, July 5 2024, 1:07 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
309 function self =
Subplot(ptype, dfref, varargin)
316 self@pm.vis.axes.Axes(ptype, varargin{:});
317 self.
df = pm.data.DataFrame(dfref);
320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323 %> Generate a plot from the selected columns
324 %> of the parent
object component ``df``.<br>
326 %> \param[inout] self : The input/output parent
object of
class [pm.vis.Subplot](@ref
Subplot)
327 %>
which is **implicitly** passed to
this dynamic method (not by the user).<br>
328 %> \param[in] varargin : Any ``property, value`` pair of the parent
object.<br>
329 %> If the
property is a ``
struct()``, then its value must be given as a cell array,
330 %> with consecutive elements representing the
struct ``property-
name, property-value`` pairs.<br>
331 %> Note that all of these property-value pairs can be also directly set via the
332 %> parent
object attributes, before calling the ``make()`` method.<br>
337 %> s = pm.vis.Subplot(ptype, dfref)
345 %> This method has side-effects by manipulating
346 %> the existing attributes of the parent
object.<br>
351 %> dfref = rand(1000, 3);
352 %> s = pm.vis.Subplot(
"scatter", dfref);
353 %> s.make(
"colx", 1,
"coly", 2,
"colc", 3)
358 %> \include{lineno} example/vis/
Subplot/main.m
379 %> \JoshuaOsborne, May 22 2024, 6:36 PM, University of Texas at Arlington<br>
380 %> \FatemehBagheri, May 20 2024, 1:25 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
381 %> \AmirShahmoradi, July 5 2024, 1:07 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
382 function make(self, varargin)
384 self.premake(varargin{:});
386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387 %%%% RULE 0: No component of ``self`` is allowed to appear to the left of assignment
operator, except ``fout``.
388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 %%%% Set what to plot.
392 noPlotEnabled =
false;
393 noPlotEnabled = noPlotEnabled || (self.type.is.scatter && ~self.scatter.enabled);
394 noPlotEnabled = noPlotEnabled || (self.type.is.scatter3 && ~self.scatter3.enabled);
395 noPlotEnabled = noPlotEnabled || (self.type.is.line && ~self.plot.enabled && ~self.surface.enabled);
396 noPlotEnabled = noPlotEnabled || (self.type.is.line3 && ~self.plot3.enabled && ~self.surface.enabled);
397 noPlotEnabled = noPlotEnabled || (self.type.is.lineScatter && ~self.plot.enabled && ~self.surface.enabled && ~self.scatter.enabled);
398 noPlotEnabled = noPlotEnabled || (self.type.is.lineScatter3 && ~self.plot3.enabled && ~self.surface.enabled && ~self.scatter3.enabled);
399 noPlotEnabled = noPlotEnabled || (self.type.is.histogram2 && ~self.histogram2.enabled);
400 noPlotEnabled = noPlotEnabled || (self.type.is.histogram && ~self.histogram.enabled);
401 noPlotEnabled = noPlotEnabled || (self.type.is.contourf && ~self.contourf.enabled);
402 noPlotEnabled = noPlotEnabled || (self.type.is.contour3 && ~self.contour3.enabled);
403 noPlotEnabled = noPlotEnabled || (self.type.is.histfit && ~self.histfit.enabled);
404 noPlotEnabled = noPlotEnabled || (self.type.is.contour && ~self.contour.enabled);
405 noPlotEnabled = noPlotEnabled || (self.type.is.heatmap && ~self.heatmap.enabled);
408 +
"All plot types are deactivated by the user. There is nothing to display." + newline ...
409 +
"Enable at least one the following plotting components of the parent object." + newline ...
414 dfcopy = self.df.copy();
416 help(
"pm.vis.Subplot");
418 +
"There is no data to plot." + newline ...
419 +
"Without any input data, visualizations are impossible." + newline ...
420 +
"The input argument ``dfref`` to the object constructor was likely empty." + newline ...
421 +
"If you merely want to create a template of visualization specifications," + newline ...
422 +
"then use the class [pm.vis.axes.Axes](@ref Axes) which is the superclass of this class." + newline ...
423 +
"For more information, see the class documentation displayed above." + newline ...
429 %%%% check rows presence
432 if pm.array.len(self.rows)
433 rowsindex = self.rows(:);
435 rowsindex = [1 : self.df.nrow()]
';
438 %%%%%%%%%%%%%%%%%%%%%%%%%%%
439 %%%% check columns presence
440 %%%%%%%%%%%%%%%%%%%%%%%%%%%
442 coldatx = []; colindx = []; colnamx = [];
443 if isprop(self, "colx") && pm.array.len(self.colx)
444 [colindx, colnamx] = pm.str.locname(dfcopy.Properties.VariableNames, self.colx);
445 elseif self.type.is.heatmap || self.type.is.d1
446 colnamx = dfcopy.Properties.VariableNames;
447 colindx = 1 : length(colnamx);
450 colnamx = "Row Index";
453 coldaty = []; colindy = []; colnamy = [];
454 if isprop(self, "coly") && pm.array.len(self.coly)
455 [colindy, colnamy] = pm.str.locname(dfcopy.Properties.VariableNames, self.coly);
456 elseif self.type.is.density && ~self.type.is.histogram2
457 if isfield(self.(self.type.name), "normalization") && ~isempty(self.(self.type.name).normalization)
458 colnamy = string(self.(self.type.name).normalization);
459 elseif self.type.is.d1
464 elseif self.type.is.heatmap
465 if isempty(dfcopy.Properties.RowNames)
466 dfcopy.Properties.RowNames = string(rowsindex);
468 colnamy = dfcopy.Properties.RowNames;
471 colnamy = "Row Index";
474 coldatz = []; colindz = []; colnamz = [];
475 if isprop(self, "colz") && pm.array.len(self.colz)
476 [colindz, colnamz] = pm.str.locname(dfcopy.Properties.VariableNames, self.colz);
477 elseif self.type.has.line || self.type.has.scatter
479 % This is necessary for 2D surface plot.
480 coldatz = zeros(length(rowsindex), 1);
483 colnamz = "Row Index";
485 elseif self.type.is.density && self.type.is.triaxes
489 coldatc = []; colindc = []; colnamc = [];
490 if isprop(self, "colc") && pm.array.len(self.colc)
491 [colindc, colnamc] = pm.str.locname(dfcopy.Properties.VariableNames, self.colc);
492 elseif self.type.has.line || self.type.has.scatter
493 if ~isempty(colnamz) && ~(isempty(coldatz) && isempty(colindz))
499 colnamc = "Row Index";
501 elseif self.type.is.density && ~self.type.is.d1
505 %%%% check the lengths are consistent.
507 colindlen = max([ length(colindc) ...
508 , length(colindz) ...
509 , length(colindy) ...
510 , length(colindx) ...
513 if length(colindc) ~= colindlen && 1 < length(colindc); error("length of colx must be either 1 or equal to the maximum of the lengths of coly, colz, colc."); end
514 if length(colindz) ~= colindlen && 1 < length(colindz); error("length of coly must be either 1 or equal to the maximum of the lengths of colx, colz, colc."); end
515 if length(colindy) ~= colindlen && 1 < length(colindy); error("length of colz must be either 1 or equal to the maximum of the lengths of colx, coly, colc."); end
516 if length(colindx) ~= colindlen && 1 < length(colindx); error("length of colc must be either 1 or equal to the maximum of the lengths of colx, coly, colz."); end
518 %%%% assign data in case of single column assignments.
520 if length(colindx) == 1; coldatx = dfcopy{rowsindex, colindx}; end
521 if length(colindy) == 1; coldaty = dfcopy{rowsindex, colindy}; end
522 if length(colindz) == 1; coldatz = dfcopy{rowsindex, colindz}; end
523 if length(colindc) == 1; coldatc = dfcopy{rowsindex, colindc}; end
525 %%%% get keyword arguments.
528 for prop = [ "axes" ...
549 if isprop(self, prop)
550 kws.(prop) = self.comp2hash(prop);
554 for prop = ["scatter", "scatter3"]
555 if isprop(self, prop) && self.(prop).filled
556 kws.(prop) = [{"filled"}; kws.(prop)(:)];
560 %%%% generate the kde2d density estimates for the contour plots.
562 kde2dUpdateNeeded = self.type.is.diffusion && (1 < length(colindx) || 1 < length(colindy));
563 if self.type.is.diffusion
565 if ~kde2dUpdateNeeded
566 [kde2d.bandwidth, kde2d.density, kde2d.crdx, kde2d.crdy] = pm.stats.hist.kde2d([coldatx(:), coldaty(:)], self.resolution);
567 kde2d.density(kde2d.density < self.maxnoise) = NaN;
571 %%%% determine the multicolor nature of the plots.
573 isMultiColorPlot = false;
574 if ~self.cenabled && (self.type.has.scatter || self.type.is.diffusion)
575 if self.type.is.diffusion
576 prop = self.type.name;
577 elseif self.type.is.d2
579 elseif self.type.is.d3
582 error("Internal error occurred. A line/scatter plot must be either 2D or 3D.");
584 if pm.array.len(self.(prop).color)
585 if all(size(self.(prop).color) == [colindlen, 3])
586 isMultiColorPlot = true;
587 multiColorList = self.(prop).color;
588 elseif all(size(self.(prop).color) == [1, 3]) || self.type.is.diffusion
589 coldatc = self.(prop).color;
592 + "The value specified for the 'color
' property of the " + prop + " component" + newline ...
593 + "must be either an RGB triplet vector of size [1, 3], or a matrix of size [" + string(colindlen) + ", 3]" + newline ...
594 + "for the current set of variables that are selected to plot. " + newline ...
595 + "It can also be an empty object, in which case, the colors" + newline ...
596 + "of the objects in the plot will be chosen automatically." + newline ...
601 multiColorList = lines(colindlen);
602 isMultiColorPlot = true;
604 elseif self.type.is.diffusion && ~pm.array.len(self.(self.type.name).color)
605 coldatc = self.(self.type.name).color;
608 %%%% initiate the legend.
610 legendary = isprop(self, "legend") && self.legend.enabled;
612 legempty = pm.array.len(self.legend.labels) == 0;
613 lglabels = strings(colindlen, 1);
619 %%%% generate axes and set axes properties.
621 if isprop(self, "axes")
622 self.fout.axes = gca;
624 % This setting must happen here, before any
625 % individual axes component settings below.
626 set(gca, kws.axes{:});
628 if self.type.is.triaxes
635 %%%% Ensure points and lines are scaled properly.
636 %%%% It is not clear whether it's worth doing so because
637 %%%% most figure resizing happen after making it,
638 %%%%
which makes the following solution useless.
642 %
if ~strcmpi(self.fout.axes.Units,
"normalized")
643 % temp = self.fout.axes.Units;
644 % self.fout.axes.Units =
"normalized";
646 % defaultSizeFig = [560, 420] % width, height in pixels.
647 % defaultSizeAxes = [0.775, 0.815] % width, height in pixels (assuming no colorbar).
648 % self.fout.axes.Position
650 % self.fout.axes.Units = temp;
655 if self.type.is.heatmap && self.heatmap.enabled
657 if ~isempty(self.precision)
658 self.fout.heatmap = heatmap(colnamx, colnamy, round(dfcopy{colnamy, colnamx}, self.precision), kws.heatmap{:});
660 self.fout.heatmap = heatmap(colnamx, colnamy, dfcopy{colnamy, colnamx}, kws.heatmap{:});
665 if ~self.type.has.line && ~self.type.has.scatter
666 % line/scatter plots must be taken care of separately.
667 self.fout.(self.type.name) = cell(colindlen, 1);
670 for icol = 1 : colindlen
672 %%%% set the data to plot.
674 if 1 < length(colindx);
if legendary; icollgx = icol; end; coldatx = dfcopy{rowsindex, colindx(icol)}; end
675 if 1 < length(colindy);
if legendary; icollgy = icol; end; coldaty = dfcopy{rowsindex, colindy(icol)}; end
676 if 1 < length(colindz);
if legendary; icollgz = icol; end; coldatz = dfcopy{rowsindex, colindz(icol)}; end
679 coldatc = multiColorList(icol, :);
680 elseif 1 < length(colindc)
681 coldatc = dfcopy{rowsindex, colindc(icol)};
684 if self.type.is.diffusion
686 kws.(self.type.name) = pm.matlab.hashmap.repKeyVal(
"color", coldatc, kws.(self.type.name));
689 [
kde2d.bandwidth,
kde2d.density,
kde2d.crdx,
kde2d.crdy] = pm.stats.hist.kde2d([coldatx(:), coldaty(:)], self.resolution);
690 kde2d.density(
kde2d.density < self.maxnoise) = NaN;
694 %%%% set the
default legend.
696 if legendary && legempty
697 if 1 < length(colindz)
698 suffix =
"-" + colnamz(icollgz);
702 if length(colindx) < 2 && 1 < length(colindy)
703 lglabels(icol) = colnamy(icollgy) + suffix;
704 elseif 1 < length(colindx) && length(colindy) < 2
705 lglabels(icol) = colnamx(icollgx) + suffix;
707 lglabels(icol) = colnamx(icollgx) +
"-" + colnamy(icollgy) + suffix;
711 %%%% add density plot.
713 if self.type.is.contour
714 self.fout.contour{icol} =
struct();
715 [self.fout.contour{icol}.matrix, self.fout.contour{icol}.handle] = contour (
kde2d.crdx ...
718 , self.contour.levels ...
721 elseif self.type.is.contour3
722 self.fout.contour3{icol} =
struct();
723 [self.fout.contour3{icol}.matrix, self.fout.contour3{icol}.handle]= contour3(
kde2d.crdx...
726 , self.contour3.levels ...
727 , kws.contour3{:} ...
729 elseif self.type.is.contourf
730 self.fout.contourf{icol} =
struct();
731 [self.fout.contourf{icol}.matrix, self.fout.contourf{icol}.handle]= contourf(
kde2d.crdx ...
734 , self.contourf.levels ...
735 , kws.contourf{:} ...
737 elseif self.type.is.histfit
738 self.fout.histfit{icol} = histfit(coldatx, self.histfit.nbins, self.histfit.dist, kws.histfit{:});
739 self.fout.histfit{icol}(1).FaceAlpha = 0.6; % make histogram face transparent 60%
740 self.fout.histfit{icol}(1).EdgeAlpha = 0; % make histogram lines invisible
741 self.fout.histfit{icol}(2).Color =
"black"; % make the fitted line black
742 elseif self.type.is.histogram
743 if ~isempty(self.histogram.nbins)
744 self.fout.histogram{icol} = histogram(coldatx, self.histogram.nbins, kws.histogram{:});
745 elseif ~isempty(self.histogram.edges)
746 self.fout.histogram{icol} = histogram(coldatx, self.histogram.edges, kws.histogram{:});
748 self.fout.histogram{icol} = histogram(coldatx, kws.histogram{:});
750 elseif self.type.is.histogram2
751 self.fout.histogram2{icol} = histogram2(coldatx, coldaty, kws.histogram2{:});
756 if self.type.has.line
757 if self.type.is.d2 && self.plot.enabled
758 self.fout.plot{icol} = plot ( coldatx ...
762 elseif self.type.is.d3 && self.plot3.enabled
763 self.fout.plot3{icol} = plot3 ( coldatx ...
769 if self.surface.enabled && self.colormap.enabled
770 self.fout.surface{icol} = surface (
"XData", [coldatx(:), coldatx(:)] ...
771 ,
"YData", [coldaty(:), coldaty(:)] ...
772 ,
"ZData", [coldatz(:), coldatz(:)] ...
773 ,
"CData", [coldatc(:), coldatc(:)] ...
779 %%%% add scatter plot.
781 if self.type.has.scatter
782 if self.type.is.d3 && self.scatter3.enabled
783 self.fout.scatter3{icol} = scatter3 ( coldatx ...
786 , self.scatter3.size ...
788 , self.scatter3.marker ...
789 , kws.scatter3{:} ...
791 elseif self.type.is.d2 && self.scatter.enabled
792 self.fout.scatter{icol} = scatter ( coldatx ...
794 , self.scatter.size ...
796 , self.scatter.marker ...
802 end % loop over plots
804 end %
if heatmap plot.
807 if ~self.type.is.heatmap
808 if isprop(self,
"xlabel") && self.xlabel.enabled;
if ~pm.array.len(self.xlabel.txt); txt = colnamx;
else; txt = self.xlabel.txt; end; self.fout.xlabel = xlabel(txt, kws.xlabel{:}); end
809 if isprop(self,
"ylabel") && self.ylabel.enabled;
if ~pm.array.len(self.ylabel.txt); txt = colnamy;
else; txt = self.ylabel.txt; end; self.fout.ylabel = ylabel(txt, kws.ylabel{:}); end
810 if isprop(self,
"zlabel") && self.zlabel.enabled;
if ~pm.array.len(self.zlabel.txt); txt = colnamz;
else; txt = self.zlabel.txt; end; self.fout.zlabel = zlabel(txt, kws.zlabel{:}); end
812 if isprop(self,
"xlabel") && self.xlabel.enabled; xlabel(self.xlabel.txt, kws.xlabel{:}); end
813 if isprop(self,
"ylabel") && self.ylabel.enabled; ylabel(self.ylabel.txt, kws.ylabel{:}); end
816 % add the colormap and colorbar.
818 if ~self.cenabled && self.type.is.heatmap
819 colormap(flipud(gray)); % self.fout.colormap =
820 elseif ~self.cenabled && self.type.is.contourf
821 colormap(self.fout.axes, flipud(gray)); % self.fout.colormap =
823 if ~isempty(self.colormap.map) || (isstring(self.colormap.map) && self.colormap.map ~=
"")
824 cmap = self.colormap.map;
826 if self.type.has.line || self.type.has.scatter
829 % self.colormap.map =
"winter";
831 % self.colormap.map =
"autumn";
833 elseif self.type.is.heatmap
834 cmap = pm.vis.cmap.redblue();
835 elseif self.type.is.density
839 if ~self.type.is.heatmap
840 colormap(self.fout.axes, cmap); % self.fout.colormap =
842 colormap(cmap); % self.fout.colormap =
846 if isprop(self,
"colorbar")
847 if self.colorbar.enabled && (self.cenabled || self.type.is.contourf)
848 if isempty(self.colorbar.fontSize) %|| ~isa(self.colorbar.fontSize, "numeric")
849 kws.colorbar = [kws.colorbar(:); {
"fontSize"}; {self.fout.axes.FontSize + 1}];
851 self.fout.colorbar = colorbar(kws.colorbar{:});
852 ylabel(self.fout.colorbar, colnamc(1));%,
"fontSize", self.colorbar.fontSize,
"interpreter",
"none"
855 self.fout.colorbar = [];
861 if legendary && 0 < colindlen
862 self.fout.legend = [];
864 lglabels = self.legend.labels;
866 if ~self.legend.enabled
867 legend(self.fout.axes,
"off");
868 elseif isa(self.legend.labels,
"cell") || isa(self.legend.labels,
"string")
869 if isempty(self.legend.fontSize)
870 kws.legend = [kws.legend(:); {
"fontSize"}; {self.fout.axes.FontSize + 1}];
873 if self.type.has.scatter && self.type.is.d2 && self.scatter.enabled
874 subset = [self.fout.scatter{:}];
875 elseif self.type.has.scatter && self.type.is.d3 && self.scatter3.enabled
876 subset = [self.fout.scatter3{:}];
878 elseif self.type.is.histfit && self.histfit.enabled
879 nhandle = length(self.fout.histfit);
880 subset = cell(nhandle, 1);
882 subset{i} = self.fout.histfit{i}(1); % get the handle to the histogram component of histfit.
884 subset = [subset{:}];
887 self.fout.legend = legend(subset, lglabels{:}, kws.legend{:});
889 self.fout.legend = legend(lglabels{:}, kws.legend{:});
893 +
"The specified ""legend.labels"" must be a cell array of string values." ...
899 %
if self.type.is.targetable
900 % self.target.fout.axes = self.fout.axes;
905 if self.title.enabled
907 for field = [
"titletext",
"subtitletext"] %
do not change the order of elements here.
908 if isfield(self.title, field) && pm.array.len(self.title.(field))
909 titletxt = [titletxt(:); self.title.(field)(:)];
912 if ~isempty(titletxt)
913 if ~self.type.is.heatmap
915 % kws.title = {titletxt{:}, kws.title(:)};
917 self.fout.title = title(self.fout.axes, titletxt{:}, kws.title{:});
919 %%%% Neither input nor output arguments are not supported when
using title with heatmap.
927 for prop = [
"xlim",
"ylim",
"zlim"]
928 if isprop(self, prop) && ~isempty(self.(prop))
929 limit = get(self.fout.axes, prop);
931 if ~isnan(self.(prop)(i))
932 limit(i) = self.(prop)(i);
935 set(self.fout.axes, prop, limit);
939 %%%% set axes scales.
941 for prop = ["xscale", "yscale", "zscale"]
942 if isprop(self, prop) && ~isempty(self.(prop))
943 set(self.fout.axes, prop, self.(prop));
947 if ~self.type.is.heatmap
955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961 methods(Access = public, Hidden)
963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 %> Prepare the subplot for visualization.<br>
968 %> \param[inout] self : The input/output parent
object of class [pm.vis.
Subplot](@ref
Subplot)
969 %>
which is **implicitly** passed to this dynamic method (not by the user).<br>
970 %> \param[in] varargin : Any ``property, value`` pair of the parent
object.<br>
971 %> If the property is a ``struct()``, then its value must be given as a cell array,
972 %> with consecutive elements representing the struct ``property-
name, property-value`` pairs.<br>
973 %> Note that all of these property-value pairs can be also directly set via the
974 %> parent
object attributes, before calling the ``premake()`` method.<br>
976 %> \interface{premake}
979 %> s = pm.vis.Subplot(ptype, dfref);
981 %> s.premake(varargin);
987 %> This method has side-effects by manipulating
988 %> the existing attributes of the parent
object.<br>
993 %> dfref = rand(1000, 3);
994 %> s = pm.vis.Subplot(
"scatter", dfref);
995 %> s.premake(
"colx", 1,
"coly", 2,
"colc", 3)
1002 %> \JoshuaOsborne, May 22 2024, 6:41 PM, University of Texas at Arlington<br>
1003 %> \FatemehBagheri, May 20 2024, 1:25 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
1004 %> \AmirShahmoradi, July 5 2024, 1:07 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
1005 function premake(self, varargin)
1006 premake@pm.vis.axes.Axes(self, varargin{:});
1009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1012 %> Reset the properties of the plot to the original
default settings.<br>
1015 %> Use
this method when you change many attributes of the plot and
1016 %> you want to
clean up and go back to the
default settings.<br>
1018 %> \param[inout] self : The input/output parent
object of
class [pm.vis.Subplot](@ref
Subplot)
1019 %>
which is **implicitly** passed to
this dynamic method (not by the user).<br>
1020 %> \param[in] varargin : Any ``property, value`` pair of the parent
object.<br>
1021 %> If the
property is a ``
struct()``, then its value must be given as a cell array,
1022 %> with consecutive elements representing the
struct ``property-
name, property-value`` pairs.<br>
1023 %> Note that all of these property-value pairs can be also directly set via the
1024 %> parent
object attributes, before calling the ``make()`` method.<br>
1026 %> \interface{reset}
1029 %> pm.vis.Subplot.reset() % reset the plot to the
default settings.
1036 %> \JoshuaOsborne, May 22 2024, 6:43 PM, University of Texas at Arlington<br>
1037 %> \FatemehBagheri, May 20 2024, 1:25 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
1038 %> \AmirShahmoradi, July 5 2024, 1:07 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
1039 function reset(self, varargin)
1041 self.fout =
struct();
1042 self.newprop(
"colx", {});
1043 if self.type.is.d2 || self.type.is.d3
1044 self.newprop(
"coly", {});
1046 self.newprop(
"colz", {});
1049 reset@pm.vis.axes.Axes(self, varargin{:});
1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function name(in vendor)
Return the MPI library name as used in naming the ParaMonte MATLAB shared libraries.
function list()
Return a list of MATLAB strings containing the names of OS platforms supported by the ParaMonte MATLA...
function version(in silent)
Return a scalar MATLAB string containing the latest available ParaMonte MATLAB version newer than the...
This is the class for generating instances of objects that contain the specifications of various type...
function Axes(in ptype, in varargin)
Construct and return an object of class pm.vis.axes.Axes.
This is the abstract class for generating instances of objects that contain the specifications of a c...
This is the base class for generating instances of figures containing a symmetric square grid or corn...
This is the abstract class for generating instances of objects that can contain basic attributes requ...
function rowslog(in self, in count, in start, in stop)
Generate and return a natural logarithmically-spaced range of indices from the row indices of the inp...
This is the base class for generating subclass of MATLAB handle superclass whose annoying methods are...
This is the base class for generating instances of objects that contain the specifications of various...
This is the SubplotContour3 class for generating instances of 3-dimensional Contour Subplot visualiza...
This is the SubplotContour class for generating instances of 2-dimensional Contour Subplot visualizat...
This is the SubplotContourf class for generating instances of 2-dimensional Contour Subplot visualiza...
This is the SubplotEllipse3 class for generating instances of 3-dimensional Ellipse Subplot visualiza...
This is the SubplotEllipse class for generating instances of 2-dimensional Ellipse Subplot visualizat...
This is the SubplotHeatmap class for generating instances of 2-dimensional Heatmap Subplot visualizat...
This is the SubplotHistfit class for generating instances of 2-dimensional Histfit Subplot visualizat...
This is the SubplotHistogram2 class for generating instances of 2-dimensional Histogram2 Subplot visu...
This is the SubplotHistogram class for generating instances of 1-dimensional Histogram Subplot visual...
This is the SubplotLine3 class for generating instances of 3-dimensional Line Subplot visualizations ...
This is the SubplotLineScatter3 class for generating instances of 3-dimensional Line-Scatter Subplot ...
This is the SubplotLineScatter class for generating instances of 2-dimensional Line-Scatter Subplot v...
This is the SubplotLine class for generating instances of 2-dimensional Line Subplot visualizations b...
This is the SubplotScatter3 class for generating instances of 3-dimensional Scatter Subplot visualiza...
This is the SubplotScatter class for generating instances of 3-dimensional Scatter Subplot visualizat...
This is the abstract class for generating instances of axes with various types of plots from one or m...
function premake(in self, in varargin)
Prepare the subplot for visualization.
function Subplot(in ptype, in dfref, in varargin)
Construct and return an object of class pm.vis.Subplot.
function reset(in self, in varargin)
Reset the properties of the plot to the original default settings.
function make(in self, in varargin)
Generate a plot from the selected columns of the parent object component df.
This is the abstract class for generating instances of objects that contain the specifications of var...
function clean()
Remove all paths that contain the ParaMonte lib directory from the MATLAB path variable.
function kde2d(in data, in resol, in xymin, in xymax)
Compute the Gaussian kernel density estimate of the input bivariate data.
function which(in vendor)
Return the a MATLAB string containing the path to the first mpiexec executable binary found in system...