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..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 @@ -47,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() } @@ -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 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..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 @@ -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..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 @@ -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 } 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')" ) ) }