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.,
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.
Triplex](@ref Triplex)<br>
178%> [pm.vis.
Figure](@ref Figure)<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.container.
DataFrame](@ref DataFrame)
196 %> containing (a reference to) 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.)
258 %> \param[in] varargin : Any ``property, value`` pair of the parent
object.<br>
259 %> If the
property is a ``
struct()``, then its value must be given as a cell array,
260 %> with consecutive elements representing the
struct ``property-
name, property-value`` pairs.<br>
261 %> Note that all of these property-value pairs can be also directly set via the
262 %> parent
object attributes, before calling the ``make()`` method.<br>
263 %> The input ``varargin`` can also contain the components
264 %> of the ``subplot`` component of the parent
object.<br>
267 %> ``self`` : The output scalar
object of
class [pm.vis.Subplot](@ref
Subplot).<br>
272 %> s = pm.vis.
Subplot(ptype, dfref);
273 %> s = pm.vis.Subplot(ptype, dfref, varargin);
278 %> In all cases, ``colc`` must have a length that is either
279 %> 0, or 1, or equal to the maximum lengths of ``(colx, coly, colz)``.<br>
280 %> If the length is 1, then all data will be plotted with the same color
281 %> mapping determined by values specified by the elements of ``colc``.<br>
282 %> If it is an empty
object having length 0, then the
default value will be used.<br>
286 %> visualization objects, the density of the input data is first computed and smoothed
287 %> by a Gaussian kernel density estimator and then passed to the MATLAB intrinsic
288 %> plotting functions , ``contour``, ``contourf``, ``contour3``.<br>
291 %> \include{lineno} example/vis/
Subplot/main.m
312 %> \JoshuaOsborne, May 22 2024, 6:45 PM, University of Texas at Arlington<br>
313 %> \AmirShahmoradi, July 5 2024, 1:07 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
314 function self =
Subplot(ptype, dfref, varargin)
321 self@pm.vis.axes.Axes(ptype, varargin{:});
322 self.
dfref = pm.container.DataFrame(dfref);
325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328 %> Generate a plot from the selected columns
329 %> of the parent
object component ``dfref``.<br>
331 %> \param[inout] self : The input/output parent
object of
class [pm.vis.Subplot](@ref
Subplot)
332 %>
which is **implicitly** passed to
this dynamic method (not by the user).<br>
333 %> \param[in] varargin : Any ``property, value`` pair of the parent
object.<br>
334 %> If the
property is a ``
struct()``, then its value must be given as a cell array,
335 %> with consecutive elements representing the
struct ``property-
name, property-value`` pairs.<br>
336 %> Note that all of these property-value pairs can be also directly set via the
337 %> parent
object attributes, before calling the ``make()`` method.<br>
342 %> s = pm.vis.Subplot(ptype, dfref)
350 %> This method has side-effects by manipulating
351 %> the existing attributes of the parent
object.<br>
356 %> dfref = rand(1000, 3);
357 %> s = pm.vis.Subplot(
"scatter", dfref);
358 %> s.make(
"colx", 1,
"coly", 2,
"colc", 3)
363 %> \include{lineno} example/vis/
Subplot/main.m
384 %> \JoshuaOsborne, May 22 2024, 6:36 PM, University of Texas at Arlington<br>
385 %> \FatemehBagheri, May 20 2024, 1:25 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
386 %> \AmirShahmoradi, July 5 2024, 1:07 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
387 function make(self, varargin)
389 self.premake(varargin{:});
391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 %%%% RULE 0: No component of ``self`` is allowed to appear to the left of assignment
operator, except ``fout``.
393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395 %%%% Set what to plot.
397 noPlotEnabled =
false;
398 noPlotEnabled = noPlotEnabled || (self.type.is.scatter && ~self.scatter.enabled);
399 noPlotEnabled = noPlotEnabled || (self.type.is.scatter3 && ~self.scatter3.enabled);
400 noPlotEnabled = noPlotEnabled || (self.type.is.line && ~self.plot.enabled && ~self.surface.enabled);
401 noPlotEnabled = noPlotEnabled || (self.type.is.line3 && ~self.plot3.enabled && ~self.surface.enabled);
402 noPlotEnabled = noPlotEnabled || (self.type.is.lineScatter && ~self.plot.enabled && ~self.surface.enabled && ~self.scatter.enabled);
403 noPlotEnabled = noPlotEnabled || (self.type.is.lineScatter3 && ~self.plot3.enabled && ~self.surface.enabled && ~self.scatter3.enabled);
404 noPlotEnabled = noPlotEnabled || (self.type.is.histogram2 && ~self.histogram2.enabled);
405 noPlotEnabled = noPlotEnabled || (self.type.is.histogram && ~self.histogram.enabled);
406 noPlotEnabled = noPlotEnabled || (self.type.is.contourf && ~self.contourf.enabled);
407 noPlotEnabled = noPlotEnabled || (self.type.is.contour3 && ~self.contour3.enabled);
408 noPlotEnabled = noPlotEnabled || (self.type.is.histfit && ~self.histfit.enabled);
409 noPlotEnabled = noPlotEnabled || (self.type.is.contour && ~self.contour.enabled);
410 noPlotEnabled = noPlotEnabled || (self.type.is.heatmap && ~self.heatmap.enabled);
413 +
"All plot types are deactivated by the user. There is nothing to display." + newline ...
414 +
"Enable at least one the following plotting components of the parent object." + newline ...
419 dfcopy = self.dfref.copy();
421 help(
"pm.vis.Subplot");
423 +
"There is no data to plot." + newline ...
424 +
"Without any input data, visualizations are impossible." + newline ...
425 +
"The input argument ``dfref`` to the object constructor was likely empty." + newline ...
426 +
"If you merely want to create a template of visualization specifications," + newline ...
427 +
"then use the class [pm.vis.axes.Axes](@ref Axes) which is the superclass of this class." + newline ...
428 +
"For more information, see the class documentation displayed above." + newline ...
434 %%%% check rows presence
437 if pm.array.len(self.rows)
438 rowsindex = self.rows(:);
440 rowsindex = [1 : self.dfref.nrow()]
';
443 %%%%%%%%%%%%%%%%%%%%%%%%%%%
444 %%%% check columns presence
445 %%%%%%%%%%%%%%%%%%%%%%%%%%%
447 coldatx = []; colindx = []; colnamx = [];
448 if isprop(self, "colx") && pm.array.len(self.colx)
449 [colindx, colnamx] = pm.str.locname(dfcopy.Properties.VariableNames, self.colx);
450 elseif self.type.is.heatmap || self.type.is.d1
451 colnamx = dfcopy.Properties.VariableNames;
452 colindx = 1 : length(colnamx);
455 colnamx = "Row Index";
458 coldaty = []; colindy = []; colnamy = [];
459 if isprop(self, "coly") && pm.array.len(self.coly)
460 [colindy, colnamy] = pm.str.locname(dfcopy.Properties.VariableNames, self.coly);
461 elseif self.type.is.density && ~self.type.is.histogram2
462 if isfield(self.(self.type.name), "normalization") && ~isempty(self.(self.type.name).normalization)
463 colnamy = string(self.(self.type.name).normalization);
464 elseif self.type.is.d1
469 elseif self.type.is.heatmap
470 if isempty(dfcopy.Properties.RowNames)
471 dfcopy.Properties.RowNames = string(rowsindex);
473 colnamy = dfcopy.Properties.RowNames;
476 colnamy = "Row Index";
479 coldatz = []; colindz = []; colnamz = [];
480 if isprop(self, "colz") && pm.array.len(self.colz)
481 [colindz, colnamz] = pm.str.locname(dfcopy.Properties.VariableNames, self.colz);
482 elseif self.type.has.line || self.type.has.scatter
484 % This is necessary for 2D surface plot.
485 coldatz = zeros(length(rowsindex), 1);
488 colnamz = "Row Index";
490 elseif self.type.is.density && self.type.is.triaxes
494 coldatc = []; colindc = []; colnamc = [];
495 if isprop(self, "colc") && pm.array.len(self.colc)
496 [colindc, colnamc] = pm.str.locname(dfcopy.Properties.VariableNames, self.colc);
497 elseif self.type.has.line || self.type.has.scatter
498 if ~isempty(colnamz) && ~(isempty(coldatz) && isempty(colindz))
504 colnamc = "Row Index";
506 elseif self.type.is.density && ~self.type.is.d1
510 %%%% check the lengths are consistent.
512 colindlen = max([ length(colindc) ...
513 , length(colindz) ...
514 , length(colindy) ...
515 , length(colindx) ...
518 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
519 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
520 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
521 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
523 %%%% assign data in case of single column assignments.
525 if length(colindx) == 1; coldatx = dfcopy{rowsindex, colindx}; end
526 if length(colindy) == 1; coldaty = dfcopy{rowsindex, colindy}; end
527 if length(colindz) == 1; coldatz = dfcopy{rowsindex, colindz}; end
528 if length(colindc) == 1; coldatc = dfcopy{rowsindex, colindc}; end
530 %%%% get keyword arguments.
533 for prop = [ "axes" ...
554 if isprop(self, prop)
555 kws.(prop) = self.comp2hash(prop);
559 for prop = ["scatter", "scatter3"]
560 if isprop(self, prop) && self.(prop).filled
561 kws.(prop) = [{"filled"}; kws.(prop)(:)];
565 %%%% generate the kde2d density estimates for the contour plots.
567 kde2dUpdateNeeded = self.type.is.diffusion && (1 < length(colindx) || 1 < length(colindy));
568 if self.type.is.diffusion
570 if ~kde2dUpdateNeeded
571 [kde2d.bandwidth, kde2d.density, kde2d.crdx, kde2d.crdy] = pm.stats.hist.kde2d([coldatx(:), coldaty(:)], self.resolution);
572 kde2d.density(kde2d.density < self.maxnoise) = NaN;
576 %%%% determine the multicolor nature of the plots.
578 isMultiColorPlot = false;
579 if ~self.cenabled && (self.type.has.scatter || self.type.is.diffusion)
580 if self.type.is.diffusion
581 prop = self.type.name;
582 elseif self.type.is.d2
584 elseif self.type.is.d3
587 error("Internal error occurred. A line/scatter plot must be either 2D or 3D.");
589 if pm.array.len(self.(prop).color)
590 if all(size(self.(prop).color) == [colindlen, 3])
591 isMultiColorPlot = true;
592 multiColorList = self.(prop).color;
593 elseif all(size(self.(prop).color) == [1, 3]) || self.type.is.diffusion
594 coldatc = self.(prop).color;
597 + "The value specified for the 'color
' property of the " + prop + " component" + newline ...
598 + "must be either an RGB triplet vector of size [1, 3], or a matrix of size [" + string(colindlen) + ", 3]" + newline ...
599 + "for the current set of variables that are selected to plot. " + newline ...
600 + "It can also be an empty object, in which case, the colors" + newline ...
601 + "of the objects in the plot will be chosen automatically." + newline ...
606 multiColorList = lines(colindlen);
607 isMultiColorPlot = true;
609 elseif self.type.is.diffusion && ~pm.array.len(self.(self.type.name).color)
610 coldatc = self.(self.type.name).color;
613 %%%% initiate the legend.
615 legendary = isprop(self, "legend") && self.legend.enabled;
617 legempty = pm.array.len(self.legend.labels) == 0;
618 lglabels = strings(colindlen, 1);
624 %%%% generate axes and set axes properties.
626 if isprop(self, "axes")
627 self.fout.axes = gca;
629 % This setting must happen here, before any
630 % individual axes component settings below.
631 set(gca, kws.axes{:});
633 if self.type.is.triaxes
640 %%%% Ensure points and lines are scaled properly.
641 %%%% It is not clear whether it's worth doing so because
642 %%%% most figure resizing happen after making it,
643 %%%%
which makes the following solution useless.
647 %
if ~strcmpi(self.fout.axes.Units,
"normalized")
648 % temp = self.fout.axes.Units;
649 % self.fout.axes.Units =
"normalized";
651 % defaultSizeFig = [560, 420] % width, height in pixels.
652 % defaultSizeAxes = [0.775, 0.815] % width, height in pixels (assuming no colorbar).
653 % self.fout.axes.Position
655 % self.fout.axes.Units = temp;
660 if self.type.is.heatmap && self.heatmap.enabled
662 if ~isempty(self.precision)
663 self.fout.heatmap = heatmap(colnamx, colnamy, round(dfcopy{colnamy, colnamx}, self.precision), kws.heatmap{:});
665 self.fout.heatmap = heatmap(colnamx, colnamy, dfcopy{colnamy, colnamx}, kws.heatmap{:});
670 if ~self.type.has.line && ~self.type.has.scatter
671 % line/scatter plots must be taken care of separately.
672 self.fout.(self.type.name) = cell(colindlen, 1);
675 for icol = 1 : colindlen
677 %%%% set the data to plot.
679 if 1 < length(colindx);
if legendary; icollgx = icol; end; coldatx = dfcopy{rowsindex, colindx(icol)}; end
680 if 1 < length(colindy);
if legendary; icollgy = icol; end; coldaty = dfcopy{rowsindex, colindy(icol)}; end
681 if 1 < length(colindz);
if legendary; icollgz = icol; end; coldatz = dfcopy{rowsindex, colindz(icol)}; end
684 coldatc = multiColorList(icol, :);
685 elseif 1 < length(colindc)
686 coldatc = dfcopy{rowsindex, colindc(icol)};
689 if self.type.is.diffusion
691 kws.(self.type.name) = pm.matlab.hashmap.repKeyVal(
"color", coldatc, kws.(self.type.name));
694 [
kde2d.bandwidth,
kde2d.density,
kde2d.crdx,
kde2d.crdy] = pm.stats.hist.kde2d([coldatx(:), coldaty(:)], self.resolution);
695 kde2d.density(
kde2d.density < self.maxnoise) = NaN;
699 %%%% set the
default legend.
701 if legendary && legempty
702 if 1 < length(colindz)
703 suffix =
"-" + colnamz(icollgz);
707 if length(colindx) < 2 && 1 < length(colindy)
708 lglabels(icol) = colnamy(icollgy) + suffix;
709 elseif 1 < length(colindx) && length(colindy) < 2
710 lglabels(icol) = colnamx(icollgx) + suffix;
712 lglabels(icol) = colnamx(icollgx) +
"-" + colnamy(icollgy) + suffix;
716 %%%% add density plot.
718 if self.type.is.contour
719 self.fout.contour{icol} =
struct();
720 [self.fout.contour{icol}.matrix, self.fout.contour{icol}.handle] = contour (
kde2d.crdx ...
723 , self.contour.levels ...
726 elseif self.type.is.contour3
727 self.fout.contour3{icol} =
struct();
728 [self.fout.contour3{icol}.matrix, self.fout.contour3{icol}.handle]= contour3(
kde2d.crdx...
731 , self.contour3.levels ...
732 , kws.contour3{:} ...
734 elseif self.type.is.contourf
735 self.fout.contourf{icol} =
struct();
736 [self.fout.contourf{icol}.matrix, self.fout.contourf{icol}.handle]= contourf(
kde2d.crdx ...
739 , self.contourf.levels ...
740 , kws.contourf{:} ...
742 elseif self.type.is.histfit
743 self.fout.histfit{icol} = histfit(coldatx, self.histfit.nbins, self.histfit.dist, kws.histfit{:});
744 self.fout.histfit{icol}(1).FaceAlpha = 0.6; % make histogram face transparent 60%
745 self.fout.histfit{icol}(1).EdgeAlpha = 0; % make histogram lines invisible
746 self.fout.histfit{icol}(2).Color =
"black"; % make the fitted line black
747 elseif self.type.is.histogram
748 if ~isempty(self.histogram.nbins)
749 self.fout.histogram{icol} = histogram(coldatx, self.histogram.nbins, kws.histogram{:});
750 elseif ~isempty(self.histogram.edges)
751 self.fout.histogram{icol} = histogram(coldatx, self.histogram.edges, kws.histogram{:});
753 self.fout.histogram{icol} = histogram(coldatx, kws.histogram{:});
755 elseif self.type.is.histogram2
756 self.fout.histogram2{icol} = histogram2(coldatx, coldaty, kws.histogram2{:});
761 if self.type.has.line
762 if self.type.is.d2 && self.plot.enabled
763 self.fout.plot{icol} = plot ( coldatx ...
767 elseif self.type.is.d3 && self.plot3.enabled
768 self.fout.plot3{icol} = plot3 ( coldatx ...
774 if self.surface.enabled && self.colormap.enabled
775 self.fout.surface{icol} = surface (
"XData", [coldatx(:), coldatx(:)] ...
776 ,
"YData", [coldaty(:), coldaty(:)] ...
777 ,
"ZData", [coldatz(:), coldatz(:)] ...
778 ,
"CData", [coldatc(:), coldatc(:)] ...
784 %%%% add scatter plot.
786 if self.type.has.scatter
787 if self.type.is.d3 && self.scatter3.enabled
788 self.fout.scatter3{icol} = scatter3 ( coldatx ...
791 , self.scatter3.size ...
793 , self.scatter3.marker ...
794 , kws.scatter3{:} ...
796 elseif self.type.is.d2 && self.scatter.enabled
797 self.fout.scatter{icol} = scatter ( coldatx ...
799 , self.scatter.size ...
801 , self.scatter.marker ...
807 end % loop over plots
809 end %
if heatmap plot.
812 if ~self.type.is.heatmap
813 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
814 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
815 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
817 if isprop(self,
"xlabel") && self.xlabel.enabled; xlabel(self.xlabel.txt, kws.xlabel{:}); end
818 if isprop(self,
"ylabel") && self.ylabel.enabled; ylabel(self.ylabel.txt, kws.ylabel{:}); end
821 % add the colormap and colorbar.
823 if ~self.cenabled && self.type.is.heatmap
824 colormap(flipud(gray)); % self.fout.colormap =
825 elseif ~self.cenabled && self.type.is.contourf
826 colormap(self.fout.axes, flipud(gray)); % self.fout.colormap =
828 if ~isempty(self.colormap.map) || (isstring(self.colormap.map) && self.colormap.map ~=
"")
829 cmap = self.colormap.map;
831 if self.type.has.line || self.type.has.scatter
834 % self.colormap.map =
"winter";
836 % self.colormap.map =
"autumn";
838 elseif self.type.is.heatmap
839 cmap = pm.vis.cmap.redblue();
840 elseif self.type.is.density
844 if ~self.type.is.heatmap
845 colormap(self.fout.axes, cmap); % self.fout.colormap =
847 colormap(cmap); % self.fout.colormap =
851 if isprop(self,
"colorbar")
852 if self.colorbar.enabled && (self.cenabled || self.type.is.contourf)
853 if isempty(self.colorbar.fontSize) %|| ~isa(self.colorbar.fontSize, "numeric")
854 kws.colorbar = [kws.colorbar(:); {
"fontSize"}; {self.fout.axes.FontSize + 1}];
856 self.fout.colorbar = colorbar(kws.colorbar{:});
857 ylabel(self.fout.colorbar, colnamc(1));%,
"fontSize", self.colorbar.fontSize,
"interpreter",
"none"
860 self.fout.colorbar = [];
866 if legendary && 0 < colindlen
867 self.fout.legend = [];
869 lglabels = self.legend.labels;
871 if ~self.legend.enabled
872 legend(self.fout.axes,
"off");
873 elseif isa(self.legend.labels,
"cell") || isa(self.legend.labels,
"string")
874 if isempty(self.legend.fontSize)
875 kws.legend = [kws.legend(:); {
"fontSize"}; {self.fout.axes.FontSize + 1}];
878 if self.type.has.scatter && self.type.is.d2 && self.scatter.enabled
879 subset = [self.fout.scatter{:}];
880 elseif self.type.has.scatter && self.type.is.d3 && self.scatter3.enabled
881 subset = [self.fout.scatter3{:}];
883 elseif self.type.is.histfit && self.histfit.enabled
884 nhandle = length(self.fout.histfit);
885 subset = cell(nhandle, 1);
887 subset{i} = self.fout.histfit{i}(1); % get the handle to the histogram component of histfit.
889 subset = [subset{:}];
892 self.fout.legend = legend(subset, lglabels{:}, kws.legend{:});
894 self.fout.legend = legend(lglabels{:}, kws.legend{:});
898 +
"The specified ""legend.labels"" must be a cell array of string values." ...
904 %
if self.type.is.targetable
905 % self.target.fout.axes = self.fout.axes;
910 if self.title.enabled
912 for field = [
"titletext",
"subtitletext"] %
do not change the order of elements here.
913 if isfield(self.title, field) && pm.array.len(self.title.(field))
914 titletxt = [titletxt(:); self.title.(field)(:)];
917 if ~isempty(titletxt)
918 if ~self.type.is.heatmap
920 % kws.title = {titletxt{:}, kws.title(:)};
922 self.fout.title = title(self.fout.axes, titletxt{:}, kws.title{:});
924 %%%% Neither input nor output arguments are not supported when
using title with heatmap.
932 for prop = [
"xlim",
"ylim",
"zlim"]
933 if isprop(self, prop) && ~isempty(self.(prop))
934 limit = get(self.fout.axes, prop);
936 if ~isnan(self.(prop)(i))
937 limit(i) = self.(prop)(i);
940 set(self.fout.axes, prop, limit);
944 %%%% set axes scales.
946 for prop = ["xscale", "yscale", "zscale"]
947 if isprop(self, prop) && ~isempty(self.(prop))
948 set(self.fout.axes, prop, self.(prop));
952 if ~self.type.is.heatmap
960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 methods(Access = public, Hidden)
968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
971 %> Prepare the subplot for visualization.<br>
973 %> \param[inout] self : The input/output parent
object of class [pm.vis.
Subplot](@ref
Subplot)
974 %>
which is **implicitly** passed to this dynamic method (not by the user).<br>
975 %> \param[in] varargin : Any ``property, value`` pair of the parent
object.<br>
976 %> If the property is a ``struct()``, then its value must be given as a cell array,
977 %> with consecutive elements representing the struct ``property-
name, property-value`` pairs.<br>
978 %> Note that all of these property-value pairs can be also directly set via the
979 %> parent
object attributes, before calling the ``premake()`` method.<br>
981 %> \interface{premake}
984 %> s = pm.vis.Subplot(ptype, dfref);
986 %> s.premake(varargin);
992 %> This method has side-effects by manipulating
993 %> the existing attributes of the parent
object.<br>
998 %> dfref = rand(1000, 3);
999 %> s = pm.vis.Subplot(
"scatter", dfref);
1000 %> s.premake(
"colx", 1,
"coly", 2,
"colc", 3)
1007 %> \JoshuaOsborne, May 22 2024, 6:41 PM, University of Texas at Arlington<br>
1008 %> \FatemehBagheri, May 20 2024, 1:25 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
1009 %> \AmirShahmoradi, July 5 2024, 1:07 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
1010 function premake(self, varargin)
1011 premake@pm.vis.axes.Axes(self, varargin{:});
1014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1017 %> Reset the properties of the plot to the original
default settings.<br>
1020 %> Use
this method when you change many attributes of the plot and
1021 %> you want to
clean up and go back to the
default settings.<br>
1023 %> \param[inout] self : The input/output parent
object of
class [pm.vis.Subplot](@ref
Subplot)
1024 %>
which is **implicitly** passed to
this dynamic method (not by the user).<br>
1025 %> \param[in] varargin : Any ``property, value`` pair of the parent
object.<br>
1026 %> If the
property is a ``
struct()``, then its value must be given as a cell array,
1027 %> with consecutive elements representing the
struct ``property-
name, property-value`` pairs.<br>
1028 %> Note that all of these property-value pairs can be also directly set via the
1029 %> parent
object attributes, before calling the ``make()`` method.<br>
1031 %> \interface{reset}
1034 %> pm.vis.Subplot.reset() % reset the plot to the
default settings.
1041 %> \JoshuaOsborne, May 22 2024, 6:43 PM, University of Texas at Arlington<br>
1042 %> \FatemehBagheri, May 20 2024, 1:25 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
1043 %> \AmirShahmoradi, July 5 2024, 1:07 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
1044 function reset(self, varargin)
1046 self.fout =
struct();
1047 self.newprop(
"colx", {});
1048 if self.type.is.d2 || self.type.is.d3
1049 self.newprop(
"coly", {});
1051 self.newprop(
"colz", {});
1054 reset@pm.vis.axes.Axes(self, varargin{:});
1057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function name(in vendor)
Return the MPI library name as used in naming the ParaMonte MATLAB shared library directories.
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 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 dfref.
This is the abstract class for generating instances of objects that contain the specifications of var...
This is the base class for generating instances of figures containing a square symmetric tiling of su...
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...