diff --git a/plotly/plotlyfig.m b/plotly/plotlyfig.m index 08e1bbfc..317213b6 100644 --- a/plotly/plotlyfig.m +++ b/plotly/plotlyfig.m @@ -681,6 +681,8 @@ function validate(obj) end % update plots + obj.PlotOptions.nplots = obj.State.Figure.NumPlots; + for n = 1:obj.State.Figure.NumPlots updateData(obj,n); @@ -1015,6 +1017,8 @@ function delete(obj) || strcmpi(fieldname,'scene') || strcmpi(fieldname,'layout') ... || strcmpi(fieldname,'heatmap') || strcmpi(fieldname,'xaxis') ... || strcmpi(fieldname,'yaxis') || strcmpi(fieldname,'cone')... + || strcmpi(fieldname,'legend') || strcmpi(fieldname,'histogram')... + || strcmpi(fieldname,'scatter')... ) fprintf(['\nWhoops! ' exception.message(1:end-1) ' in ' fieldname '\n\n']); end diff --git a/plotly/plotlyfig_aux/core/updateData.m b/plotly/plotlyfig_aux/core/updateData.m index 5b11064e..171da3ca 100644 --- a/plotly/plotlyfig_aux/core/updateData.m +++ b/plotly/plotlyfig_aux/core/updateData.m @@ -36,7 +36,9 @@ switch lower(obj.State.Plot(dataIndex).Class) %--CORE PLOT OBJECTS--% - case 'wordcloud' + case 'scatterhistogram' + updateScatterhistogram(obj, dataIndex); + case 'wordcloud' updateWordcloud(obj, dataIndex); case 'heatmap' updateHeatmap(obj, dataIndex); diff --git a/plotly/plotlyfig_aux/handlegraphics/updateScatterhistogram.m b/plotly/plotlyfig_aux/handlegraphics/updateScatterhistogram.m new file mode 100644 index 00000000..380249aa --- /dev/null +++ b/plotly/plotlyfig_aux/handlegraphics/updateScatterhistogram.m @@ -0,0 +1,476 @@ +function updateScatterhistogram(obj,scatterIndex) + +%-AXIS INDEX-% +axIndex = obj.getAxisIndex(obj.State.Plot(scatterIndex).AssociatedAxis); + +%-SCATTER DATA STRUCTURE- % +scatter_data = get(obj.State.Plot(scatterIndex).Handle); + +%-CHECK FOR MULTIPLE AXES-% +[xsource, ysource, xoverlay, yoverlay] = findSourceAxis(obj,axIndex); + +%-parcing data-% +xplot = scatter_data.XData; +yplot = scatter_data.YData; + +xcateg = iscategorical(xplot); +ycateg = iscategorical(yplot); + +if xcateg + [xcats, ~, xplot] = unique(xplot); + xc = {}; + for c=1:length(xcats) + xc{c} = char(xcats(c)); + end +end +if ycateg + [ycats, ~, yplot] = unique(yplot); + yc = {}; + for c=1:length(ycats) + yc{c} = char(ycats(c)); + end +end + +xdata = {}; ydata = {}; +gd = scatter_data.GroupData; +st = scatter_data.SourceTable; + +bygroups = ~isempty(gd); + +if bygroups + if iscellstr(gd) + gd = string(gd); + end + + gs = unique(gd,'stable'); + + for g=1:length(gs) + inds = gd == gs(g); + xdata{g} = xplot(inds); + ydata{g} = yplot(inds); + end + +else + xdata{1} = xplot; + ydata{1} = yplot; +end + +%=========================================================================% +% +%-UPDATE MAIN PLOT-% +% +%=========================================================================% + +for t=1:length(xdata) + + p = t; + if t > 1 + obj.PlotOptions.nplots = obj.PlotOptions.nplots + 1; + p = obj.PlotOptions.nplots; + end + + %-----------------------------------------------------------------------% + + %-scatter type-% + obj.data{p}.type = 'scatter'; + + %-----------------------------------------------------------------------% + + %-scatter mode-% + obj.data{p}.mode = 'markers'; + + %-----------------------------------------------------------------------% + + % %-scatter visible-% + obj.data{p}.visible = strcmp(scatter_data.Visible,'on'); + + %-----------------------------------------------------------------------% + + %-scatter data-% + obj.data{p}.x = xdata{t}; + obj.data{p}.y = ydata{t}; + + %-----------------------------------------------------------------------% + + %-scatter marker-% + childmarker = extractScatterhistogramMarker(scatter_data, t); + obj.data{p}.marker = childmarker; + + %-----------------------------------------------------------------------% + + %-associate x and y axis layout-% + obj.data{p}.xaxis = sprintf('x%d', xsource); + obj.data{p}.yaxis = sprintf('y%d', ysource); + + %-----------------------------------------------------------------------% + + %-legend-% + + if bygroups + try + obj.data{p}.name = char(gs(t)); + catch + obj.data{p}.name = char(string(gs(t))); + end + + obj.data{p}.legendgroup = obj.data{p}.name; + obj.data{p}.showlegend = true; + end + +end + +%-------------------------------------------------------------------------% + +%-create xaxis layout-% +xo = scatter_data.Position(1); +yo = scatter_data.Position(2); +w = scatter_data.Position(3); +h = scatter_data.Position(4); +axiscol = 'rgba(0,0,0, 0.4)'; + +xaxis.domain = min([xo xo + w],1); +xaxis.showgrid = false; +xaxis.showticklabels = true; +xaxis.zeroline = true; +xaxis.anchor = sprintf('y%d', xsource); +xaxis.linecolor = axiscol; +xaxis.tickcolor = axiscol; +xaxis.mirror = 'ticks'; +xaxis.ticks = 'inside'; +xaxis.font.family = matlab2plotlyfont(scatter_data.FontName); +xaxis.tickfont.size = 1.2*scatter_data.FontSize; +xaxis.title.text = scatter_data.XLabel; +xaxis.title.font.family = matlab2plotlyfont(scatter_data.FontName); +xaxis.title.font.size = 1.2*scatter_data.FontSize; + +if ~xcateg + xaxis.range = scatter_data.XLimits; +else + xaxis.range = [min(xplot)-0.5, max(xplot)+0.5]; + xaxis.tickvals = 1:max(xplot); + xaxis.ticktext = xc; +end + +if xoverlay + xaxis.overlaying = sprintf('x%d', xoverlay); +end + +%-------------------------------------------------------------------------% + +%-create yaxis layout-% +yaxis.domain = min([yo yo + h],1); +yaxis.showgrid = false; +yaxis.showticklabels = true; +yaxis.zeroline = true; +yaxis.anchor = sprintf('x%d', ysource); +yaxis.linecolor = axiscol; +yaxis.tickcolor = axiscol; +yaxis.mirror = 'ticks'; +yaxis.ticks = 'inside'; +yaxis.tickfont.family = matlab2plotlyfont(scatter_data.FontName); +yaxis.tickfont.size = 1.2*scatter_data.FontSize; +yaxis.title.text = scatter_data.YLabel; +yaxis.title.font.family = matlab2plotlyfont(scatter_data.FontName); +yaxis.title.font.size = 1.2*scatter_data.FontSize; + +if ~ycateg + yaxis.range = scatter_data.YLimits; +else + yaxis.range = [min(yplot)-0.5, max(yplot)+0.5]; + yaxis.tickvals = 1:max(yplot); + yaxis.ticktext = yc; +end + +if yoverlay + yaxis.overlaying = sprintf('y%d', yoverlay); +end + +%-------------------------------------------------------------------------% + +%-set x and y axis layout-% +obj.layout = setfield(obj.layout, sprintf('xaxis%d',xsource), xaxis); +obj.layout = setfield(obj.layout, sprintf('yaxis%d',ysource), yaxis); + +%-------------------------------------------------------------------------% + +%-remove any annotation text-% +istitle = length(scatter_data.Title) > 0; +obj.layout.annotations{1}.text = ' '; +obj.layout.annotations{1}.showarrow = false; + +if istitle + obj.layout.annotations{1}.text = sprintf('%s', scatter_data.Title); + obj.layout.annotations{1}.xref = 'paper'; + obj.layout.annotations{1}.yref = 'paper'; + obj.layout.annotations{1}.yanchor = 'top'; + obj.layout.annotations{1}.xanchor = 'middle'; + obj.layout.annotations{1}.x = mean(xaxis.domain); + obj.layout.annotations{1}.y = 0.96; + obj.layout.annotations{1}.font.color = 'black'; + obj.layout.annotations{1}.font.family = matlab2plotlyfont(scatter_data.FontName); + obj.layout.annotations{1}.font.size = 1.5*scatter_data.FontSize; +end + + +%layout legend-% +if bygroups + obj.layout.showlegend = true; + obj.layout.legend.xref = 'paper'; + obj.layout.legend.borderwidth = 1; + obj.layout.legend.bordercolor = 'rgba(0,0,0,0.2)'; + obj.layout.legend.font.family = matlab2plotlyfont(scatter_data.FontName); + obj.layout.legend.font.size = 1.0*scatter_data.FontSize; + obj.layout.legend.valign = 'middle'; + + if length(scatter_data.LegendTitle) > 0 + obj.layout.legend.title.text = sprintf('%s', scatter_data.LegendTitle); + obj.layout.legend.title.side = 'top'; + obj.layout.legend.title.font.family = matlab2plotlyfont(scatter_data.FontName); + obj.layout.legend.title.font.size = 1.2*scatter_data.FontSize; + obj.layout.legend.title.font.color = 'black'; + end + + if ~isempty(strfind(scatter_data.ScatterPlotLocation, 'SouthWest')) + obj.layout.legend.x = 0.96; + obj.layout.legend.y = 0.96; + obj.layout.legend.xanchor = 'right'; + obj.layout.legend.yanchor = 'top'; + elseif ~isempty(strfind(scatter_data.ScatterPlotLocation, 'NorthEast')) + obj.layout.legend.x = 0.02; + obj.layout.legend.y = 0.02; + obj.layout.legend.xanchor = 'left'; + obj.layout.legend.yanchor = 'bottom'; + end +end + +%-------------------------------------------------------------------------% + +%=========================================================================% +% +%-UPDATE MARGINAL X AXIS-% +% +%=========================================================================% + +for t=1:length(xdata) + + obj.PlotOptions.nplots = obj.PlotOptions.nplots + 1; + p = obj.PlotOptions.nplots; + + if t == 1 + ps = p; + end + + %-----------------------------------------------------------------------% + + %-histogram type-% + obj.data{p}.type = 'histogram'; + + %-----------------------------------------------------------------------% + + %-set plot data-% + obj.data{p}.x = xdata{t}; + obj.data{p}.y = ydata{t}; + obj.data{p}.nbinsx = scatter_data.NumBins(1, t); + + %-----------------------------------------------------------------------% + + %-plot setting-% + obj.data{p}.marker.color = sprintf('rgba(%f,%f,%f,0.7)', scatter_data.Color(t, :)); + obj.data{p}.histnorm = 'probability'; + obj.data{p}.histfunc = 'count'; + + %-----------------------------------------------------------------------% + + %-associate x and y axis layout-% + obj.data{p}.xaxis = sprintf('x%d', ps); + obj.data{p}.yaxis = sprintf('y%d', ps); + obj.data{p}.showlegend = false; + + if bygroups + try + obj.data{p}.name = char(gs(t)); + catch + obj.data{p}.name = char(string(gs(t))); + end + + obj.data{p}.legendgroup = obj.data{p}.name; + end + + %-----------------------------------------------------------------------% + +end + +%-------------------------------------------------------------------------% + +%-create xaxis layout-% +xbase = xaxis.domain; + +if ~isempty(strfind(scatter_data.ScatterPlotLocation, 'South')) + yo1 = yo + h*1.02; + + if istitle + h1 = 0.9 - yo1; + else + h1 = 0.96 - yo1; + end + +elseif ~isempty(strfind(scatter_data.ScatterPlotLocation, 'North')) + yo1 = 0.02; + h1 = yo*0.7 - yo1; +end + +xo1 = xo; +w1 = w; + +xaxis1.showgrid = false; +xaxis1.showticklabels = false; +xaxis1.zeroline = false; +xaxis1.range = scatter_data.XLimits; +xaxis1.domain = min([xo1 xo1+w1],1); +xaxis1.anchor = sprintf('y%d', ps); +xaxis1.color = 'rgba(0,0,0,0)'; + +if xoverlay + xaxis1.overlaying = sprintf('x%d', ps); +end + +%-------------------------------------------------------------------------% + +%-create yaxis layout-% +yaxis1.showgrid = false; +yaxis1.showticklabels = false; +yaxis1.zeroline = true; +yaxis1.zerolinecolor = axiscol; +yaxis1.domain = min([yo1 yo1+h1],1); +yaxis1.anchor = sprintf('x%d', ps); +yaxis1.color = 'rgba(0,0,0,0)'; + +if yoverlay + yaxis1.overlaying = sprintf('y%d', ps); +end + +%-------------------------------------------------------------------------% + +%-set x and y axis layout-% +obj.layout = setfield(obj.layout, sprintf('xaxis%d', ps), xaxis1); +obj.layout = setfield(obj.layout, sprintf('yaxis%d', ps), yaxis1); + +obj.layout.barmode = 'overlay'; +obj.layout.bargap = 0.05; + + +%=========================================================================% +% +%-UPDATE MARGINAL Y AXIS-% +% +%=========================================================================% + +for t=1:length(xdata) + + obj.PlotOptions.nplots = obj.PlotOptions.nplots + 1; + p = obj.PlotOptions.nplots; + + if t == 1 + ps = p; + end + + %-----------------------------------------------------------------------% + + %-histogram type-% + obj.data{p}.type = 'histogram'; + + %-----------------------------------------------------------------------% + + %-set plot data-% + obj.data{p}.x = xdata{t}; + obj.data{p}.y = ydata{t}; + obj.data{p}.nbinsy = scatter_data.NumBins(2, t); + + %-----------------------------------------------------------------------% + + %-plot setting-% + obj.data{p}.marker.color = sprintf('rgba(%f,%f,%f, 0.7)', scatter_data.Color(t, :)); + obj.data{p}.histnorm = 'probability'; + obj.data{p}.histfunc = 'count'; + obj.data{p}.orientation = 'h'; + + %-----------------------------------------------------------------------% + + %-associate x and y axis layout-% + obj.data{p}.xaxis = sprintf('x%d', ps); + obj.data{p}.yaxis = sprintf('y%d', ps); + obj.data{p}.showlegend = false; + + if bygroups + try + obj.data{p}.name = char(gs(t)); + catch + obj.data{p}.name = char(string(gs(t))); + end + + obj.data{p}.legendgroup = obj.data{p}.name; + end + + %-----------------------------------------------------------------------% + +end + +%-------------------------------------------------------------------------% + +%-create xaxis layout-% +ybase = yaxis.domain; +if ~isempty(strfind(scatter_data.ScatterPlotLocation, 'West')) + xo2 = xo + w * 1.0075; + w2 = 0.96 - xo2; +elseif ~isempty(strfind(scatter_data.ScatterPlotLocation, 'East')) + xo2 = 0.02; + w2 = xo*0.7 - xo2; +end + +yo2 = yo; +h2 = h; + +xaxis2.showgrid = false; +xaxis2.showticklabels = false; +xaxis2.zeroline = true; +xaxis2.zerolinecolor = axiscol; +xaxis2.domain = min([xo2 xo2+w2],1); +xaxis2.anchor = sprintf('y%d', ps); +xaxis2.color = 'rgba(0,0,0,0)'; + +if xoverlay + xaxis2.overlaying = sprintf('x%d', ps); +end + +%-------------------------------------------------------------------------% + +%-create yaxis layout-% +yaxis2.showgrid = false; +yaxis2.showticklabels = false; +yaxis2.zeroline = false; +yaxis2.domain = min([yo2 yo2+h2],1); +yaxis2.anchor = sprintf('x%d', ps); +yaxis2.color = 'rgba(0,0,0,0)'; + +if ~ycateg + yaxis2.range = scatter_data.YLimits; +else + yaxis2.range = [min(yplot)-0.5, max(yplot)+0.5]; + yaxis2.tickvals = 1:max(yplot); + yaxis2.ticktext = yc; +end + +if yoverlay + yaxis2.overlaying = sprintf('y%d', ps); +end + +%-------------------------------------------------------------------------% + +%-set x and y axis layout-% +obj.layout = setfield(obj.layout, sprintf('xaxis%d',ps), xaxis2); +obj.layout = setfield(obj.layout, sprintf('yaxis%d',ps), yaxis2); + +%-------------------------------------------------------------------------% + +end + diff --git a/plotly/plotlyfig_aux/helpers/extractScatterhistogramMarker.m b/plotly/plotlyfig_aux/helpers/extractScatterhistogramMarker.m new file mode 100644 index 00000000..0309462d --- /dev/null +++ b/plotly/plotlyfig_aux/helpers/extractScatterhistogramMarker.m @@ -0,0 +1,127 @@ +function marker = extractScatterhistogramMarker(patch_data, t) + +% EXTRACTS THE MARKER STYLE USED FOR MATLAB OBJECTS +% OF TYPE "PATCH". THESE OBJECTS ARE USED IN AREASERIES +% BARSERIES, CONTOURGROUP, SCATTERGROUP. + +%-------------------------------------------------------------------------% + +%-AXIS STRUCTURE-% +axis_data = get(ancestor(patch_data.Parent,'axes')); + +%-FIGURE STRUCTURE-% +figure_data = get(ancestor(patch_data.Parent,'figure')); + +%-INITIALIZE OUTPUT-% +marker = struct(); + +%-------------------------------------------------------------------------% + +%-MARKER SIZE (STYLE)-% +marker.size = patch_data.MarkerSize(t)*0.20; + +%-------------------------------------------------------------------------% + +%-MARKER SYMBOL (STYLE)-% +if ~strcmp(patch_data.MarkerStyle(t),'none') + + switch patch_data.MarkerStyle(t) + case '.' + marksymbol = 'circle'; + case 'o' + marksymbol = 'circle'; + case 'x' + marksymbol = 'x-thin-open'; + case '+' + marksymbol = 'cross-thin-open'; + case '*' + marksymbol = 'asterisk-open'; + case {'s','square'} + marksymbol = 'square'; + case {'d','diamond'} + marksymbol = 'diamond'; + case 'v' + marksymbol = 'triangle-down'; + case '^' + marksymbol = 'triangle-up'; + case '<' + marksymbol = 'triangle-left'; + case '>' + marksymbol = 'triangle-right'; + case {'p','pentagram'} + marksymbol = 'star'; + case {'h','hexagram'} + marksymbol = 'hexagram'; + end + + marker.symbol = marksymbol; +end + +%-------------------------------------------------------------------------% + +%-MARKER LINE WIDTH (STYLE)-% +marker.line.width = patch_data.LineWidth(t); + +%-------------------------------------------------------------------------% + +%--MARKER COLOR--% + +%-figure colormap-% +colormap = figure_data.Colormap; + +% marker face color +MarkerColor = patch_data.Color(t, :); + +filledMarkerSet = {'o','square','s','diamond','d',... + 'v','^', '<','>','hexagram','pentagram'}; + +filledMarker = ismember(patch_data.MarkerStyle(t), filledMarkerSet); + +if filledMarker && strcmp(patch_data.MarkerFilled, 'on') + + if isnumeric(MarkerColor) + markercolor = sprintf('rgb(%f,%f,%f)', 255*MarkerColor); + else + + switch MarkerColor + + case 'none' + + markercolor = 'rgba(0,0,0,0)'; + + case 'auto' + + if ~strcmp(axis_data.Color,'none') + col = 255*axis_data.Color; + else + col = 255*figure_data.Color; + end + + markercolor = ['rgb(' num2str(col(1)) ',' num2str(col(2)) ',' num2str(col(3)) ')']; + + + case 'flat' + + for n = 1:length(patch_data.CData) + + capCD = max(min(patch_data.CData(n),axis_data.CLim(2)),axis_data.CLim(1)); + scalefactor = (capCD - axis_data.CLim(1))/diff(axis_data.CLim); + col = 255*(colormap(1 + floor(scalefactor*(length(colormap)-1)),:)); + + markercolor{n} = ['rgb(' num2str(col(1)) ',' num2str(col(2)) ',' num2str(col(3)) ')']; + + end + end + end + + marker.color = markercolor; + +end + +if filledMarker + marker.line.color = markercolor; +end + +%-------------------------------------------------------------------------% + +end