diff --git a/plotly/plotlyfig.m b/plotly/plotlyfig.m index 011c5caf..01fc20b5 100644 --- a/plotly/plotlyfig.m +++ b/plotly/plotlyfig.m @@ -640,9 +640,13 @@ function validate(obj) obj.State.Axis(a).Handle = ax(axrev); % add title - obj.State.Text(a).Handle = get(ax(axrev),'Title'); - obj.State.Text(a).AssociatedAxis = handle(ax(axrev)); - obj.State.Text(a).Title = true; + try + obj.State.Text(a).Handle = get(ax(axrev),'Title'); + obj.State.Text(a).AssociatedAxis = handle(ax(axrev)); + obj.State.Text(a).Title = true; + catch + % TODO + end % find plots of figure plots = findobj(ax(axrev),'-not','Type','Text','-not','Type','axes','-depth',1); @@ -768,6 +772,7 @@ function validate(obj) % reset dataget(obj.State.Figure.Handle,'Children') obj.data = {}; obj.PlotOptions.nPlots = obj.State.Figure.NumPlots; + obj.PlotlyDefaults.anIndex = obj.State.Figure.NumTexts + 1; % reset layout obj.layout = struct(); diff --git a/plotly/plotlyfig_aux/core/updateData.m b/plotly/plotlyfig_aux/core/updateData.m index de882cf1..0df2b26b 100644 --- a/plotly/plotlyfig_aux/core/updateData.m +++ b/plotly/plotlyfig_aux/core/updateData.m @@ -44,11 +44,15 @@ switch lower(obj.State.Plot(dataIndex).Class) - %--GEOAXES SPECIAL CASE--% + %--SPIDER PLOT -> SPECIAL CASE--% + case 'spider_plot_class' + updateSpiderPlot(obj, dataIndex); + + %--GEOAXES -> SPECIAL CASE--% case 'geoaxes' UpdateGeoAxes(obj, dataIndex); - %-EMULATE AXES-% + %-EMULATE AXES -> SPECIAL CASE--% case 'nothing' updateOnlyAxes(obj, dataIndex); diff --git a/plotly/plotlyfig_aux/handlegraphics/updateSpiderPlot.m b/plotly/plotlyfig_aux/handlegraphics/updateSpiderPlot.m new file mode 100644 index 00000000..28610c7e --- /dev/null +++ b/plotly/plotlyfig_aux/handlegraphics/updateSpiderPlot.m @@ -0,0 +1,607 @@ +function obj = updateSpiderPlot(obj,spiderIndex) + + %-------------------------------------------------------------------------% + + %-INITIALIZATIONS-% + axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis); + plotData = obj.State.Plot(spiderIndex).Handle; + [xSource, ySource] = findSourceAxis(obj, axIndex); + + nTraces = size(plotData.P, 1); + isLegend = false; + + axesStruct = setAxes(obj, spiderIndex); + updateSpiderLayout(obj, spiderIndex); + setAnnotation(obj, axesStruct, spiderIndex); + + if ~isempty(plotData.LegendHandle) + isLegend = true; + setLegeng(obj, spiderIndex); + end + + %-------------------------------------------------------------------------% + + %-set traces-% + for t = 1:nTraces + + %-get plotIndex-% + obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1; + plotIndex = obj.PlotOptions.nPlots; + + %-associate axis-% + obj.data{plotIndex}.xaxis = sprintf('x%d', xSource); + obj.data{plotIndex}.yaxis = sprintf('y%d', ySource); + + %-trace settings-% + obj.data{plotIndex}.type = 'scatter'; + obj.data{plotIndex}.mode = 'lines+markers'; + + if strcmp(plotData.Marker{t, 1}, 'none') + obj.data{plotIndex}.mode = 'lines'; + end + + %-set data-% + [xData, yData] = getCartesianPoints(plotData, axesStruct, t); + + obj.data{plotIndex}.x = xData; + obj.data{plotIndex}.y = yData; + + %-marker settings-% + obj.data{plotIndex}.marker = getMarker(plotData, t); + + %-line settings-% + obj.data{plotIndex}.line = getLine(plotData, t); + + %-fill area-% + if strcmp(plotData.FillOption{t}, 'on') + [fillColor, ~] = getColor(plotData.Color, t, ... + plotData.FillTransparency); + obj.data{plotIndex}.fillcolor = fillColor; + obj.data{plotIndex}.fill = 'toself'; + end + + %-legend-% + if isLegend + if strcmp(plotData.LegendHandle.Visible, 'on') + obj.data{plotIndex}.name = plotData.LegendLabels{t}; + obj.data{plotIndex}.showlegend = true; + end + end + + end + + %-------------------------------------------------------------------------% +end + +function [xData, yData] = getCartesianPoints(plotData, axesStruct, traceIndex) + + %-initializations-% + rData = plotData.P(traceIndex, :); + axesAngle = axesStruct.axesAngle; + nAxes = axesStruct.nAxes; + nTicks = axesStruct.nTicks; + + for a = 1:nAxes + + %-get axis limits-% + try + axesLim = plotData.AxesLimits(:, a)'; + catch + axesLim = [min(plotData.P(:, a)), max(plotData.P(:, a))]; + end + + %-normalize radial data-% + rPoint = [rData(a), axesLim]; + if strcmpi(plotData.AxesScaling(a), 'log') + rPoint = log10(rPoint); + end + if strcmpi(plotData.AxesDirection(a), 'reverse'); + rPoint = -rPoint; + end + rPoint = rescale(rPoint, 1/nTicks, 1); + + %-convertion-% + xData(a) = rPoint(1) * cos(axesAngle(a)); + yData(a) = rPoint(1) * sin(axesAngle(a)); + end + + %-return-% + xData = [xData, xData(1)]; + yData = [yData, yData(1)]; +end + +function lineStruct = getLine(plotData, traceIndex) + %-INITIALIZATIONS-% + lineStruct = struct(); + + %-line color-% + [lineColor, ~] = getColor(plotData.Color, traceIndex, ... + plotData.LineTransparency); + lineStruct.color = lineColor; + + %-line width-% + lineStruct.width = plotData.LineWidth(traceIndex); + + %-line style-% + switch plotData.LineStyle{traceIndex, 1} + case '-' + lineStyle = 'solid'; + case '--' + lineStyle = 'dash'; + case ':' + lineStyle = 'dot'; + case '-.' + lineStyle = 'dashdot'; + end + + lineStruct.dash = lineStyle; +end + +function markerStruct = getMarker(plotData, traceIndex) + + %-INITIALIZATIONS-% + markerStruct = struct(); + + %-marker color-% + [markerColor, ~] = getColor(plotData.Color, traceIndex, ... + plotData.MarkerTransparency); + markerStruct.color = markerColor; + markerStruct.line.color = markerColor; + + %-marker size-% + markerStruct.size = plotData.MarkerSize(traceIndex, 1) * 0.2; + + %-marker symbol-% + if ~strcmp(plotData.Marker{traceIndex, 1}, 'none') + + switch plotData.Marker{traceIndex, 1} + case '.' + mSymbol = 'circle'; + case 'o' + mSymbol = 'circle'; + case 'x' + mSymbol = 'x-thin-open'; + case '+' + mSymbol = 'cross-thin-open'; + case '*' + mSymbol = 'asterisk-open'; + case {'s','square'} + mSymbol = 'square'; + case {'d','diamond'} + mSymbol = 'diamond'; + case 'v' + mSymbol = 'triangle-down'; + case '^' + mSymbol = 'triangle-up'; + case '<' + mSymbol = 'triangle-left'; + case '>' + mSymbol = 'triangle-right'; + case {'p','pentagram'} + mSymbol = 'star'; + case {'h','hexagram'} + mSymbol = 'hexagram'; + end + + markerStruct.symbol = mSymbol; + end +end + +function setAnnotation(obj, axesStruct, spiderIndex) + + %-------------------------------------------------------------------------% + + %-INITIALIZATIONS-% + axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis); + anIndex = obj.PlotlyDefaults.anIndex; + + plotData = obj.State.Plot(spiderIndex).Handle; + [xSource, ySource] = findSourceAxis(obj, axIndex); + + axesLabels = plotData.AxesLabels; + axesLabelsOffset = plotData.AxesLabelsOffset * 0.5; + axesDisplay = plotData.AxesDisplay; + axesLim = plotData.AxesLimits; + axesFontColor = plotData.AxesFontColor; + axesPrecision = plotData.AxesPrecision; + axesLabelsEdge = plotData.AxesLabelsEdge; + + nAxes = axesStruct.nAxes; + axesAngle = axesStruct.axesAngle; + tickValues = axesStruct.axesAngle; + nTicks = axesStruct.nTicks; + if strcmp(axesDisplay, 'data'), nTicks = size(plotData.P, 1); end + + labelColor = 'rgb(0,0,0)'; + labelSize = plotData.LabelFontSize; + labelFamily = matlab2plotlyfont(plotData.LabelFont); + + nAxesFontColor = size(axesFontColor, 1); + axesSize = plotData.AxesFontSize; + axesFamily = matlab2plotlyfont(plotData.AxesFont); + + %-------------------------------------------------------------------------% + + %-set axes labels-% + for l = 1:nAxes + + %-create annotation-% + annotations{anIndex}.showarrow = false; + annotations{anIndex}.xref = sprintf('x%d', xSource); + annotations{anIndex}.yref = sprintf('y%d', ySource); + annotations{anIndex}.bgcolor = 'rgba(0,0,0,0)'; + annotations{anIndex}.bordercolor = getLabelEdgeColor(axesLabelsEdge); + annotations{anIndex}.borderwidth = 1; + annotations{anIndex}.borderpad = labelSize * 0.5; + + %-text label-% + textLabel = axesLabels{l}; + if isempty(textLabel), textLabel = parseString(textLabel, 'tex'); end + + annotations{anIndex}.text = textLabel; + + %-location-% + lastXTick = cos(axesAngle(l)); + lastYTick = sin(axesAngle(l)); + + if abs(lastXTick) < 1e-3 + annotations{anIndex}.x = lastXTick; + annotations{anIndex}.xanchor = 'middle'; + elseif lastXTick > 0 + annotations{anIndex}.x = lastXTick + axesLabelsOffset; + annotations{anIndex}.xanchor = 'left'; + elseif lastXTick < 0 + annotations{anIndex}.x = lastXTick - axesLabelsOffset; + annotations{anIndex}.xanchor = 'right'; + end + + if abs(lastYTick) < 1e-3 + annotations{anIndex}.y = lastYTick; + annotations{anIndex}.yanchor = 'middle'; + elseif lastYTick > 0 + annotations{anIndex}.y = lastYTick + axesLabelsOffset; + annotations{anIndex}.yanchor = 'bottom'; + elseif lastYTick < 0 + annotations{anIndex}.y = lastYTick - axesLabelsOffset; + annotations{anIndex}.yanchor = 'top'; + end + + %-font properties-% + annotations{anIndex}.font.color = labelColor; + annotations{anIndex}.font.size = labelSize; + annotations{anIndex}.font.family = labelFamily; + + %-update annotation Index-% + anIndex = anIndex + 1; + end + + %-------------------------------------------------------------------------% + + %-set axes tick labels-% + for t = 1:nTicks + + indexColor = mod(t-1, nAxesFontColor) + 1; + axesColor = 255*axesFontColor(indexColor, :); + axesColor = sprintf('rgb(%f,%f,%f)', axesColor); + + for a = 1:nAxes + + %-create annotation-% + annotations{anIndex}.showarrow = false; + annotations{anIndex}.xref = sprintf('x%d', xSource); + annotations{anIndex}.yref = sprintf('y%d', ySource); + annotations{anIndex}.bgcolor = 'rgba(0,0,0,0)'; + annotations{anIndex}.bordercolor = 'rgba(0,0,0,0)'; + + %-get tick label-% + try + axesLim = plotData.AxesLimits(:, a)'; + catch + axesLim = [min(plotData.P(:, a)), max(plotData.P(:, a))]; + end + + if strcmp(axesDisplay, 'data') + tickLabel = plotData.P(t, a); + + else + tickLabel = linspace(axesLim(1), axesLim(2), nTicks); + tickLabel = tickLabel(t); + + if strcmpi(plotData.AxesScaling(a), 'log') + tickLabel = 10^(t-1); + end + end + + %-get tick value-% + tickValue = [tickLabel, axesLim]; + + if strcmpi(plotData.AxesScaling(a), 'log') + tickValue = log10(tickValue); + end + + if strcmpi(plotData.AxesDirection(a), 'reverse'); + tickValue = -1 * tickValue; + end + + tickValue = rescale(tickValue, 1/axesStruct.nTicks, 1); + tickValue = tickValue(1); + + %-set tick label-% + tickLabel = num2str(tickLabel, sprintf('%%.%df', axesPrecision(a))); + annotations{anIndex}.text = tickLabel; + + %-set tick location-% + annotations{anIndex}.x = tickValue * cos(axesAngle(a)); + annotations{anIndex}.y = tickValue * sin(axesAngle(a)); + annotations{anIndex}.xanchor = plotData.AxesHorzAlign; + annotations{anIndex}.yanchor = plotData.AxesVertAlign; + annotations{anIndex}.align = plotData.AxesHorzAlign; + + if strcmp(axesDisplay, 'data') + if annotations{anIndex}.y > 0 + annotations{anIndex}.yanchor = 'bottom'; + elseif annotations{anIndex}.y < 0 + annotations{anIndex}.yanchor = 'top'; + end + + if abs(annotations{anIndex}.x) < 1e-3 + annotations{anIndex}.xanchor = 'middle'; + elseif annotations{anIndex}.x > 0 + annotations{anIndex}.xanchor = 'left'; + elseif annotations{anIndex}.x < 0 + annotations{anIndex}.xanchor = 'right'; + end + end + + %-font properties-% + annotations{anIndex}.font.color = axesColor; + annotations{anIndex}.font.size = axesSize; + annotations{anIndex}.font.family = axesFamily; + + %-update annotation Index-% + anIndex = anIndex + 1; + + %-stop according AxesDisplay-% + if strcmp(axesDisplay, 'one') + if a==1, break; end + elseif strcmp(axesDisplay, 'two') + if a==2, break; end + elseif strcmp(axesDisplay, 'three') + if a==3, break; end + end + end + + end + + %-------------------------------------------------------------------------% + + %-set annotations to layout-% + obj.layout = setfield(obj.layout, 'annotations', annotations); + + %-------------------------------------------------------------------------% + + obj.PlotlyDefaults.anIndex = anIndex; + + %-------------------------------------------------------------------------% +end + +function axesStruct = setAxes(obj, spiderIndex) + + %-------------------------------------------------------------------------% + + %-INITIALIZATIONS-% + axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis); + plotData = obj.State.Plot(spiderIndex).Handle; + [xSource, ySource] = findSourceAxis(obj, axIndex); + + %-------------------------------------------------------------------------% + + %-set axes-% + nAxes = size(plotData.P,2); + angleStep = 2*pi/nAxes; + axesAngle = [pi/2]; + plotIndex = spiderIndex; + axesColor = sprintf('rgb(%f,%f,%f)', 255*plotData.AxesColor); + + for a = 1:nAxes + + %-get plotIndex-% + if a > 1 + obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1; + plotIndex = obj.PlotOptions.nPlots; + end + + %-set axes-% + obj.data{plotIndex}.xaxis = sprintf('x%d', xSource); + obj.data{plotIndex}.yaxis = sprintf('y%d', ySource); + + obj.data{plotIndex}.type = 'scatter'; + obj.data{plotIndex}.mode = 'lines'; + obj.data{plotIndex}.line.color = axesColor; + obj.data{plotIndex}.line.width = 1.75; + + obj.data{plotIndex}.x = [0, cos(axesAngle(a))]; + obj.data{plotIndex}.y = [0, sin(axesAngle(a))]; + + %-update axesAngle list-% + if a ~= nAxes + if strcmp(plotData.Direction, 'clockwise') + axesAngle(a+1) = axesAngle(a) - angleStep; + else + axesAngle(a+1) = axesAngle(a) + angleStep; + end + end + + %-hide associated trace-% + obj.data{plotIndex}.showlegend = false; + + end + + %-------------------------------------------------------------------------% + + %-set grid-% + nTicks = plotData.AxesInterval + 1; + tickValues = linspace(1/nTicks, 1, nTicks); + xData = cos([axesAngle, axesAngle(1)]); + yData = sin([axesAngle, axesAngle(1)]); + + for g = 1:nTicks + + %-get plotIndex-% + obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1; + plotIndex = obj.PlotOptions.nPlots; + + %-set current line grid-% + obj.data{plotIndex}.xaxis = sprintf('x%d', xSource); + obj.data{plotIndex}.yaxis = sprintf('y%d', ySource); + + obj.data{plotIndex}.type = 'scatter'; + obj.data{plotIndex}.mode = 'lines'; + obj.data{plotIndex}.line.color = axesColor; + obj.data{plotIndex}.line.width = 0.4; + + obj.data{plotIndex}.x = tickValues(g)*xData; + obj.data{plotIndex}.y = tickValues(g)*yData; + + %-hide associated trace-% + obj.data{plotIndex}.showlegend = false; + + end + + %-------------------------------------------------------------------------% + + %-return-% + axesStruct.axesAngle = axesAngle; + axesStruct.nAxes = nAxes; + axesStruct.nTicks = nTicks; + axesStruct.tickValues = tickValues; + + %-------------------------------------------------------------------------% +end + +function updateSpiderLayout(obj, spiderIndex) + + %-------------------------------------------------------------------------% + + %-INITIALIZATIONS-% + axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis); + plotData = obj.State.Plot(spiderIndex).Handle; + [xSource, ySource] = findSourceAxis(obj, axIndex); + + xo = plotData.Position(1); + yo = plotData.Position(2); + w = plotData.Position(3); + h = plotData.Position(4); + + %-------------------------------------------------------------------------% + + %-get x axis-% + xaxis.domain = min([xo xo + w],1); + xaxis.range = [-1.5, 1.5]; + xaxis.showline = false; + xaxis.zeroline = false; + xaxis.showgrid = false; + xaxis.showticklabels = false; + + %-------------------------------------------------------------------------% + + %-get y axis-% + yaxis.domain = min([yo yo + h],1); + yaxis.range = [-1.25, 1.25]; + yaxis.showline = false; + yaxis.zeroline = false; + yaxis.showgrid = false; + yaxis.showticklabels = false; + + %-------------------------------------------------------------------------% + + %-set axis-% + obj.layout = setfield(obj.layout, sprintf('xaxis%d', xSource), xaxis); + obj.layout = setfield(obj.layout, sprintf('yaxis%d', ySource), yaxis); + + %-------------------------------------------------------------------------% +end + +function setLegeng(obj, spiderIndex) + + %-------------------------------------------------------------------------% + + %-INITIALIZATIONS-% + axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis); + plotData = obj.State.Plot(spiderIndex).Handle; + [xSource, ySource] = findSourceAxis(obj, axIndex); + + legData = plotData.LegendHandle; + obj.layout.showlegend = strcmpi(plotData.Visible,'on'); + + %-------------------------------------------------------------------------% + + %-legend location-% + obj.layout.legend.x = legData.Position(1); + obj.layout.legend.y = legData.Position(2); + obj.layout.legend.xref = 'paper'; + obj.layout.legend.yref = 'paper'; + obj.layout.legend.xanchor = 'left'; + obj.layout.legend.yanchor = 'top'; + + %-------------------------------------------------------------------------% + + %-legend settings-% + if (strcmp(legData.Box,'on') && strcmp(legData.Visible, 'on')) + edgeColor = 255*legData.EdgeColor; + bgColor = 255*legData.Color; + textColor = 255*legData.TextColor; + + obj.layout.legend.traceorder = 'normal'; + obj.layout.legend.borderwidth = legData.LineWidth; + obj.layout.legend.bordercolor = sprintf('rgb(%f,%f,%f)', edgeColor); + obj.layout.legend.bgcolor = sprintf('rgb(%f,%f,%f)', bgColor); + obj.layout.legend.font.size = legData.FontSize; + obj.layout.legend.font.family = matlab2plotlyfont(legData.FontName); + obj.layout.legend.font.color = sprintf('rgb(%f,%f,%f)', textColor); + end +end + +function [strColor, numColor] = getColor(colorMatrix, traceIndex, ... + colorOpacities) + + colorOpacity = 1; + + if nargin > 2 + colorOpacity = colorOpacities(traceIndex); + end + + nColors = size(colorMatrix, 1); + colorIndex = mod(traceIndex-1, nColors) + 1; + numColor = 255*colorMatrix(colorIndex, :); + strColor = sprintf('rgba(%f,%f,%f,%f)', numColor, colorOpacity); +end + +function edgeColor = getLabelEdgeColor(axesLabelsEdge) + if isnumeric(axesLabelsEdge) + edgeColor = sprintf('rgb', 255*axesLabelsEdge); + + elseif strcmp(axesLabelsEdge, 'none') + edgeColor = 'rgba(0,0,0,0)'; + + else + switch axesLabelsEdge + case {'b', 'blue'} + edgeColor = 'rgb(0,0,1)'; + case {'k', 'black'} + edgeColor = 'rgb(0,0,0)'; + case {'r', 'red'} + edgeColor = 'rgb(1,0,0)'; + case {'g', 'green'} + edgeColor = 'rgb(0,1,0)'; + case {'y', 'yellow'} + edgeColor = 'rgb(1,1,0)'; + case {'c', 'cyan'} + edgeColor = 'rgb(0,1,1)'; + case {'m', 'magenta'} + edgeColor = 'rgb(1,0,1)'; + case {'w', 'white'} + edgeColor = 'rgb(1,1,1)'; + end + end +end