From 49ce2b2242ddb314e7f405f4122d6d7d2c2ef06c Mon Sep 17 00:00:00 2001 From: Gilberto Galvis Date: Thu, 23 Sep 2021 13:29:20 -0400 Subject: [PATCH] add geoscatter functionality in fig2plotly --- plotly/plotly_aux/plotly.m | 2 +- plotly/plotlyfig.m | 2 + plotly/plotlyfig_aux/core/updateAxis.m | 20 ++- plotly/plotlyfig_aux/core/updateData.m | 8 +- .../handlegraphics/UpdateGeoAxes.m | 84 +++++++++ .../handlegraphics/updateGeoScatter.m | 44 +++++ .../plotlyfig_aux/helpers/extractGeoMarker.m | 166 ++++++++++++++++++ 7 files changed, 318 insertions(+), 8 deletions(-) create mode 100644 plotly/plotlyfig_aux/handlegraphics/UpdateGeoAxes.m create mode 100644 plotly/plotlyfig_aux/handlegraphics/updateGeoScatter.m create mode 100644 plotly/plotlyfig_aux/helpers/extractGeoMarker.m diff --git a/plotly/plotly_aux/plotly.m b/plotly/plotly_aux/plotly.m index c8c37bfc..7bdcee12 100644 --- a/plotly/plotly_aux/plotly.m +++ b/plotly/plotly_aux/plotly.m @@ -57,7 +57,7 @@ offline_given = true; end -if offline_given +if ~offline_given obj = plotlyfig(args, structargs); obj.layout.width = 840; obj.layout.height = 630; diff --git a/plotly/plotlyfig.m b/plotly/plotlyfig.m index 48357dc1..daa30b5b 100644 --- a/plotly/plotlyfig.m +++ b/plotly/plotlyfig.m @@ -100,6 +100,7 @@ obj.PlotlyDefaults.CaptionMarginIncreaseFactor = 1.2; obj.PlotlyDefaults.MinCaptionMargin = 80; obj.PlotlyDefaults.IsLight = false; + obj.PlotlyDefaults.isGeoaxis = false; %-State-% obj.State.Figure = []; @@ -1060,6 +1061,7 @@ function delete(obj) || strcmpi(fieldname,'yaxis') || strcmpi(fieldname,'cone')... || strcmpi(fieldname,'legend') || strcmpi(fieldname,'histogram')... || strcmpi(fieldname,'scatter') || strcmpi(fieldname,'line')... + || strcmpi(fieldname,'scattergeo') ... ) fprintf(['\nWhoops! ' exception.message(1:end-1) ' in ' fieldname '\n\n']); end diff --git a/plotly/plotlyfig_aux/core/updateAxis.m b/plotly/plotlyfig_aux/core/updateAxis.m index 1aec4ca6..1dc0ffd0 100644 --- a/plotly/plotlyfig_aux/core/updateAxis.m +++ b/plotly/plotlyfig_aux/core/updateAxis.m @@ -61,20 +61,28 @@ is_headmap_axis = isfield(axis_data, 'XDisplayData'); obj.PlotOptions.is_headmap_axis = is_headmap_axis; +%-------------------------------------------------------------------------% + +%-check if geo-axis-% +isGeoaxis = isfield(axis_data, 'Type') && strcmpi(axis_data.Type, 'geoaxes'); +obj.PlotlyDefaults.isGeoaxis = isGeoaxis; + +%-------------------------------------------------------------------------% + %-xaxis-% -if ~is_headmap_axis - xaxis = extractAxisData(obj,axis_data,'X'); +if is_headmap_axis + xaxis = extractHeatmapAxisData(obj,axis_data, 'X'); else - xaxis = extractHeatmapAxisData(obj,axis_data,'X'); + xaxis = extractAxisData(obj,axis_data, 'X'); end %-------------------------------------------------------------------------% %-yaxis-% -if ~is_headmap_axis - yaxis = extractAxisData(obj,axis_data,'Y'); +if is_headmap_axis + yaxis = extractHeatmapAxisData(obj,axis_data, 'Y'); else - yaxis = extractHeatmapAxisData(obj,axis_data,'Y'); + yaxis = extractAxisData(obj,axis_data, 'Y'); end %-------------------------------------------------------------------------% diff --git a/plotly/plotlyfig_aux/core/updateData.m b/plotly/plotlyfig_aux/core/updateData.m index 4d8e0f0f..194f0c99 100644 --- a/plotly/plotlyfig_aux/core/updateData.m +++ b/plotly/plotlyfig_aux/core/updateData.m @@ -51,6 +51,10 @@ switch lower(obj.State.Plot(dataIndex).Class) + %--GEOAXES SPECIAL CASE--% + case 'geoaxes' + UpdateGeoAxes(obj, dataIndex); + %--CORE PLOT OBJECTS--% case 'scatterhistogram' updateScatterhistogram(obj, dataIndex); @@ -119,7 +123,9 @@ updateQuivergroup(obj, dataIndex); case 'scatter' if strcmpi(obj.State.Axis(dataIndex).Handle.Type, 'polaraxes') - updateScatterPolar(obj, dataIndex); + updateScatterPolar(obj, dataIndex); + elseif obj.PlotlyDefaults.isGeoaxis + updateGeoScatter(obj, dataIndex); else updateScatter(obj, dataIndex); end diff --git a/plotly/plotlyfig_aux/handlegraphics/UpdateGeoAxes.m b/plotly/plotlyfig_aux/handlegraphics/UpdateGeoAxes.m new file mode 100644 index 00000000..a1d6231a --- /dev/null +++ b/plotly/plotlyfig_aux/handlegraphics/UpdateGeoAxes.m @@ -0,0 +1,84 @@ +function UpdateGeoAxes(obj, geoIndex) + + %-AXIS INDEX-% + axIndex = obj.getAxisIndex(obj.State.Plot(geoIndex).AssociatedAxis); + + %-GET DATA STRUCTURE- % + geoData = get(obj.State.Plot(geoIndex).Handle); + + %-CHECK FOR MULTIPLE AXES-% + [xsource, ysource] = findSourceAxis(obj,axIndex); + + %-------------------------------------------------------------------------% + + %-set domain geo plot-% + xo = geoData.Position(1); + yo = geoData.Position(2); + w = geoData.Position(3); + h = geoData.Position(4); + + geo.domain.x = min([xo xo + w],1); + geo.domain.y = min([yo yo + h],1); + + %-------------------------------------------------------------------------% + + %-setting projection-% + geo.projection.type = 'mercator'; + + %-------------------------------------------------------------------------% + + %-setting basemap-% + geo.framecolor = 'rgb(120,120,120)'; + + if strcmpi(geoData.Basemap, 'streets-light') + geo.oceancolor = 'rgba(20,220,220,1)'; + geo.landcolor = 'rgba(20,220,220,0.2)'; + elseif strcmpi(geoData.Basemap, 'colorterrain') + geo.oceancolor = 'rgba(118,165,225,0.6)'; + geo.landcolor = 'rgba(190,180,170,1)'; + geo.showcountries = true; + geo.showlakes = true; + end + + geo.showocean = true; + geo.showcoastlines = false; + geo.showland = true; + + %-------------------------------------------------------------------------% + + %-setting latitude axis + latTick = geoData.LatitudeAxis.TickValues; + + geo.lataxis.range = geoData.LatitudeLimits; + geo.lataxis.tick0 = latTick(1); + geo.lataxis.dtick = mean(diff(latTick)); + + if strcmpi(geoData.Grid, 'on') + geo.lataxis.showgrid = true; + geo.lataxis.gridwidth = geoData.LineWidth; + geo.lataxis.gridcolor = sprintf('rgba(%f,%f,%f,%f)', 255*geoData.GridColor, geoData.GridAlpha); + end + + %-------------------------------------------------------------------------% + + %-setting longitude axis + lonTick = geoData.LongitudeAxis.TickValues; + + geo.lonaxis.range = geoData.LongitudeLimits; + geo.lonaxis.tick0 = lonTick(1); + geo.lonaxis.dtick = mean(diff(lonTick)); + + if strcmpi(geoData.Grid, 'on') + geo.lonaxis.showgrid = true; + geo.lonaxis.gridwidth = geoData.LineWidth; + geo.lonaxis.gridcolor = sprintf('rgba(%f,%f,%f,%f)', 255*geoData.GridColor, geoData.GridAlpha); + end + + %-------------------------------------------------------------------------% + + %-set geo axes to layout-% + + obj.layout = setfield(obj.layout, sprintf('geo%d', xsource+1), geo); + + %-------------------------------------------------------------------------% +end \ No newline at end of file diff --git a/plotly/plotlyfig_aux/handlegraphics/updateGeoScatter.m b/plotly/plotlyfig_aux/handlegraphics/updateGeoScatter.m new file mode 100644 index 00000000..514555de --- /dev/null +++ b/plotly/plotlyfig_aux/handlegraphics/updateGeoScatter.m @@ -0,0 +1,44 @@ +function updateGeoScatter(obj,geoIndex) + + %-AXIS INDEX-% + axIndex = obj.getAxisIndex(obj.State.Plot(geoIndex).AssociatedAxis); + + %-GET STRUCTURES-% + geoData = get(obj.State.Plot(geoIndex).Handle); + axisData = geoData.Parent; + figureData = get(obj.State.Figure.Handle); + + %-CHECK FOR MULTIPLE AXES-% + [xsource, ysource] = findSourceAxis(obj,axIndex); + + %-ASSOCIATE GEO-AXES LAYOUT-% + obj.data{geoIndex}.geo = sprintf('geo%d', xsource+1); + + %-------------------------------------------------------------------------% + + %-set scattergeo type-% + obj.data{geoIndex}.type = 'scattergeo'; + + %-------------------------------------------------------------------------% + + %-set scattergeo mode-% + obj.data{geoIndex}.mode = 'markers'; + + %-------------------------------------------------------------------------% + + %-set plot data-% + obj.data{geoIndex}.lat = geoData.LatitudeData; + obj.data{geoIndex}.lon = geoData.LongitudeData; + + %-------------------------------------------------------------------------% + + %-get marker setting-% + marker = extractGeoMarker(geoData, axisData); + + %-------------------------------------------------------------------------% + + %-set marker field-% + obj.data{geoIndex}.marker = marker; + + %-------------------------------------------------------------------------% +end \ No newline at end of file diff --git a/plotly/plotlyfig_aux/helpers/extractGeoMarker.m b/plotly/plotlyfig_aux/helpers/extractGeoMarker.m new file mode 100644 index 00000000..d1d20f13 --- /dev/null +++ b/plotly/plotlyfig_aux/helpers/extractGeoMarker.m @@ -0,0 +1,166 @@ +function marker = extractGeoMarker(geoData, axisData) + + %-------------------------------------------------------------------------% + + %-FIGURE STRUCTURE-% + figureData = get(ancestor(geoData.Parent,'figure')); + + %-INITIALIZE OUTPUT-% + marker = struct(); + + %-------------------------------------------------------------------------% + + %-MARKER SIZEREF-% + marker.sizeref = 1; + + %-------------------------------------------------------------------------% + + %-MARKER SIZEMODE-% + marker.sizemode = 'area'; + + %-------------------------------------------------------------------------% + + %-MARKER SIZE (STYLE)-% + marker.size = geoData.SizeData; + + %-------------------------------------------------------------------------% + + %-MARKER SYMBOL (STYLE)-% + if ~strcmp(geoData.Marker,'none') + + switch geoData.Marker + 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 = 'star-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 = 2*geoData.LineWidth; + + %-------------------------------------------------------------------------% + + %--MARKER FILL COLOR--% + + % marker face color + faceColor = geoData.MarkerFaceColor; + + filledMarkerSet = {'o','square','s','diamond','d','v','^', '<','>','hexagram','pentagram'}; + filledMarker = ismember(geoData.Marker, filledMarkerSet); + + if filledMarker + + if isnumeric(faceColor) + markerColor = sprintf('rgb(%f,%f,%f)', 255 * faceColor); + + else + + switch faceColor + + case 'none' + + markerColor = 'rgba(0,0,0,0)'; + + case 'auto' + + if ~strcmp(axisData.Color,'none') + col = 255*axisData.Color; + else + col = 255*figureData.Color; + end + + markerColor = sprintf('rgb(%f,%f,%f)', col); + + case 'flat' + + cData = geoData.CData; + cMap = figureData.Colormap; + ncolors = size(cMap, 1); + + for m = 1:length(cData) + colorValue = max( min( cData(m), axisData.CLim(2) ), axisData.CLim(1) ); + scaleFactor = (colorValue - axisData.CLim(1)) / diff(axisData.CLim); + rgbColor = 255 * cMap( 1+floor(scaleFactor*(ncolors-1)), : ); + markerColor{m} = sprintf('rgb(%f,%f,%f)', rgbColor); + end + end + end + + %-set marker color-% + marker.color = markerColor; + + end + + %-------------------------------------------------------------------------% + + %-MARKER LINE COLOR-% + + % marker edge color + edgeColor = geoData.MarkerEdgeColor; + + if isnumeric(edgeColor) + lineColor = sprintf('rgb(%f,%f,%f)', 255 * edgeColor); + + else + switch edgeColor + + case 'none' + + lineColor = 'rgba(0,0,0,0)'; + + case 'auto' + + % TODO + + case 'flat' + + cData = geoData.CData; + cMap = figureData.Colormap; + ncolors = size(cMap, 1); + + for m = 1:length(cData) + colorValue = max( min( cData(m), axisData.CLim(2) ), axisData.CLim(1) ); + scaleFactor = (colorValue - axisData.CLim(1)) / diff(axisData.CLim); + rgbColor = 255 * cMap( 1+floor(scaleFactor*(ncolors-1)), : ); + lineColor{m} = sprintf('rgb(%f,%f,%f)', rgbColor); + end + + end + end + + if filledMarker + marker.line.color = lineColor; + else + marker.color = lineColor; + end + + %-------------------------------------------------------------------------% + +end