Skip to content

Commit

Permalink
Implement delta_color options (#1538)
Browse files Browse the repository at this point in the history
* Implemented positiveDeltaColor and negativeDeltaColor

* Add testings for the delta colors

* Remove default values

* Removed symbols

* Implement invert to delta_color

* Updated deleteDecreasing logic and invert testing function

* Update viselelements.json
  • Loading branch information
Satoshi-Sh committed Jul 19, 2024
1 parent d754750 commit 0ae161a
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 25 deletions.
20 changes: 20 additions & 0 deletions frontend/taipy-gui/src/components/Taipy/Metric.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,26 @@ describe("Metric Component", () => {
});
});

it("applies style correctly when deltaColor is set", async () => {
render(<Metric delta={10} deltaColor="#FF4136" testId="test-id" />);
await waitFor(() => {
const elt = document.querySelector(".delta");
expect(elt).toHaveStyle({
fill: "rgb(255, 65, 54)"
});
});
});

it("applies style correctly when deltaColor is set invert", async () => {
render(<Metric delta={10} deltaColor="invert" testId="test-id" />);
await waitFor(() => {
const elt = document.querySelector(".delta");
expect(elt).toHaveStyle({
fill: "rgb(255, 65, 54)"
});
});
});

it("processes type and threshold props correctly when type is linear", async () => {
render(<Metric type="linear" threshold={50} testId="test-id" />);
await waitFor(() => {
Expand Down
18 changes: 16 additions & 2 deletions frontend/taipy-gui/src/components/Taipy/Metric.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ interface MetricProps extends TaipyBaseProps, TaipyHoverProps {
defaultValue?: number
delta?: number
defaultDelta?: number
deltaColor?: string
negativeDeltaColor?: string
threshold?: number
defaultThreshold?: number
testId?: string
Expand All @@ -58,7 +60,9 @@ const Metric = (props: MetricProps) => {
const {
width = "100%",
height,
showValue = true
showValue = true,
deltaColor,
negativeDeltaColor
} = props;
const value = useDynamicProperty(props.value, props.defaultValue, 0)
const threshold = useDynamicProperty(props.threshold, props.defaultThreshold, undefined)
Expand Down Expand Up @@ -88,6 +92,11 @@ const Metric = (props: MetricProps) => {
const mode = (props.type === "none") ? [] : ["gauge"];
showValue && mode.push("number");
(delta !== undefined) && mode.push("delta");
const deltaIncreasing = deltaColor ? {
color: deltaColor == "invert" ? "#FF4136" : deltaColor } : undefined
const deltaDecreasing = deltaColor == "invert" ? {
color: "#3D9970"
} : negativeDeltaColor ? { color: negativeDeltaColor } : undefined;
return [
{
domain: {x: [0, 1], y: [0, 1]},
Expand All @@ -103,7 +112,10 @@ const Metric = (props: MetricProps) => {
reference: typeof value === 'number' && typeof delta === 'number' ? value - delta : undefined,
prefix: extractPrefix(props.deltaFormat),
suffix: extractSuffix(props.deltaFormat),
valueformat: sprintfToD3Converter(props.deltaFormat)
valueformat: sprintfToD3Converter(props.deltaFormat),
increasing: deltaIncreasing,
decreasing: deltaDecreasing

} as Partial<Delta>,
gauge: {
axis: {
Expand All @@ -130,6 +142,8 @@ const Metric = (props: MetricProps) => {
props.type,
value,
showValue,
deltaColor,
negativeDeltaColor,
delta,
threshold,
colorMap
Expand Down
4 changes: 3 additions & 1 deletion taipy/gui/_renderers/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ class _Factory:
("min", PropertyType.number, 0),
("max", PropertyType.number, 100),
("delta", PropertyType.dynamic_number),
("delta_color", PropertyType.string),
("negative_delta_color", PropertyType.string),
("threshold", PropertyType.dynamic_number),
("width", PropertyType.string_or_number),
("height", PropertyType.string_or_number),
Expand Down Expand Up @@ -594,7 +596,7 @@ class _Factory:
[
("linear", PropertyType.boolean, False),
("show_value", PropertyType.boolean, False),
("render", PropertyType.dynamic_boolean, True)
("render", PropertyType.dynamic_boolean, True),
]
)
._set_propagate(),
Expand Down
11 changes: 11 additions & 0 deletions taipy/gui/viselements.json
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,17 @@
"type": "dynamic(int|float)",
"doc": "The delta value to display."
},
{
"name": "delta_color",
"type": "str",
"doc": "The color that is used to display the value of the <i>delta</i> property. If negative_delta_color is set, then this property applies for positive values of delta only. If this property is set to \"invert\", then delta values are represented with the color used for negative values if delta is positive. The value for delta is also represented with the color used for positive values if delta is negative."
},
{
"name": "negative_delta_color",
"type": "str",
"doc": "If set, this represents the color to be used when the value of <i>delta</i> is negative (or positive if <i>delta_color</i> is set to \"invert\")"

},
{
"name": "threshold",
"type": "dynamic(int|float)",
Expand Down
64 changes: 42 additions & 22 deletions tests/gui/e2e/test_metric_indicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ def test_format_converter_integer_to_binary(page: Page, gui: Gui, helpers):
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "110010"


Expand All @@ -117,8 +116,7 @@ def test_format_converter_integer_to_signed_decimal_d_type(page: Page, gui: Gui,
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "50"


Expand All @@ -132,8 +130,7 @@ def test_format_converter_integer_to_signed_decimal_i_type(page: Page, gui: Gui,
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "50"


Expand All @@ -147,8 +144,7 @@ def test_format_converter_yields_float_using_science_notation(page: Page, gui: G
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "5.000000e+1"


Expand All @@ -162,8 +158,7 @@ def test_format_converter_yields_float_using_fixed_point_notation_f_type(page: P
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "99.99"


Expand All @@ -177,8 +172,7 @@ def test_format_converter_yields_float_using_fixed_point_notation_g_type(page: P
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "51"


Expand All @@ -192,8 +186,7 @@ def test_format_converter_yields_integer_as_octal(page: Page, gui: Gui, helpers)
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "62"


Expand All @@ -207,8 +200,7 @@ def test_format_converter_yields_integer_as_hexadecimal(page: Page, gui: Gui, he
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "32"


Expand All @@ -222,8 +214,7 @@ def test_format_converter_yields_integer_as_uppercase_hexadecimal(page: Page, gu
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "32"


Expand All @@ -237,8 +228,7 @@ def test_format_converter_yields_integer_as_unsigned_decimal(page: Page, gui: Gu
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "(50)"


Expand All @@ -252,9 +242,39 @@ def test_format_converter_yields_edge_cases(page: Page, gui: Gui, helpers):
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
number = page.locator(
"//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
number = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[@class='number']")
assert number.text_content() == "a%b50c%d"


@pytest.mark.teste2e
def test_negative_delta_color(page: Page, gui: Gui, helpers):
page_md = """
<|50|metric|negative_delta_color=#3D9970|delta=-20|>
"""
gui._set_frame(inspect.currentframe())
gui.add_page(name="test", page=page_md)
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
events_list = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[local-name()='text']")
delta = events_list.nth(1)
fill_color = delta.evaluate("el => getComputedStyle(el).fill")

assert fill_color == "rgb(61, 153, 112)"


@pytest.mark.teste2e
def test_delta_color_invert(page: Page, gui: Gui, helpers):
page_md = """
<|50|metric|delta_color=invert|delta=-20|>
"""
gui._set_frame(inspect.currentframe())
gui.add_page(name="test", page=page_md)
helpers.run_e2e(gui)
page.goto("./test")
page.wait_for_selector(".plot-container")
events_list = page.locator("//*[@class='js-plotly-plot']//*[name()='svg'][2]//*[local-name()='text']")
delta = events_list.nth(1)
fill_color = delta.evaluate("el => getComputedStyle(el).fill")

assert fill_color == "rgb(61, 153, 112)"

0 comments on commit 0ae161a

Please sign in to comment.