Quellcode durchsuchen

Merge pull request #1645 from Avaiga/1644-metric-control-add-the-bar_color-property

metric control: Add the bar_color property
Nam Nguyen vor 9 Monaten
Ursprung
Commit
9e1c47a3ad

+ 1 - 1
doc/gui/examples/controls/chat-discuss.py

@@ -24,7 +24,7 @@ from taipy.gui import Gui, Icon
 from taipy.gui.gui_actions import navigate, notify
 from taipy.gui.gui_actions import navigate, notify
 
 
 username = ""
 username = ""
-users: list[str|Icon] = []
+users: list[str | Icon] = []
 messages: list[tuple[str, str, str]] = []
 messages: list[tuple[str, str, str]] = []
 
 
 Gui.add_shared_variables("messages", "users")
 Gui.add_shared_variables("messages", "users")

+ 28 - 0
doc/gui/examples/controls/metric-delta-color.py

@@ -0,0 +1,28 @@
+# Copyright 2021-2024 Avaiga Private Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+# -----------------------------------------------------------------------------------------
+# To execute this script, make sure that the taipy-gui package is installed in your
+# Python environment and run:
+#     python <script>
+# -----------------------------------------------------------------------------------------
+from taipy.gui import Gui
+
+# Source: https://gml.noaa.gov/ccgg/trends/gl_gr.html
+# Estimated Global Trend on january 1st:
+co2_2014 = 396.37
+co2_2024 = 421.13
+delta = co2_2024 - co2_2014
+
+page = """
+<|{co2_2024}|metric|delta={delta}|delta_color=invert|format=%.1f ppm|delta_format=%.1f ppm|min=300|max=500|>
+"""
+
+Gui(page).run()

+ 3 - 6
doc/gui/examples/controls/metric-value-format.py → doc/gui/examples/controls/metric-formats.py

@@ -15,14 +15,11 @@
 # -----------------------------------------------------------------------------------------
 # -----------------------------------------------------------------------------------------
 from taipy.gui import Gui
 from taipy.gui import Gui
 
 
-value = 50
-delta_value = 20
-
-# format & delta_format are used to format the value and delta value respectively.
-# They use the printf syntax.
+speed = 60
+variation = 15
 
 
 page = """
 page = """
-<|{value}|metric|delta={delta_value}|format=%d km/h|delta_format=%d km/h|>
+<|{speed}|metric|format=%d km/h|delta={variation}|delta_format=%d %%|>
 """
 """
 
 
 
 

+ 5 - 13
doc/gui/examples/controls/metric-layout.py

@@ -15,22 +15,14 @@
 # -----------------------------------------------------------------------------------------
 # -----------------------------------------------------------------------------------------
 from taipy.gui import Gui
 from taipy.gui import Gui
 
 
-# Layout reference can be found in the documentation: https://plotly.com/python/reference/layout/
-
 value = 50
 value = 50
+# The layout object reference can be found in Plotly's documentation:
+#         https://plotly.com/python/reference/layout/
 layout = {
 layout = {
-    "width": "1000",
-    "height": "500",
-    "paper_bgcolor": "lightgray",
-    "margin": {
-        "l": 100,
-        "r": 100,
-        "b": 100,
-        "t": 100,
-    },
+    "paper_bgcolor": "lightblue",
     "font": {
     "font": {
-        "size": 20,
-        "color": "black",
+        "size": 30,
+        "color": "blue",
         "family": "Arial",
         "family": "Arial",
     },
     },
 }
 }

+ 2 - 4
doc/gui/examples/controls/metric-range.py

@@ -15,12 +15,10 @@
 # -----------------------------------------------------------------------------------------
 # -----------------------------------------------------------------------------------------
 from taipy.gui import Gui
 from taipy.gui import Gui
 
 
-value = 50
-min_value = 50
-max_value = 150
+value = 120
 
 
 page = """
 page = """
-<|{value}|metric|min={min_value}|max={max_value}|>
+<|{value}|metric|min=50|max=150|>
 """
 """
 
 
 
 

+ 4 - 3
doc/gui/examples/controls/metric-type.py

@@ -15,11 +15,12 @@
 # -----------------------------------------------------------------------------------------
 # -----------------------------------------------------------------------------------------
 from taipy.gui import Gui
 from taipy.gui import Gui
 
 
-value = 50
+value = 72
+delta = 15
+threshold = 60
 
 
 page = """
 page = """
-<|{value}|metric|type=linear|>
-<|{value}|metric|type=circular|>
+<|{value}|metric|threshold={threshold}|type=linear|>
 """
 """
 
 
 Gui(page).run()
 Gui(page).run()

+ 0 - 1
doc/gui/examples/controls/number-min-max.py

@@ -22,4 +22,3 @@ page = """
 """
 """
 
 
 Gui(page).run()
 Gui(page).run()
-

+ 0 - 1
doc/gui/examples/controls/number-step.py

@@ -22,4 +22,3 @@ page = """
 """
 """
 
 
 Gui(page).run()
 Gui(page).run()
-

+ 4 - 4
doc/gui/examples/controls/table-formatting.py

@@ -25,10 +25,10 @@ stock = {
 }
 }
 
 
 columns = {
 columns = {
-    "date" : {"title": "Data", "format": "MMM d"},
-    "price" : {"title": "Price", "format": "$%.02f"},
-    "change" : {"title": "% change", "format": "%.01f"},
-    "volume" : {"title": "Volume"}
+    "date": {"title": "Data", "format": "MMM d"},
+    "price": {"title": "Price", "format": "$%.02f"},
+    "change": {"title": "% change", "format": "%.01f"},
+    "volume": {"title": "Volume"},
 }
 }
 
 
 page = """
 page = """

+ 1 - 1
doc/gui/examples/controls/text-md.py

@@ -23,7 +23,7 @@ add style to the text.
 
 
 If a line ends with two white spaces, such as here
 If a line ends with two white spaces, such as here
 then you can create line skips.
 then you can create line skips.
-""" # noqa W291
+"""  # noqa W291
 
 
 page = """
 page = """
 <|{markdown}|text|mode=markdown|>
 <|{markdown}|text|mode=markdown|>

+ 87 - 92
frontend/taipy-gui/src/components/Taipy/Metric.tsx

@@ -11,62 +11,57 @@
  * specific language governing permissions and limitations under the License.
  * specific language governing permissions and limitations under the License.
  */
  */
 
 
-import React, {CSSProperties, lazy, Suspense, useMemo} from 'react';
-import {Data, Delta, Layout} from "plotly.js";
+import React, { CSSProperties, lazy, Suspense, useMemo } from "react";
+import { Data, Delta, Layout } from "plotly.js";
 import Box from "@mui/material/Box";
 import Box from "@mui/material/Box";
 import Skeleton from "@mui/material/Skeleton";
 import Skeleton from "@mui/material/Skeleton";
 import Tooltip from "@mui/material/Tooltip";
 import Tooltip from "@mui/material/Tooltip";
-import {useTheme} from "@mui/material";
-import {useClassNames, useDynamicJsonProperty, useDynamicProperty} from "../../utils/hooks";
-import {extractPrefix, extractSuffix, sprintfToD3Converter} from "../../utils/formatConversion";
-import {TaipyBaseProps, TaipyHoverProps} from "./utils";
-import {darkThemeTemplate} from "../../themes/darkThemeTemplate";
+import { useTheme } from "@mui/material";
+import { useClassNames, useDynamicJsonProperty, useDynamicProperty } from "../../utils/hooks";
+import { extractPrefix, extractSuffix, sprintfToD3Converter } from "../../utils/formatConversion";
+import { TaipyBaseProps, TaipyHoverProps } from "./utils";
+import { darkThemeTemplate } from "../../themes/darkThemeTemplate";
 
 
 const Plot = lazy(() => import("react-plotly.js"));
 const Plot = lazy(() => import("react-plotly.js"));
 
 
 interface MetricProps extends TaipyBaseProps, TaipyHoverProps {
 interface MetricProps extends TaipyBaseProps, TaipyHoverProps {
-    title?: string
-    type?: string
-    min?: number
-    max?: number
-    value?: number
-    defaultValue?: number
-    delta?: number
-    defaultDelta?: number
-    deltaColor?: string
-    negativeDeltaColor?: string
-    threshold?: number
-    defaultThreshold?: number
-    testId?: string
-    defaultLayout?: string;
+    value?: number;
+    defaultValue?: number;
+    delta?: number;
+    defaultDelta?: number;
+    type?: string;
+    min?: number;
+    max?: number;
+    deltaColor?: string;
+    negativeDeltaColor?: string;
+    threshold?: number;
+    defaultThreshold?: number;
+    format?: string;
+    deltaFormat?: string;
+    barColor?: string;
+    showValue?: boolean;
+    colorMap?: string;
+    title?: string;
+    testId?: string;
     layout?: string;
     layout?: string;
-    defaultStyle?: string;
+    defaultLayout?: string;
     style?: string;
     style?: string;
+    defaultStyle?: string;
     width?: string | number;
     width?: string | number;
     height?: string | number;
     height?: string | number;
-    showValue?: boolean;
-    format?: string;
-    deltaFormat?: string;
-    colorMap?: string;
     template?: string;
     template?: string;
     template_Dark_?: string;
     template_Dark_?: string;
     template_Light_?: string;
     template_Light_?: string;
 }
 }
 
 
 const emptyLayout = {} as Partial<Layout>;
 const emptyLayout = {} as Partial<Layout>;
-const defaultStyle = {position: "relative", display: "inline-block"};
+const defaultStyle = { position: "relative", display: "inline-block" };
 
 
 const Metric = (props: MetricProps) => {
 const Metric = (props: MetricProps) => {
-    const {
-        width = "100%",
-        height,
-        showValue = true,
-        deltaColor,
-        negativeDeltaColor
-    } = props;
-    const value = useDynamicProperty(props.value, props.defaultValue, 0)
-    const threshold = useDynamicProperty(props.threshold, props.defaultThreshold, undefined)
-    const delta = useDynamicProperty(props.delta, props.defaultDelta, undefined)
+    const { width = "100%", height, showValue = true, deltaColor, negativeDeltaColor } = props;
+    const value = useDynamicProperty(props.value, props.defaultValue, 0);
+    const threshold = useDynamicProperty(props.threshold, props.defaultThreshold, undefined);
+    const delta = useDynamicProperty(props.delta, props.defaultDelta, undefined);
     const className = useClassNames(props.libClassName, props.dynamicClassName, props.className);
     const className = useClassNames(props.libClassName, props.dynamicClassName, props.className);
     const baseLayout = useDynamicJsonProperty(props.layout, props.defaultLayout || "", emptyLayout);
     const baseLayout = useDynamicJsonProperty(props.layout, props.defaultLayout || "", emptyLayout);
     const hover = useDynamicProperty(props.hoverText, props.defaultHoverText, undefined);
     const hover = useDynamicProperty(props.hoverText, props.defaultHoverText, undefined);
@@ -75,31 +70,42 @@ const Metric = (props: MetricProps) => {
     const colorMap = useMemo(() => {
     const colorMap = useMemo(() => {
         try {
         try {
             const obj = props.colorMap ? JSON.parse(props.colorMap) : null;
             const obj = props.colorMap ? JSON.parse(props.colorMap) : null;
-            if (obj && typeof obj === 'object') {
+            if (obj && typeof obj === "object") {
                 const keys = Object.keys(obj);
                 const keys = Object.keys(obj);
-                return keys.sort((a, b) => Number(a) - Number(b)).map((key, index) => {
-                    const nextKey = keys[index + 1] !== undefined ? Number(keys[index + 1]) : props.max || 100;
-                    return {range: [Number(key), nextKey], color: obj[key]};
-                }).filter(item => item.color !== null)
+                return keys
+                    .sort((a, b) => Number(a) - Number(b))
+                    .map((key, index) => {
+                        const nextKey = keys[index + 1] !== undefined ? Number(keys[index + 1]) : props.max || 100;
+                        return { range: [Number(key), nextKey], color: obj[key] };
+                    })
+                    .filter((item) => item.color !== null);
             }
             }
         } catch (e) {
         } catch (e) {
             console.info(`Error parsing color_map value (metric).\n${(e as Error).message || e}`);
             console.info(`Error parsing color_map value (metric).\n${(e as Error).message || e}`);
         }
         }
         return undefined;
         return undefined;
-    }, [props.colorMap, props.max])
+    }, [props.colorMap, props.max]);
 
 
     const data = useMemo(() => {
     const data = useMemo(() => {
-        const mode = (props.type === "none") ? [] : ["gauge"];
+        const mode = props.type === "none" ? [] : ["gauge"];
         showValue && mode.push("number");
         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;
+        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 [
         return [
             {
             {
-                domain: {x: [0, 1], y: [0, 1]},
+                domain: { x: [0, 1], y: [0, 1] },
                 value: value,
                 value: value,
                 type: "indicator",
                 type: "indicator",
                 mode: mode.join("+"),
                 mode: mode.join("+"),
@@ -109,58 +115,58 @@ const Metric = (props: MetricProps) => {
                     valueformat: sprintfToD3Converter(props.format),
                     valueformat: sprintfToD3Converter(props.format),
                 },
                 },
                 delta: {
                 delta: {
-                    reference: typeof value === 'number' && typeof delta === 'number' ? value - delta : undefined,
+                    reference: typeof value === "number" && typeof delta === "number" ? value - delta : undefined,
                     prefix: extractPrefix(props.deltaFormat),
                     prefix: extractPrefix(props.deltaFormat),
                     suffix: extractSuffix(props.deltaFormat),
                     suffix: extractSuffix(props.deltaFormat),
                     valueformat: sprintfToD3Converter(props.deltaFormat),
                     valueformat: sprintfToD3Converter(props.deltaFormat),
                     increasing: deltaIncreasing,
                     increasing: deltaIncreasing,
-                    decreasing: deltaDecreasing
-
+                    decreasing: deltaDecreasing,
                 } as Partial<Delta>,
                 } as Partial<Delta>,
                 gauge: {
                 gauge: {
                     axis: {
                     axis: {
-                        range: [
-                            props.min || 0,
-                            props.max || 100
-                        ]
+                        range: [props.min || 0, props.max || 100],
+                    },
+                    bar: {
+                        color: props.barColor,
                     },
                     },
                     steps: colorMap,
                     steps: colorMap,
                     shape: props.type === "linear" ? "bullet" : "angular",
                     shape: props.type === "linear" ? "bullet" : "angular",
                     threshold: {
                     threshold: {
-                        line: {color: "red", width: 4},
+                        line: { color: "red", width: 4 },
                         thickness: 0.75,
                         thickness: 0.75,
-                        value: threshold
-                    }
+                        value: threshold,
+                    },
                 },
                 },
-            }
+            },
         ] as Data[];
         ] as Data[];
     }, [
     }, [
-        props.format,
-        props.deltaFormat,
+        value,
+        delta,
+        props.type,
         props.min,
         props.min,
         props.max,
         props.max,
-        props.type,
-        value,
-        showValue,
         deltaColor,
         deltaColor,
         negativeDeltaColor,
         negativeDeltaColor,
-        delta,
         threshold,
         threshold,
-        colorMap
+        props.format,
+        props.deltaFormat,
+        props.barColor,
+        showValue,
+        colorMap,
     ]);
     ]);
 
 
     const style = useMemo(
     const style = useMemo(
         () =>
         () =>
             height === undefined
             height === undefined
-                ? ({...defaultStyle, width: width} as CSSProperties)
-                : ({...defaultStyle, width: width, height: height} as CSSProperties),
+                ? ({ ...defaultStyle, width: width } as CSSProperties)
+                : ({ ...defaultStyle, width: width, height: height } as CSSProperties),
         [height, width]
         [height, width]
     );
     );
 
 
-    const skelStyle = useMemo(() => ({...style, minHeight: "7em"}), [style]);
+    const skelStyle = useMemo(() => ({ ...style, minHeight: "7em" }), [style]);
 
 
     const layout = useMemo(() => {
     const layout = useMemo(() => {
-        const layout = {...baseLayout};
+        const layout = { ...baseLayout };
         let template = undefined;
         let template = undefined;
         try {
         try {
             const tpl = props.template && JSON.parse(props.template);
             const tpl = props.template && JSON.parse(props.template);
@@ -170,7 +176,7 @@ const Metric = (props: MetricProps) => {
                         ? JSON.parse(props.template_Dark_)
                         ? JSON.parse(props.template_Dark_)
                         : darkTemplate
                         : darkTemplate
                     : props.template_Light_ && JSON.parse(props.template_Light_);
                     : props.template_Light_ && JSON.parse(props.template_Light_);
-            template = tpl ? (tplTheme ? {...tpl, ...tplTheme} : tpl) : tplTheme ? tplTheme : undefined;
+            template = tpl ? (tplTheme ? { ...tpl, ...tplTheme } : tpl) : tplTheme ? tplTheme : undefined;
         } catch (e) {
         } catch (e) {
             console.info(`Error while parsing Metric.template\n${(e as Error).message || e}`);
             console.info(`Error while parsing Metric.template\n${(e as Error).message || e}`);
         }
         }
@@ -183,34 +189,23 @@ const Metric = (props: MetricProps) => {
         }
         }
 
 
         return layout as Partial<Layout>;
         return layout as Partial<Layout>;
-    }, [
-        props.title,
-        props.template,
-        props.template_Dark_,
-        props.template_Light_,
-        theme.palette.mode,
-        baseLayout,
-    ])
+    }, [props.title, props.template, props.template_Dark_, props.template_Light_, theme.palette.mode, baseLayout]);
 
 
+    const plotConfig = {displaylogo: false}
     return (
     return (
         <Tooltip title={hover || ""}>
         <Tooltip title={hover || ""}>
             <Box data-testid={props.testId} className={className}>
             <Box data-testid={props.testId} className={className}>
-                <Suspense fallback={<Skeleton key="skeleton" sx={skelStyle}/>}>
-                    <Plot
-                        data={data}
-                        layout={layout}
-                        style={style}
-                        useResizeHandler
-                    />
+                <Suspense fallback={<Skeleton key="skeleton" sx={skelStyle} />}>
+                    <Plot data={data} layout={layout} style={style} config={plotConfig} useResizeHandler />
                 </Suspense>
                 </Suspense>
             </Box>
             </Box>
         </Tooltip>
         </Tooltip>
     );
     );
-}
+};
 
 
 export default Metric;
 export default Metric;
 
 
-const {colorscale, colorway, font} = darkThemeTemplate.layout;
+const { colorscale, colorway, font } = darkThemeTemplate.layout;
 const darkTemplate = {
 const darkTemplate = {
     layout: {
     layout: {
         colorscale,
         colorscale,
@@ -218,4 +213,4 @@ const darkTemplate = {
         font,
         font,
         paper_bgcolor: "rgb(31,47,68)",
         paper_bgcolor: "rgb(31,47,68)",
     },
     },
-}
+};

+ 1 - 0
taipy/gui/_renderers/factory.py

@@ -361,6 +361,7 @@ class _Factory:
                 ("show_value", PropertyType.boolean, True),
                 ("show_value", PropertyType.boolean, True),
                 ("format", PropertyType.string),
                 ("format", PropertyType.string),
                 ("delta_format", PropertyType.string),
                 ("delta_format", PropertyType.string),
+                ("bar_color", PropertyType.string),
                 ("color_map", PropertyType.dict),
                 ("color_map", PropertyType.dict),
                 ("hover_text", PropertyType.dynamic_string),
                 ("hover_text", PropertyType.dynamic_string),
                 ("template", PropertyType.dict),
                 ("template", PropertyType.dict),

+ 1 - 1
taipy/gui/server.py

@@ -291,7 +291,7 @@ class _Server:
             runtime_manager.add_gui(self._gui, port)
             runtime_manager.add_gui(self._gui, port)
         if debug and not is_running_from_reloader() and _is_port_open(host_value, port):
         if debug and not is_running_from_reloader() and _is_port_open(host_value, port):
             raise ConnectionError(
             raise ConnectionError(
-                "Port {port} is already opened on {host} because another application is running on the same port. Please pick another port number and rerun with the 'port=<new_port>' option. You can also let Taipy choose a port number for you by running with the 'port=\"auto\"' option."  # noqa: E501
+                f"Port {port} is already opened on {host} because another application is running on the same port.\nPlease pick another port number and rerun with the 'port=<new_port>' setting.\nYou can also let Taipy choose a port number for you by running with the 'port=\"auto\"' setting."  # noqa: E501
             )
             )
         if not flask_log:
         if not flask_log:
             log = logging.getLogger("werkzeug")
             log = logging.getLogger("werkzeug")

+ 29 - 20
taipy/gui/viselements.json

@@ -51,7 +51,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of a function that is triggered when the button is pressed.<br/>The parameters of that function are all optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (optional[str]): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "doc": "The name of a function that is triggered when the button is pressed.<br/>The parameters of that function are all optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -501,7 +501,7 @@
                     {
                     {
                         "name": "on_range_change",
                         "name": "on_range_change",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The callback function that is invoked when the visible part of the x axis changes.<br/>The function receives three parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (optional[str]): the identifier of the chart control.</li>\n<li>payload (dict[str, any]): the full details on this callback's invocation, as emitted by <a href=\"https://plotly.com/javascript/plotlyjs-events/#update-data\">Plotly</a>.</li>\n</ul>",
+                        "doc": "The callback function that is invoked when the visible part of the x axis changes.<br/>The function receives three parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the chart control.</li>\n<li>payload (dict[str, any]): the full details on this callback's invocation, as emitted by <a href=\"https://plotly.com/javascript/plotlyjs-events/#update-data\">Plotly</a>.</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -988,7 +988,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of a function that is triggered when the download is terminated (or on user action if <i>content</i> is None).<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (optional[str]): the identifier of the button.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has two keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: A list of two elements: <i>args[0]</i> reflects the <i>name</i> property and <i>args[1]</i> holds the file URL.</li>\n</ul>\n</li>\n</ul>",
+                        "doc": "The name of a function that is triggered when the download is terminated (or on user action if <i>content</i> is None).<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has two keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: A list of two elements: <i>args[0]</i> reflects the <i>name</i> property and <i>args[1]</i> holds the file URL.</li>\n</ul>\n</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1052,7 +1052,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of the function that will be triggered.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (optional[str]): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "doc": "The name of the function that will be triggered.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1117,7 +1117,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of a function that is triggered when the user clicks on the image.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (optional[str]): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "doc": "The name of a function that is triggered when the user clicks on the image.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1158,31 +1158,25 @@
                         "name": "value",
                         "name": "value",
                         "default_property": true,
                         "default_property": true,
                         "type": "dynamic(int|float)",
                         "type": "dynamic(int|float)",
-                        "doc": "The value to display."
+                        "doc": "The value to represent."
                     },
                     },
                     {
                     {
                         "name": "type",
                         "name": "type",
                         "default_value": "\"circular\"",
                         "default_value": "\"circular\"",
                         "type": "str",
                         "type": "str",
-                        "doc": "The type of the gauge.<br/>Possible values are:\n<ul>\n<li>\"none\"</li>\n<li>\"circular\"</li>\n<li>\"linear\"</li></ul>."
-                    },
-                    {
-                        "name": "title",
-                        "default_value": "None",
-                        "type": "str",
-                        "doc": "The title of the metric."
+                        "doc": "The type of the gauge.<br/>Possible values are:\n<ul>\n<li>\"none\"</li>\n<li>\"circular\"</li>\n<li>\"linear\"</li></ul>Setting this value to \"none\" remove the gauge."
                     },
                     },
                     {
                     {
                         "name": "min",
                         "name": "min",
                         "type": "int|float",
                         "type": "int|float",
                         "default_value": "0",
                         "default_value": "0",
-                        "doc": "The minimum value of this metric control."
+                        "doc": "The minimum value of this metric control's gauge."
                     },
                     },
                     {
                     {
                         "name": "max",
                         "name": "max",
                         "type": "int|float",
                         "type": "int|float",
                         "default_value": "100",
                         "default_value": "100",
-                        "doc": "The maximum value of this metric control."
+                        "doc": "The maximum value of this metric control's gauge."
                     },
                     },
                     {
                     {
                         "name": "delta",
                         "name": "delta",
@@ -1192,13 +1186,18 @@
                     {
                     {
                         "name": "delta_color",
                         "name": "delta_color",
                         "type": "str",
                         "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."
+                        "doc": "The color that is used to display the value of the <i>delta</i> property.<br/>If <i>negative_delta_color</i> is set, then this property applies for positive values of <i>delta</i> only.<br/>If this property is set to \"invert\", then values for <i>delta</i> are represented with the color used for negative values if delta is positive and <i>delta</i> is represented with the color used for positive values if it is negative."
+                    },
+                    {
+                        "name": "title",
+                        "default_value": "None",
+                        "type": "str",
+                        "doc": "The title of the metric."
                     },
                     },
                     {
                     {
                         "name": "negative_delta_color",
                         "name": "negative_delta_color",
                         "type": "str",
                         "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\")"
-
+                        "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",
                         "name": "threshold",
@@ -1221,10 +1220,15 @@
                         "type": "str",
                         "type": "str",
                         "doc": "The format to use when displaying the delta value.<br/>This uses the <code>printf</code> syntax."
                         "doc": "The format to use when displaying the delta value.<br/>This uses the <code>printf</code> syntax."
                     },
                     },
+                    {
+                        "name": "bar_color",
+                        "type": "str",
+                        "doc": "The color of the bar in the gauge."
+                    },
                     {
                     {
                         "name": "color_map",
                         "name": "color_map",
                         "type": "dict",
                         "type": "dict",
-                        "doc": "TODO The color_map is used to display different colors for different ranges of the metric. The color_map's keys represent the starting point of each range, which is a number, while the values represent the corresponding color for that range. If the value associated with a key is set to None, it implies that the corresponding range is not assigned any color."
+                        "doc": "Indicates what colors should be used for different ranges of the metric. The <i>color_map</i>'s keys represent the lower bound of each range, which is a number, while the values represent the color for that range.<br/>If the value associated with a key is set to None, the corresponding range is not assigned any color."
                     },
                     },
                     {
                     {
                         "name": "width",
                         "name": "width",
@@ -1238,6 +1242,11 @@
                         "default_value": "None",
                         "default_value": "None",
                         "doc": "The height of the metric control, in CSS units."
                         "doc": "The height of the metric control, in CSS units."
                     },
                     },
+                    {
+                        "name": "layout",
+                        "type": "dynamic(dict[str, any])",
+                        "doc": "The <i>plotly.js</i> compatible <a href=\"https://plotly.com/javascript/reference/layout/\">layout object</a>."
+                    },
                     {
                     {
                         "name": "template",
                         "name": "template",
                         "type": "dict",
                         "type": "dict",
@@ -1767,7 +1776,7 @@
                     {
                     {
                         "name": "on_close",
                         "name": "on_close",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of a function that is triggered when this pane is closed (if the user clicks outside of it or presses the Esc key).<br/>All parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (optional[str]): the identifier of the button.</li>\n</ul><br/>If this property is not set, no function is called when this pane is closed.",
+                        "doc": "The name of a function that is triggered when this pane is closed (if the user clicks outside of it or presses the Esc key).<br/>All parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n</ul><br/>If this property is not set, no function is called when this pane is closed.",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",

+ 3 - 3
tests/gui/builder/control/test_chat.py

@@ -35,7 +35,7 @@ def test_chat_builder_1(gui: Gui, test_client, helpers):
         "<Chat",
         "<Chat",
         'defaultUsers="[[&quot;Fred&quot;, &#x7B;&quot;path&quot;: &quot;/images/favicon.png&quot;, &quot;text&quot;: &quot;Fred.png&quot;&#x7D;], [&quot;Fredi&quot;, &#x7B;&quot;path&quot;: &quot;/images/fred.png&quot;, &quot;text&quot;: &quot;Fred.png&quot;&#x7D;]]"',  # noqa: E501
         'defaultUsers="[[&quot;Fred&quot;, &#x7B;&quot;path&quot;: &quot;/images/favicon.png&quot;, &quot;text&quot;: &quot;Fred.png&quot;&#x7D;], [&quot;Fredi&quot;, &#x7B;&quot;path&quot;: &quot;/images/fred.png&quot;, &quot;text&quot;: &quot;Fred.png&quot;&#x7D;]]"',  # noqa: E501
         "messages={_TpD_tpec_TpExPr_messages_TPMDL_0}",
         "messages={_TpD_tpec_TpExPr_messages_TPMDL_0}",
-        "updateVarName=\"_TpD_tpec_TpExPr_messages_TPMDL_0\""
+        'updateVarName="_TpD_tpec_TpExPr_messages_TPMDL_0"',
     ]
     ]
     helpers.test_control_builder(gui, page, expected_list)
     helpers.test_control_builder(gui, page, expected_list)
 
 
@@ -61,8 +61,8 @@ def test_chat_builder_2(gui: Gui, test_client, helpers):
         "<Chat",
         "<Chat",
         'defaultUsers="[[&quot;Fred&quot;, &#x7B;&quot;path&quot;: &quot;/images/favicon.png&quot;, &quot;text&quot;: &quot;Fred.png&quot;&#x7D;], [&quot;Fredi&quot;, &#x7B;&quot;path&quot;: &quot;/images/fred.png&quot;, &quot;text&quot;: &quot;Fred.png&quot;&#x7D;]]"',  # noqa: E501
         'defaultUsers="[[&quot;Fred&quot;, &#x7B;&quot;path&quot;: &quot;/images/favicon.png&quot;, &quot;text&quot;: &quot;Fred.png&quot;&#x7D;], [&quot;Fredi&quot;, &#x7B;&quot;path&quot;: &quot;/images/fred.png&quot;, &quot;text&quot;: &quot;Fred.png&quot;&#x7D;]]"',  # noqa: E501
         "messages={_TpD_tpec_TpExPr_messages_TPMDL_0}",
         "messages={_TpD_tpec_TpExPr_messages_TPMDL_0}",
-        "updateVarName=\"_TpD_tpec_TpExPr_messages_TPMDL_0\"",
+        'updateVarName="_TpD_tpec_TpExPr_messages_TPMDL_0"',
         "users={_TpL_tp_TpExPr_gui_get_adapted_lov_users_list_TPMDL_0_0}",
         "users={_TpL_tp_TpExPr_gui_get_adapted_lov_users_list_TPMDL_0_0}",
-        "updateVars=\"users=_TpL_tp_TpExPr_gui_get_adapted_lov_users_list_TPMDL_0_0\""
+        'updateVars="users=_TpL_tp_TpExPr_gui_get_adapted_lov_users_list_TPMDL_0_0"',
     ]
     ]
     helpers.test_control_builder(gui, page, expected_list)
     helpers.test_control_builder(gui, page, expected_list)

+ 1 - 1
tests/gui/builder/control/test_progress.py

@@ -16,5 +16,5 @@ from taipy.gui import Gui
 def test_progress_builder(gui: Gui, helpers):
 def test_progress_builder(gui: Gui, helpers):
     with tgb.Page(frame=None) as page:
     with tgb.Page(frame=None) as page:
         tgb.progress(linear="true", show_value="true", value={50})  # type: ignore[attr-defined]
         tgb.progress(linear="true", show_value="true", value={50})  # type: ignore[attr-defined]
-    expected_list = ["<Progress", 'linear={true}', 'showValue={true}', 'value="{50}"']
+    expected_list = ["<Progress", "linear={true}", "showValue={true}", 'value="{50}"']
     helpers.test_control_builder(gui, page, expected_list)
     helpers.test_control_builder(gui, page, expected_list)