From 71fab1a56b9695a91336224d60c0bce5c02aae57 Mon Sep 17 00:00:00 2001 From: ali Date: Thu, 19 Sep 2024 16:47:29 -0700 Subject: [PATCH 1/4] feat: pattern var is now received by user --- .../visualization/barChart/BarChartOpDesc.scala | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/barChart/BarChartOpDesc.scala b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/barChart/BarChartOpDesc.scala index 24eb0966924..cd60d3cbcf7 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/barChart/BarChartOpDesc.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/barChart/BarChartOpDesc.scala @@ -36,6 +36,12 @@ class BarChartOpDesc extends VisualizationOperator with PythonOperatorDescriptor @AutofillAttributeName var fields: String = "" + @JsonProperty(required = false) + @JsonSchemaTitle("Pattern") + @JsonPropertyDescription("Add texture to the chart based on an attribute") + @AutofillAttributeName + var pattern: String = "" + @JsonProperty(defaultValue = "No Selection", required = false) @JsonSchemaTitle("Category Column") @JsonPropertyDescription("Optional - Select a column to Color Code the Categories") @@ -74,6 +80,10 @@ class BarChartOpDesc extends VisualizationOperator with PythonOperatorDescriptor if (horizontalOrientation) isHorizontalOrientation = "True" + var isPatternSelected = "False" + if (pattern != "") + isPatternSelected = "True" + var isCategoryColumn = "False" if (categoryColumn != "No Selection") isCategoryColumn = "True" @@ -102,9 +112,9 @@ class BarChartOpDesc extends VisualizationOperator with PythonOperatorDescriptor | ${manipulateTable()} | if not table.empty and '$fields' != '$value': | if $isHorizontalOrientation: - | fig = go.Figure(px.bar(table, y='$fields', x='$value', color="$categoryColumn" if $isCategoryColumn else None, orientation = 'h')) + | fig = go.Figure(px.bar(table, y='$fields', x='$value', color="$categoryColumn" if $isCategoryColumn else None, pattern_shape="$pattern" if $isPatternSelected else None, orientation = 'h')) | else: - | fig = go.Figure(px.bar(table, y='$value', x='$fields', color="$categoryColumn" if $isCategoryColumn else None)) + | fig = go.Figure(px.bar(table, y='$value', x='$fields', color="$categoryColumn" if $isCategoryColumn else None, pattern_shape="$pattern" if $isPatternSelected else None)) | fig.update_layout(margin=dict(l=0, r=0, t=0, b=0)) | html = plotly.io.to_html(fig, include_plotlyjs = 'cdn', auto_play = False) | # use latest plotly lib in html From 6d79eb2ab63ce3ebcfdf821c49e69154177b6685 Mon Sep 17 00:00:00 2001 From: ali Date: Fri, 20 Sep 2024 15:10:09 -0700 Subject: [PATCH 2/4] feat: pattern var (as string) added to charts --- .../visualization/barChart/BarChartOpDesc.scala | 12 ++++++------ .../filledAreaPlot/FilledAreaPlotOpDesc.scala | 9 ++++++++- .../visualization/ganttChart/GanttChartOpDesc.scala | 9 ++++++++- .../histogram/HistogramChartOpDesc.scala | 10 +++++++++- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/barChart/BarChartOpDesc.scala b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/barChart/BarChartOpDesc.scala index cd60d3cbcf7..e4f76113de9 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/barChart/BarChartOpDesc.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/barChart/BarChartOpDesc.scala @@ -36,12 +36,6 @@ class BarChartOpDesc extends VisualizationOperator with PythonOperatorDescriptor @AutofillAttributeName var fields: String = "" - @JsonProperty(required = false) - @JsonSchemaTitle("Pattern") - @JsonPropertyDescription("Add texture to the chart based on an attribute") - @AutofillAttributeName - var pattern: String = "" - @JsonProperty(defaultValue = "No Selection", required = false) @JsonSchemaTitle("Category Column") @JsonPropertyDescription("Optional - Select a column to Color Code the Categories") @@ -53,6 +47,12 @@ class BarChartOpDesc extends VisualizationOperator with PythonOperatorDescriptor @JsonPropertyDescription("Orientation Style") var horizontalOrientation: Boolean = _ + @JsonProperty(required = false) + @JsonSchemaTitle("Pattern") + @JsonPropertyDescription("Add texture to the chart based on an attribute") + @AutofillAttributeName + var pattern: String = "" + override def getOutputSchema(schemas: Array[Schema]): Schema = { Schema.builder().add(new Attribute("html-content", AttributeType.STRING)).build() } diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala index 3e5ee2523dc..8eeaf200235 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala @@ -43,6 +43,12 @@ class FilledAreaPlotOpDesc extends VisualizationOperator with PythonOperatorDesc @JsonPropertyDescription("Do you want to split the graph") var facetColumn: Boolean = false + @JsonProperty(required = false) + @JsonSchemaTitle("Pattern") + @JsonPropertyDescription("Add texture to the chart based on an attribute") + @AutofillAttributeName + var pattern: String = "" + override def getOutputSchema(schemas: Array[Schema]): Schema = { Schema.builder().add(new Attribute("html-content", AttributeType.STRING)).build() } @@ -67,9 +73,10 @@ class FilledAreaPlotOpDesc extends VisualizationOperator with PythonOperatorDesc val colorArg = if (color.nonEmpty) s""", color="$color"""" else "" val facetColumnArg = if (facetColumn) s""", facet_col="$lineGroup"""" else "" val lineGroupArg = if (lineGroup.nonEmpty) s""", line_group="$lineGroup"""" else "" + val patternParam = if(pattern.nonEmpty) s""", pattern_shape="$pattern"""" else "" s""" - | fig = px.area(table, x="$x", y="$y"$colorArg$facetColumnArg$lineGroupArg) + | fig = px.area(table, x="$x", y="$y"$colorArg$facetColumnArg$lineGroupArg$patternParam) |""".stripMargin } diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala index 0a10312c8bd..09577e70e7a 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala @@ -50,6 +50,12 @@ class GanttChartOpDesc extends VisualizationOperator with PythonOperatorDescript @AutofillAttributeName var color: String = _ + @JsonProperty(required = false) + @JsonSchemaTitle("Pattern") + @JsonPropertyDescription("Add texture to the chart based on an attribute") + @AutofillAttributeName + var pattern: String = "" + override def getOutputSchema(schemas: Array[Schema]): Schema = { Schema.builder().add(new Attribute("html-content", AttributeType.STRING)).build() } @@ -72,9 +78,10 @@ class GanttChartOpDesc extends VisualizationOperator with PythonOperatorDescript def createPlotlyFigure(): String = { val colorSetting = if (color.nonEmpty) s", color='$color'" else "" + val patternParam = if(pattern.nonEmpty) s""", pattern_shape="$pattern"""" else "" s""" - | fig = px.timeline(table, x_start='$start', x_end='$finish', y='$task' $colorSetting) + | fig = px.timeline(table, x_start='$start', x_end='$finish', y='$task' $colorSetting $patternParam) | fig.update_yaxes(autorange='reversed') | fig.update_layout(margin=dict(t=0, b=0, l=0, r=0)) |""".stripMargin diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/histogram/HistogramChartOpDesc.scala b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/histogram/HistogramChartOpDesc.scala index 3dd06f57ad4..d80789dd1cc 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/histogram/HistogramChartOpDesc.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/histogram/HistogramChartOpDesc.scala @@ -36,6 +36,12 @@ class HistogramChartOpDesc extends VisualizationOperator with PythonOperatorDesc @JsonPropertyDescription("Distribution type (rug, box, violin).") var marginal: String = "" + @JsonProperty(required = false) + @JsonSchemaTitle("Pattern") + @JsonPropertyDescription("Add texture to the chart based on an attribute") + @AutofillAttributeName + var pattern: String = "" + override def operatorInfo: OperatorInfo = OperatorInfo( "Histogram Chart", @@ -50,12 +56,14 @@ class HistogramChartOpDesc extends VisualizationOperator with PythonOperatorDesc var colorParam = "" var categoryParam = "" var marginalParam = "" + var patternParam = "" if (color.nonEmpty) colorParam = s", color = '$color'" if (separateBy.nonEmpty) categoryParam = s", facet_col = '$separateBy'" if (marginal.nonEmpty) marginalParam = s", marginal='$marginal'" + if (pattern != "") patternParam = s", pattern_shape='$pattern'" s""" - | fig = px.histogram(table, x = '$value', text_auto = True $colorParam $categoryParam $marginalParam) + | fig = px.histogram(table, x = '$value', text_auto = True $colorParam $categoryParam $marginalParam $patternParam) | fig.update_layout(margin=dict(l=0, r=0, t=0, b=0)) |""".stripMargin } From 669872c8c79e4a758e02d876fcdaa75b43358283 Mon Sep 17 00:00:00 2001 From: ali Date: Fri, 20 Sep 2024 21:52:47 -0700 Subject: [PATCH 3/4] fix: lint --- .../visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala | 2 +- .../operators/visualization/ganttChart/GanttChartOpDesc.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala index 8eeaf200235..dd9d0f8848c 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/filledAreaPlot/FilledAreaPlotOpDesc.scala @@ -73,7 +73,7 @@ class FilledAreaPlotOpDesc extends VisualizationOperator with PythonOperatorDesc val colorArg = if (color.nonEmpty) s""", color="$color"""" else "" val facetColumnArg = if (facetColumn) s""", facet_col="$lineGroup"""" else "" val lineGroupArg = if (lineGroup.nonEmpty) s""", line_group="$lineGroup"""" else "" - val patternParam = if(pattern.nonEmpty) s""", pattern_shape="$pattern"""" else "" + val patternParam = if (pattern.nonEmpty) s""", pattern_shape="$pattern"""" else "" s""" | fig = px.area(table, x="$x", y="$y"$colorArg$facetColumnArg$lineGroupArg$patternParam) diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala index 09577e70e7a..7c4bc3fb425 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala @@ -78,7 +78,7 @@ class GanttChartOpDesc extends VisualizationOperator with PythonOperatorDescript def createPlotlyFigure(): String = { val colorSetting = if (color.nonEmpty) s", color='$color'" else "" - val patternParam = if(pattern.nonEmpty) s""", pattern_shape="$pattern"""" else "" + val patternParam = if (pattern.nonEmpty) s""", pattern_shape="$pattern"""" else "" s""" | fig = px.timeline(table, x_start='$start', x_end='$finish', y='$task' $colorSetting $patternParam) From 96bd3d2eeec707ed02687c1e3f3e13dfcfdb3c4c Mon Sep 17 00:00:00 2001 From: ali Date: Fri, 20 Sep 2024 22:22:32 -0700 Subject: [PATCH 4/4] fix: test case for Gantt chart --- .../ganttChart/GanttChartOpDesc.scala | 2 +- .../ganttChart/GanttChartOpDescSpec.scala | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala index 7c4bc3fb425..cc27f908aaa 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDesc.scala @@ -78,7 +78,7 @@ class GanttChartOpDesc extends VisualizationOperator with PythonOperatorDescript def createPlotlyFigure(): String = { val colorSetting = if (color.nonEmpty) s", color='$color'" else "" - val patternParam = if (pattern.nonEmpty) s""", pattern_shape="$pattern"""" else "" + val patternParam = if (pattern.nonEmpty) s", pattern_shape='$pattern'" else "" s""" | fig = px.timeline(table, x_start='$start', x_end='$finish', y='$task' $colorSetting $patternParam) diff --git a/core/amber/src/test/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDescSpec.scala b/core/amber/src/test/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDescSpec.scala index 035f8e451e8..14337b57710 100644 --- a/core/amber/src/test/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDescSpec.scala +++ b/core/amber/src/test/scala/edu/uci/ics/texera/workflow/operators/visualization/ganttChart/GanttChartOpDescSpec.scala @@ -16,7 +16,7 @@ class GanttChartOpDescSpec extends AnyFlatSpec with BeforeAndAfter { opDesc .createPlotlyFigure() .contains( - "fig = px.timeline(table, x_start='start', x_end='finish', y='task' )" + "fig = px.timeline(table, x_start='start', x_end='finish', y='task' )" ) ) } @@ -30,7 +30,22 @@ class GanttChartOpDescSpec extends AnyFlatSpec with BeforeAndAfter { opDesc .createPlotlyFigure() .contains( - "fig = px.timeline(table, x_start='start', x_end='finish', y='task' , color='color')" + "fig = px.timeline(table, x_start='start', x_end='finish', y='task' , color='color' )" + ) + ) + } + it should "generate a plotly python figure with 3 columns and color and pattern" in { + opDesc.start = "start" + opDesc.finish = "finish" + opDesc.task = "task" + opDesc.color = "color" + opDesc.pattern = "task" + + assert( + opDesc + .createPlotlyFigure() + .contains( + "fig = px.timeline(table, x_start='start', x_end='finish', y='task' , color='color' , pattern_shape='task')" ) ) }