jbilcke-hf HF Staff commited on
Commit
0e1d4ae
·
1 Parent(s): d0b05b4

making progress

Browse files
docs/gradio/Interactive Plots.md ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Creating Plots
2
+ ==============
3
+
4
+ Gradio is a great way to create extremely customizable dashboards. Gradio comes with three native Plot components: `gr.LinePlot`, `gr.ScatterPlot` and `gr.BarPlot`. All these plots have the same API. Let's take a look how to set them up.
5
+
6
+ Creating a Plot with a pd.Dataframe[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#creating-a-plot-with-a-pd-dataframe)
7
+ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
8
+
9
+ Plots accept a pandas Dataframe as their value. The plot also takes `x` and `y` which represent the names of the columns that represent the x and y axes respectively. Here's a simple example:
10
+
11
+ import gradio as gr
12
+ import pandas as pd
13
+ import numpy as np
14
+ import random
15
+
16
+ df = pd.DataFrame({
17
+ 'height': np.random.randint(50, 70, 25),
18
+ 'weight': np.random.randint(120, 320, 25),
19
+ 'age': np.random.randint(18, 65, 25),
20
+ 'ethnicity': [random.choice(["white", "black", "asian"]) for _ in range(25)]
21
+ })
22
+
23
+ with gr.Blocks() as demo:
24
+ gr.LinePlot(df, x="weight", y="height")
25
+
26
+ demo.launch()
27
+
28
+ Textbox
29
+
30
+ [gradio/plot\_guide\_line](https://huggingface.co/spaces/gradio/plot_guide_line) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
31
+
32
+ All plots have the same API, so you could swap this out with a `gr.ScatterPlot`:
33
+
34
+ import gradio as gr
35
+ from data import df
36
+
37
+ with gr.Blocks() as demo:
38
+ gr.ScatterPlot(df, x="weight", y="height")
39
+
40
+ demo.launch()
41
+
42
+ Textbox
43
+
44
+ [gradio/plot\_guide\_scatter](https://huggingface.co/spaces/gradio/plot_guide_scatter) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
45
+
46
+ The y axis column in the dataframe should have a numeric type, but the x axis column can be anything from strings, numbers, categories, or datetimes.
47
+
48
+ import gradio as gr
49
+ from data import df
50
+
51
+ with gr.Blocks() as demo:
52
+ gr.ScatterPlot(df, x="ethnicity", y="height")
53
+
54
+ demo.launch()
55
+
56
+ Loading...
57
+
58
+ [gradio/plot\_guide\_scatter\_nominal](https://huggingface.co/spaces/gradio/plot_guide_scatter_nominal) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
59
+
60
+ Breaking out Series by Color[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#breaking-out-series-by-color)
61
+ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
62
+
63
+ You can break out your plot into series using the `color` argument.
64
+
65
+ import gradio as gr
66
+ from data import df
67
+
68
+ with gr.Blocks() as demo:
69
+ gr.ScatterPlot(df, x="weight", y="height", color="ethnicity")
70
+
71
+ demo.launch()
72
+
73
+ Loading...
74
+
75
+ [gradio/plot\_guide\_series\_nominal](https://huggingface.co/spaces/gradio/plot_guide_series_nominal) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
76
+
77
+ If you wish to assign series specific colors, use the `color_map` arg, e.g. `gr.ScatterPlot(..., color_map={'white': '#FF9988', 'asian': '#88EEAA', 'black': '#333388'})`
78
+
79
+ The color column can be numeric type as well.
80
+
81
+ import gradio as gr
82
+ from data import df
83
+
84
+ with gr.Blocks() as demo:
85
+ gr.ScatterPlot(df, x="weight", y="height", color="age")
86
+
87
+ demo.launch()
88
+
89
+ Loading...
90
+
91
+ [gradio/plot\_guide\_series\_quantitative](https://huggingface.co/spaces/gradio/plot_guide_series_quantitative) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
92
+
93
+ Aggregating Values[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#aggregating-values)
94
+ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
95
+
96
+ You can aggregate values into groups using the `x_bin` and `y_aggregate` arguments. If your x-axis is numeric, providing an `x_bin` will create a histogram-style binning:
97
+
98
+ import gradio as gr
99
+ from data import df
100
+
101
+ with gr.Blocks() as demo:
102
+ gr.BarPlot(df, x="weight", y="height", x_bin=10, y_aggregate="sum")
103
+
104
+ demo.launch()
105
+
106
+ Loading...
107
+
108
+ [gradio/plot\_guide\_aggregate\_quantitative](https://huggingface.co/spaces/gradio/plot_guide_aggregate_quantitative) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
109
+
110
+ If your x-axis is a string type instead, they will act as the category bins automatically:
111
+
112
+ import gradio as gr
113
+ from data import df
114
+
115
+ with gr.Blocks() as demo:
116
+ gr.BarPlot(df, x="ethnicity", y="height", y_aggregate="mean")
117
+
118
+ demo.launch()
119
+
120
+ Loading...
121
+
122
+ [gradio/plot\_guide\_aggregate\_nominal](https://huggingface.co/spaces/gradio/plot_guide_aggregate_nominal) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
123
+
124
+ Selecting Regions[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#selecting-regions)
125
+ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
126
+
127
+ You can use the `.select` listener to select regions of a plot. Click and drag on the plot below to select part of the plot.
128
+
129
+ import gradio as gr
130
+ from data import df
131
+
132
+ with gr.Blocks() as demo:
133
+ plt = gr.LinePlot(df, x="weight", y="height")
134
+ selection_total = gr.Number(label="Total Weight of Selection")
135
+
136
+ def select_region(selection: gr.SelectData):
137
+ min_w, max_w = selection.index
138
+ return df[(df["weight"] >= min_w) & (df["weight"] <= max_w)]["weight"].sum()
139
+
140
+ plt.select(select_region, None, selection_total)
141
+
142
+ demo.launch()
143
+
144
+ Loading...
145
+
146
+ [gradio/plot\_guide\_selection](https://huggingface.co/spaces/gradio/plot_guide_selection) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
147
+
148
+ You can combine this and the `.double_click` listener to create some zoom in/out effects by changing `x_lim` which sets the bounds of the x-axis:
149
+
150
+ import gradio as gr
151
+ from data import df
152
+
153
+ with gr.Blocks() as demo:
154
+ plt = gr.LinePlot(df, x="weight", y="height")
155
+
156
+ def select_region(selection: gr.SelectData):
157
+ min_w, max_w = selection.index
158
+ return gr.LinePlot(x_lim=(min_w, max_w))
159
+
160
+ plt.select(select_region, None, plt)
161
+ plt.double_click(lambda: gr.LinePlot(x_lim=None), None, plt)
162
+
163
+ demo.launch()
164
+
165
+ Loading...
166
+
167
+ [gradio/plot\_guide\_zoom](https://huggingface.co/spaces/gradio/plot_guide_zoom) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
168
+
169
+ If you had multiple plots with the same x column, your event listeners could target the x limits of all other plots so that the x-axes stay in sync.
170
+
171
+ import gradio as gr
172
+ from data import df
173
+
174
+ with gr.Blocks() as demo:
175
+ plt1 = gr.LinePlot(df, x="weight", y="height")
176
+ plt2 = gr.BarPlot(df, x="weight", y="age", x_bin=10)
177
+ plots = [plt1, plt2]
178
+
179
+ def select_region(selection: gr.SelectData):
180
+ min_w, max_w = selection.index
181
+ return [gr.LinePlot(x_lim=(min_w, max_w))] * len(plots)
182
+
183
+ for plt in plots:
184
+ plt.select(select_region, None, plots)
185
+ plt.double_click(lambda: [gr.LinePlot(x_lim=None)] * len(plots), None, plots)
186
+
187
+ demo.launch()
188
+
189
+ Loading...
190
+
191
+ [gradio/plot\_guide\_zoom\_sync](https://huggingface.co/spaces/gradio/plot_guide_zoom_sync) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
192
+
193
+ Making an Interactive Dashboard[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#making-an-interactive-dashboard)
194
+ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
195
+
196
+ Take a look how you can have an interactive dashboard where the plots are functions of other Components.
197
+
198
+ import gradio as gr
199
+ from data import df
200
+
201
+ with gr.Blocks() as demo:
202
+ with gr.Row():
203
+ ethnicity = gr.Dropdown(["all", "white", "black", "asian"], value="all")
204
+ max_age = gr.Slider(18, 65, value=65)
205
+
206
+ def filtered_df(ethnic, age):
207
+ _df = df if ethnic == "all" else df[df["ethnicity"] == ethnic]
208
+ _df = _df[_df["age"] < age]
209
+ return _df
210
+
211
+ gr.ScatterPlot(filtered_df, inputs=[ethnicity, max_age], x="weight", y="height", title="Weight x Height")
212
+ gr.LinePlot(filtered_df, inputs=[ethnicity, max_age], x="age", y="height", title="Age x Height")
213
+
214
+ demo.launch()
215
+
216
+ Loading...
217
+
218
+ [gradio/plot\_guide\_interactive](https://huggingface.co/spaces/gradio/plot_guide_interactive) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
219
+
220
+ It's that simple to filter and control the data presented in your visualization!
docs/gradio/Time Plots.md ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 1. Data Science And Plots
2
+ 2. Time Plots
3
+
4
+ [
5
+
6
+
7
+
8
+ Creating Plots
9
+
10
+
11
+
12
+ ](../guides/creating-plots/)[
13
+
14
+ Filters Tables And Stats
15
+
16
+
17
+
18
+ ](../guides/filters-tables-and-stats/)
19
+
20
+ Time Plots
21
+ ==========
22
+
23
+ Creating visualizations with a time x-axis is a common use case. Let's dive in!
24
+
25
+ Creating a Plot with a pd.Dataframe[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#creating-a-plot-with-a-pd-dataframe)
26
+ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
27
+
28
+ Time plots need a datetime column on the x-axis. Here's a simple example with some flight data:
29
+
30
+ import gradio as gr
31
+ import pandas as pd
32
+ import numpy as np
33
+ import random
34
+
35
+ from datetime import datetime, timedelta
36
+ now = datetime.now()
37
+
38
+ df = pd.DataFrame({
39
+ 'time': [now - timedelta(minutes=5*i) for i in range(25)],
40
+ 'price': np.random.randint(100, 1000, 25),
41
+ 'origin': [random.choice(["DFW", "DAL", "HOU"]) for _ in range(25)],
42
+ 'destination': [random.choice(["JFK", "LGA", "EWR"]) for _ in range(25)],
43
+ })
44
+
45
+ with gr.Blocks() as demo:
46
+ gr.LinePlot(df, x="time", y="price")
47
+ gr.ScatterPlot(df, x="time", y="price", color="origin")
48
+
49
+ demo.launch()
50
+
51
+ Textbox
52
+
53
+ Textbox
54
+
55
+ [gradio/plot\_guide\_temporal](https://huggingface.co/spaces/gradio/plot_guide_temporal) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
56
+
57
+ Aggregating by Time[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#aggregating-by-time)
58
+ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
59
+
60
+ You may wish to bin data by time buckets. Use `x_bin` to do so, using a string suffix with "s", "m", "h" or "d", such as "15m" or "1d".
61
+
62
+ import gradio as gr
63
+ from data import df
64
+
65
+ with gr.Blocks() as demo:
66
+ plot = gr.BarPlot(df, x="time", y="price", x_bin="10m")
67
+
68
+ bins = gr.Radio(["10m", "30m", "1h"], label="Bin Size")
69
+ bins.change(lambda bins: gr.BarPlot(x_bin=bins), bins, plot)
70
+
71
+ demo.launch()
72
+
73
+ Textbox
74
+
75
+ Bin Size
76
+
77
+ 10m 30m 1h
78
+
79
+ [gradio/plot\_guide\_aggregate\_temporal](https://huggingface.co/spaces/gradio/plot_guide_aggregate_temporal) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
80
+
81
+ DateTime Components[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#date-time-components)
82
+ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
83
+
84
+ You can use `gr.DateTime` to accept input datetime data. This works well with plots for defining the x-axis range for the data.
85
+
86
+ import gradio as gr
87
+ from data import df
88
+
89
+ with gr.Blocks() as demo:
90
+ with gr.Row():
91
+ start = gr.DateTime("now - 24h")
92
+ end = gr.DateTime("now")
93
+ apply_btn = gr.Button("Apply")
94
+ plot = gr.LinePlot(df, x="time", y="price")
95
+
96
+ apply_btn.click(lambda start, end: gr.BarPlot(x_lim=[start, end]), [start, end], plot)
97
+
98
+ demo.launch()
99
+
100
+ Time
101
+
102
+
103
+
104
+ Time
105
+
106
+
107
+
108
+ Apply
109
+
110
+ Textbox
111
+
112
+ [gradio/plot\_guide\_datetime](https://huggingface.co/spaces/gradio/plot_guide_datetime) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
113
+
114
+ Note how `gr.DateTime` can accept a full datetime string, or a shorthand using `now - [0-9]+[smhd]` format to refer to a past time.
115
+
116
+ You will often have many time plots in which case you'd like to keep the x-axes in sync. The `DateTimeRange` custom component keeps a set of datetime plots in sync, and also uses the `.select` listener of plots to allow you to zoom into plots while keeping plots in sync.
117
+
118
+ Because it is a custom component, you first need to `pip install gradio_datetimerange`. Then run the following:
119
+
120
+ import gradio as gr
121
+ from gradio_datetimerange import DateTimeRange
122
+ from data import df
123
+
124
+ with gr.Blocks() as demo:
125
+ daterange = DateTimeRange(["now - 24h", "now"])
126
+ plot1 = gr.LinePlot(df, x="time", y="price")
127
+ plot2 = gr.LinePlot(df, x="time", y="price", color="origin")
128
+ daterange.bind([plot1, plot2])
129
+
130
+ demo.launch()
131
+
132
+ Time
133
+
134
+ Back Last 15mLast 1hLast 24h
135
+
136
+ Time
137
+
138
+
139
+
140
+ Time
141
+
142
+
143
+
144
+ Textbox
145
+
146
+ Textbox
147
+
148
+ [gradio/plot\_guide\_datetimerange](https://huggingface.co/spaces/gradio/plot_guide_datetimerange) built with [Gradio](https://gradio.app). Hosted on [![Hugging Face Space](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='10'%20fill='none'%3e%3cpath%20fill='%23FF3270'%20d='M1.93%206.03v2.04h2.04V6.03H1.93Z'/%3e%3cpath%20fill='%23861FFF'%20d='M6.03%206.03v2.04h2.04V6.03H6.03Z'/%3e%3cpath%20fill='%23097EFF'%20d='M1.93%201.93v2.04h2.04V1.93H1.93Z'/%3e%3cpath%20fill='%23000'%20fill-rule='evenodd'%20d='M.5%201.4c0-.5.4-.9.9-.9h3.1a.9.9%200%200%201%20.87.67A2.44%202.44%200%200%201%209.5%202.95c0%20.65-.25%201.24-.67%201.68.39.1.67.46.67.88v3.08c0%20.5-.4.91-.9.91H1.4a.9.9%200%200%201-.9-.9V1.4Zm1.43.53v2.04h2.04V1.93H1.93Zm0%206.14V6.03h2.04v2.04H1.93Zm4.1%200V6.03h2.04v2.04H6.03Zm0-5.12a1.02%201.02%200%201%201%202.04%200%201.02%201.02%200%200%201-2.04%200Z'%20clip-rule='evenodd'/%3e%3cpath%20fill='%23FFD702'%20d='M7.05%201.93a1.02%201.02%200%201%200%200%202.04%201.02%201.02%200%200%200%200-2.04Z'/%3e%3c/svg%3e) Spaces](https://huggingface.co/spaces)
149
+
150
+ Try zooming around in the plots and see how DateTimeRange updates. All the plots updates their `x_lim` in sync. You also have a "Back" link in the component to allow you to quickly zoom in and out.
151
+
152
+ RealTime Data[![](data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='%23808080'%20viewBox='0%200%20640%20512'%3e%3c!--!%20Font%20Awesome%20Pro%206.0.0%20by%20@fontawesome%20-%20https://fontawesome.com%20License%20-%20https://fontawesome.com/license%20(Commercial%20License)%20Copyright%202022%20Fonticons,%20Inc.%20--%3e%3cpath%20d='M172.5%20131.1C228.1%2075.51%20320.5%2075.51%20376.1%20131.1C426.1%20181.1%20433.5%20260.8%20392.4%20318.3L391.3%20319.9C381%20334.2%20361%20337.6%20346.7%20327.3C332.3%20317%20328.9%20297%20339.2%20282.7L340.3%20281.1C363.2%20249%20359.6%20205.1%20331.7%20177.2C300.3%20145.8%20249.2%20145.8%20217.7%20177.2L105.5%20289.5C73.99%20320.1%2073.99%20372%20105.5%20403.5C133.3%20431.4%20177.3%20435%20209.3%20412.1L210.9%20410.1C225.3%20400.7%20245.3%20404%20255.5%20418.4C265.8%20432.8%20262.5%20452.8%20248.1%20463.1L246.5%20464.2C188.1%20505.3%20110.2%20498.7%2060.21%20448.8C3.741%20392.3%203.741%20300.7%2060.21%20244.3L172.5%20131.1zM467.5%20380C411%20436.5%20319.5%20436.5%20263%20380C213%20330%20206.5%20251.2%20247.6%20193.7L248.7%20192.1C258.1%20177.8%20278.1%20174.4%20293.3%20184.7C307.7%20194.1%20311.1%20214.1%20300.8%20229.3L299.7%20230.9C276.8%20262.1%20280.4%20306.9%20308.3%20334.8C339.7%20366.2%20390.8%20366.2%20422.3%20334.8L534.5%20222.5C566%20191%20566%20139.1%20534.5%20108.5C506.7%2080.63%20462.7%2076.99%20430.7%2099.9L429.1%20101C414.7%20111.3%20394.7%20107.1%20384.5%2093.58C374.2%2079.2%20377.5%2059.21%20391.9%2048.94L393.5%2047.82C451%206.731%20529.8%2013.25%20579.8%2063.24C636.3%20119.7%20636.3%20211.3%20579.8%20267.7L467.5%20380z'/%3e%3c/svg%3e)](#real-time-data)
153
+ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
154
+
155
+ In many cases, you're working with live, realtime date, not a static dataframe. In this case, you'd update the plot regularly with a `gr.Timer()`. Assuming there's a `get_data` method that gets the latest dataframe:
156
+
157
+ with gr.Blocks() as demo:
158
+ timer = gr.Timer(5)
159
+ plot1 = gr.BarPlot(x="time", y="price")
160
+ plot2 = gr.BarPlot(x="time", y="price", color="origin")
161
+
162
+ timer.tick(lambda: [get_data(), get_data()], outputs=[plot1, plot2])
163
+
164
+ You can also use the `every` shorthand to attach a `Timer` to a component that has a function value:
165
+
166
+ with gr.Blocks() as demo:
167
+ timer = gr.Timer(5)
168
+ plot1 = gr.BarPlot(get_data, x="time", y="price", every=timer)
169
+ plot2 = gr.BarPlot(get_data, x="time", y="price", color="origin", every=timer)
170
+
171
+ [
172
+
173
+
174
+
175
+ Creating Plots
176
+
177
+
178
+
179
+ ](../guides/creating-plots/)[
180
+
181
+ Filters Tables And Stats
182
+
183
+
184
+
185
+ ](../guides/filters-tables-and-stats/)
vms/ui/monitoring/services/gpu.py CHANGED
@@ -10,11 +10,8 @@ from typing import Dict, List, Any, Optional, Tuple
10
  from collections import deque
11
  from datetime import datetime
12
 
13
- # Force the use of the Agg backend which is thread-safe
14
- import matplotlib
15
- matplotlib.use('Agg') # Must be before importing pyplot
16
- import matplotlib.pyplot as plt
17
  import numpy as np
 
18
 
19
  logger = logging.getLogger(__name__)
20
  logger.setLevel(logging.INFO)
@@ -307,180 +304,81 @@ class GPUMonitoringService:
307
  """
308
  return self.collect_gpu_metrics()
309
 
310
- def generate_utilization_plot(self, gpu_index: int) -> plt.Figure:
311
- """Generate a plot of GPU utilization over time
312
 
313
  Args:
314
- gpu_index: Index of the GPU to plot
315
 
316
  Returns:
317
- Matplotlib figure with utilization plot
318
  """
319
- plt.close('all') # Close all existing figures
320
-
321
- plt.style.use('dark_background')
322
-
323
- fig, ax = plt.subplots(figsize=(10, 5))
324
-
325
  if not self.has_nvidia_gpus or gpu_index not in self.history:
326
- ax.set_title(f"No data available for GPU {gpu_index}")
327
- return fig
328
 
329
  history = self.history[gpu_index]
330
  if not history['timestamps']:
331
- ax.set_title(f"No history data for GPU {gpu_index}")
332
- return fig
333
 
334
- # Convert timestamps to strings
335
- x = [t.strftime('%H:%M:%S') for t in history['timestamps']]
336
-
337
- # If we have many points, show fewer labels for readability
338
- if len(x) > 10:
339
- step = len(x) // 10
340
- ax.set_xticks(range(0, len(x), step))
341
- ax.set_xticklabels([x[i] for i in range(0, len(x), step)], rotation=45)
342
-
343
- # Plot utilization
344
- ax.plot(x, list(history['utilization']), 'b-', label='GPU Utilization %')
345
- ax.set_ylim(0, 100)
346
-
347
- # Add temperature on secondary y-axis
348
- ax2 = ax.twinx()
349
- ax2.plot(x, list(history['temperature']), 'r-', label='Temperature °C')
350
- ax2.set_ylabel('Temperature (°C)', color='r')
351
- ax2.tick_params(axis='y', colors='r')
352
-
353
- # Set labels and title
354
- ax.set_title(f'GPU {gpu_index} Utilization Over Time')
355
- ax.set_xlabel('Time')
356
- ax.set_ylabel('Utilization %')
357
- ax.grid(True, alpha=0.3)
358
 
359
- # Add legend
360
- lines, labels = ax.get_legend_handles_labels()
361
- lines2, labels2 = ax2.get_legend_handles_labels()
362
- ax.legend(lines + lines2, labels + labels2, loc='upper left')
363
-
364
- plt.tight_layout()
365
- return fig
366
-
367
- def generate_memory_plot(self, gpu_index: int) -> plt.Figure:
368
- """Generate a plot of GPU memory usage over time
369
 
370
  Args:
371
- gpu_index: Index of the GPU to plot
372
 
373
  Returns:
374
- Matplotlib figure with memory usage plot
375
  """
376
- plt.close('all') # Close all existing figures
377
-
378
- plt.style.use('dark_background')
379
-
380
- fig, ax = plt.subplots(figsize=(10, 5))
381
-
382
  if not self.has_nvidia_gpus or gpu_index not in self.history:
383
- ax.set_title(f"No data available for GPU {gpu_index}")
384
- return fig
385
 
386
  history = self.history[gpu_index]
387
  if not history['timestamps']:
388
- ax.set_title(f"No history data for GPU {gpu_index}")
389
- return fig
390
 
391
- # Convert timestamps to strings
392
- x = [t.strftime('%H:%M:%S') for t in history['timestamps']]
393
-
394
- # If we have many points, show fewer labels for readability
395
- if len(x) > 10:
396
- step = len(x) // 10
397
- ax.set_xticks(range(0, len(x), step))
398
- ax.set_xticklabels([x[i] for i in range(0, len(x), step)], rotation=45)
399
-
400
- # Plot memory percentage
401
- ax.plot(x, list(history['memory_percent']), 'g-', label='Memory Usage %')
402
- ax.set_ylim(0, 100)
403
-
404
- # Add absolute memory values on secondary y-axis (convert to GB)
405
- ax2 = ax.twinx()
406
  memory_used_gb = [m / (1024**3) for m in history['memory_used']]
407
- memory_total_gb = [m / (1024**3) for m in history['memory_total']]
408
-
409
- ax2.plot(x, memory_used_gb, 'm--', label='Used (GB)')
410
- ax2.set_ylabel('Memory (GB)')
411
-
412
- # Set labels and title
413
- ax.set_title(f'GPU {gpu_index} Memory Usage Over Time')
414
- ax.set_xlabel('Time')
415
- ax.set_ylabel('Usage %')
416
- ax.grid(True, alpha=0.3)
417
-
418
- # Add legend
419
- lines, labels = ax.get_legend_handles_labels()
420
- lines2, labels2 = ax2.get_legend_handles_labels()
421
- ax.legend(lines + lines2, labels + labels2, loc='upper left')
422
-
423
- plt.tight_layout()
424
- return fig
425
 
426
- def generate_power_plot(self, gpu_index: int) -> plt.Figure:
427
- """Generate a plot of GPU power usage over time
428
 
429
  Args:
430
- gpu_index: Index of the GPU to plot
431
 
432
  Returns:
433
- Matplotlib figure with power usage plot
434
  """
435
- plt.close('all') # Close all existing figures
436
-
437
- plt.style.use('dark_background')
438
-
439
- fig, ax = plt.subplots(figsize=(10, 5))
440
-
441
  if not self.has_nvidia_gpus or gpu_index not in self.history:
442
- ax.set_title(f"No data available for GPU {gpu_index}")
443
- return fig
444
 
445
  history = self.history[gpu_index]
446
  if not history['timestamps'] or not any(history['power_usage']):
447
- ax.set_title(f"No power data for GPU {gpu_index}")
448
- return fig
449
 
450
- # Convert timestamps to strings
451
- x = [t.strftime('%H:%M:%S') for t in history['timestamps']]
452
-
453
- # If we have many points, show fewer labels for readability
454
- if len(x) > 10:
455
- step = len(x) // 10
456
- ax.set_xticks(range(0, len(x), step))
457
- ax.set_xticklabels([x[i] for i in range(0, len(x), step)], rotation=45)
458
 
459
- # Plot power usage
460
- power_usage = list(history['power_usage'])
461
- if any(power_usage): # Only plot if we have actual power data
462
- ax.plot(x, power_usage, 'b-', label='Power Usage (W)')
463
-
464
- # Get power limit if available
465
- power_limit = list(history['power_limit'])
466
- if any(power_limit): # Only plot if we have power limit data
467
- # Show power limit as horizontal line
468
- limit = max(power_limit) # Should be constant, but take max just in case
469
- if limit > 0:
470
- ax.axhline(y=limit, color='r', linestyle='--', label=f'Power Limit ({limit}W)')
471
-
472
- # Set labels and title
473
- ax.set_title(f'GPU {gpu_index} Power Usage Over Time')
474
- ax.set_xlabel('Time')
475
- ax.set_ylabel('Power (Watts)')
476
- ax.grid(True, alpha=0.3)
477
- ax.legend(loc='upper left')
478
- else:
479
- ax.set_title(f"Power data not available for GPU {gpu_index}")
480
 
481
- plt.tight_layout()
482
- return fig
483
 
 
 
484
  def shutdown(self):
485
  """Clean up resources when shutting down"""
486
  self.stop_monitoring()
 
10
  from collections import deque
11
  from datetime import datetime
12
 
 
 
 
 
13
  import numpy as np
14
+ import pandas as pd
15
 
16
  logger = logging.getLogger(__name__)
17
  logger.setLevel(logging.INFO)
 
304
  """
305
  return self.collect_gpu_metrics()
306
 
307
+ def get_utilization_data(self, gpu_index: int) -> pd.DataFrame:
308
+ """Get utilization data as a DataFrame
309
 
310
  Args:
311
+ gpu_index: Index of the GPU to get data for
312
 
313
  Returns:
314
+ DataFrame with time, utilization, and temperature
315
  """
 
 
 
 
 
 
316
  if not self.has_nvidia_gpus or gpu_index not in self.history:
317
+ return pd.DataFrame()
 
318
 
319
  history = self.history[gpu_index]
320
  if not history['timestamps']:
321
+ return pd.DataFrame()
 
322
 
323
+ # Convert to dataframe
324
+ return pd.DataFrame({
325
+ 'time': list(history['timestamps']),
326
+ 'GPU Utilization (%)': list(history['utilization']),
327
+ 'Temperature (°C)': list(history['temperature'])
328
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
 
330
+ def get_memory_data(self, gpu_index: int) -> pd.DataFrame:
331
+ """Get memory data as a DataFrame
 
 
 
 
 
 
 
 
332
 
333
  Args:
334
+ gpu_index: Index of the GPU to get data for
335
 
336
  Returns:
337
+ DataFrame with time, memory percent, and memory used
338
  """
 
 
 
 
 
 
339
  if not self.has_nvidia_gpus or gpu_index not in self.history:
340
+ return pd.DataFrame()
 
341
 
342
  history = self.history[gpu_index]
343
  if not history['timestamps']:
344
+ return pd.DataFrame()
 
345
 
346
+ # Convert to dataframe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  memory_used_gb = [m / (1024**3) for m in history['memory_used']]
348
+ return pd.DataFrame({
349
+ 'time': list(history['timestamps']),
350
+ 'Memory Usage (%)': list(history['memory_percent']),
351
+ 'Memory Used (GB)': memory_used_gb
352
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
353
 
354
+ def get_power_data(self, gpu_index: int) -> pd.DataFrame:
355
+ """Get power data as a DataFrame
356
 
357
  Args:
358
+ gpu_index: Index of the GPU to get data for
359
 
360
  Returns:
361
+ DataFrame with time and power usage
362
  """
 
 
 
 
 
 
363
  if not self.has_nvidia_gpus or gpu_index not in self.history:
364
+ return pd.DataFrame()
 
365
 
366
  history = self.history[gpu_index]
367
  if not history['timestamps'] or not any(history['power_usage']):
368
+ return pd.DataFrame()
 
369
 
370
+ power_limit = max(history['power_limit']) if any(history['power_limit']) else None
 
 
 
 
 
 
 
371
 
372
+ df = pd.DataFrame({
373
+ 'time': list(history['timestamps']),
374
+ 'Power Usage (W)': list(history['power_usage'])
375
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
 
377
+ if power_limit and power_limit > 0:
378
+ df['Power Limit (W)'] = power_limit
379
 
380
+ return df
381
+
382
  def shutdown(self):
383
  """Clean up resources when shutting down"""
384
  self.stop_monitoring()
vms/ui/monitoring/services/monitoring.py CHANGED
@@ -8,19 +8,13 @@ import time
8
  import logging
9
  import platform
10
  import threading
 
11
  from datetime import datetime, timedelta
12
  from collections import deque
13
  from typing import Dict, List, Optional, Tuple, Any
14
 
15
  import psutil
16
 
17
- # Force the use of the Agg backend which is thread-safe
18
- import matplotlib
19
- matplotlib.use('Agg') # Must be before importing pyplot
20
- import matplotlib.pyplot as plt
21
-
22
- import numpy as np
23
-
24
  from vms.ui.monitoring.services.gpu import GPUMonitoringService
25
 
26
  logger = logging.getLogger(__name__)
@@ -230,157 +224,112 @@ class MonitoringService:
230
  'system': sys_info,
231
  }
232
 
233
- def generate_cpu_plot(self) -> plt.Figure:
234
- """Generate a plot of CPU usage over time
235
 
236
  Returns:
237
- Matplotlib figure with CPU usage plot
238
  """
239
- plt.close('all') # Close all existing figures
240
-
241
- plt.style.use('dark_background')
242
-
243
- fig, ax = plt.subplots(figsize=(10, 5))
244
-
245
  if not self.timestamps:
246
- ax.set_title("No CPU data available yet")
247
- return fig
 
 
248
 
249
- x = [t.strftime('%H:%M:%S') for t in self.timestamps]
250
- if len(x) > 10:
251
- # Show fewer x-axis labels for readability
252
- step = len(x) // 10
253
- ax.set_xticks(range(0, len(x), step))
254
- ax.set_xticklabels([x[i] for i in range(0, len(x), step)])
255
-
256
- ax.plot(x, list(self.cpu_percent), 'b-', label='CPU Usage %')
257
 
 
258
  if self.cpu_temp and len(self.cpu_temp) > 0:
259
- # Plot temperature on a secondary y-axis if available
260
- ax2 = ax.twinx()
261
- ax2.plot(x[:len(self.cpu_temp)], list(self.cpu_temp), 'r-', label='CPU Temp °C')
262
- ax2.set_ylabel('Temperature (°C)', color='r')
263
- ax2.tick_params(axis='y', colors='r')
 
 
264
 
265
- ax.set_title('CPU Usage Over Time')
266
- ax.set_xlabel('Time')
267
- ax.set_ylabel('Usage %')
268
- ax.grid(True, alpha=0.3)
269
- ax.set_ylim(0, 100)
270
-
271
- # Add legend
272
- lines, labels = ax.get_legend_handles_labels()
273
- if hasattr(locals(), 'ax2'):
274
- lines2, labels2 = ax2.get_legend_handles_labels()
275
- ax.legend(lines + lines2, labels + labels2, loc='upper left')
276
- else:
277
- ax.legend(loc='upper left')
278
-
279
- plt.tight_layout()
280
- return fig
281
 
282
- def generate_memory_plot(self) -> plt.Figure:
283
- """Generate a plot of memory usage over time
284
 
285
  Returns:
286
- Matplotlib figure with memory usage plot
287
  """
288
- plt.close('all') # Close all existing figures
289
-
290
- plt.style.use('dark_background')
291
-
292
- fig, ax = plt.subplots(figsize=(10, 5))
293
-
294
  if not self.timestamps:
295
- ax.set_title("No memory data available yet")
296
- return fig
 
 
 
 
297
 
298
- x = [t.strftime('%H:%M:%S') for t in self.timestamps]
299
- if len(x) > 10:
300
- # Show fewer x-axis labels for readability
301
- step = len(x) // 10
302
- ax.set_xticks(range(0, len(x), step))
303
- ax.set_xticklabels([x[i] for i in range(0, len(x), step)])
 
 
 
304
 
305
- ax.plot(x, list(self.memory_percent), 'g-', label='Memory Usage %')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
 
307
- # Add secondary y-axis for absolute memory values
308
- ax2 = ax.twinx()
309
- ax2.plot(x, list(self.memory_used), 'm--', label='Used (GB)')
310
- ax2.plot(x, list(self.memory_available), 'c--', label='Available (GB)')
311
- ax2.set_ylabel('Memory (GB)')
312
 
313
- ax.set_title('Memory Usage Over Time')
314
- ax.set_xlabel('Time')
315
- ax.set_ylabel('Usage %')
316
- ax.grid(True, alpha=0.3)
317
- ax.set_ylim(0, 100)
 
 
 
318
 
319
- # Add legend
320
- lines, labels = ax.get_legend_handles_labels()
321
- lines2, labels2 = ax2.get_legend_handles_labels()
322
- ax.legend(lines + lines2, labels + labels2, loc='upper left')
323
-
324
- plt.tight_layout()
325
- return fig
326
 
327
- def generate_per_core_plot(self) -> plt.Figure:
328
- """Generate a plot of per-core CPU usage
 
329
 
330
  Returns:
331
- Matplotlib figure with per-core CPU usage
332
  """
333
- num_cores = len(self.cpu_cores_percent)
334
- if num_cores == 0:
335
- # No data yet
336
- plt.close('all') # Close all existing figures
337
-
338
- plt.style.use('dark_background')
339
-
340
- fig, ax = plt.subplots(figsize=(10, 5))
341
- ax.set_title("No per-core CPU data available yet")
342
- return fig
343
 
344
- # Determine grid layout based on number of cores
345
- if num_cores <= 4:
346
- rows, cols = 2, 2
347
- elif num_cores <= 6:
348
- rows, cols = 2, 3
349
- elif num_cores <= 9:
350
- rows, cols = 3, 3
351
- elif num_cores <= 12:
352
- rows, cols = 3, 4
353
- else:
354
- rows, cols = 4, 4
355
-
356
- fig, axes = plt.subplots(rows, cols, figsize=(12, 8), sharex=True, sharey=True)
357
- axes = axes.flatten()
358
 
359
- x = [t.strftime('%H:%M:%S') for t in self.timestamps]
360
- if len(x) > 5:
361
- # Show fewer x-axis labels for readability
362
- step = len(x) // 5
363
- else:
364
- step = 1
365
-
366
- for i, (core_id, percentages) in enumerate(self.cpu_cores_percent.items()):
367
- if i >= len(axes):
368
- break
369
-
370
- ax = axes[i]
371
- ax.plot(x[:len(percentages)], list(percentages), 'b-')
372
- ax.set_title(f'Core {core_id}')
373
- ax.set_ylim(0, 100)
374
- ax.grid(True, alpha=0.3)
375
-
376
- # Add x-axis labels sparingly for readability
377
- if i >= len(axes) - cols: # Only for bottom row
378
- ax.set_xticks(range(0, len(x), step))
379
- ax.set_xticklabels([x[i] for i in range(0, len(x), step)], rotation=45)
380
-
381
- # Hide unused subplots
382
- for i in range(num_cores, len(axes)):
383
- axes[i].set_visible(False)
384
 
385
- plt.tight_layout()
386
- return fig
 
8
  import logging
9
  import platform
10
  import threading
11
+ import pandas as pd
12
  from datetime import datetime, timedelta
13
  from collections import deque
14
  from typing import Dict, List, Optional, Tuple, Any
15
 
16
  import psutil
17
 
 
 
 
 
 
 
 
18
  from vms.ui.monitoring.services.gpu import GPUMonitoringService
19
 
20
  logger = logging.getLogger(__name__)
 
224
  'system': sys_info,
225
  }
226
 
227
+ def get_cpu_data(self) -> pd.DataFrame:
228
+ """Get CPU usage data as a DataFrame
229
 
230
  Returns:
231
+ DataFrame with CPU usage data
232
  """
 
 
 
 
 
 
233
  if not self.timestamps:
234
+ return pd.DataFrame({
235
+ 'time': list(),
236
+ 'CPU Usage (%)': list()
237
+ })
238
 
239
+ data = {
240
+ 'time': list(self.timestamps),
241
+ 'CPU Usage (%)': list(self.cpu_percent)
242
+ }
 
 
 
 
243
 
244
+ # Add temperature if available
245
  if self.cpu_temp and len(self.cpu_temp) > 0:
246
+ # Ensure temperature data aligns with timestamps
247
+ # If fewer temperature readings than timestamps, pad with None
248
+ temp_data = list(self.cpu_temp)
249
+ if len(temp_data) < len(self.timestamps):
250
+ padding = [None] * (len(self.timestamps) - len(temp_data))
251
+ temp_data = padding + temp_data
252
+ data['CPU Temperature (°C)'] = temp_data
253
 
254
+ return pd.DataFrame(data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
 
256
+ def get_memory_data(self) -> pd.DataFrame:
257
+ """Get memory usage data as a DataFrame
258
 
259
  Returns:
260
+ DataFrame with memory usage data
261
  """
 
 
 
 
 
 
262
  if not self.timestamps:
263
+ return pd.DataFrame({
264
+ 'time': list(),
265
+ 'Memory Usage (%)': list(),
266
+ 'Memory Used (GB)': list(),
267
+ 'Memory Available (GB)': list()
268
+ })
269
 
270
+ return pd.DataFrame({
271
+ 'time': list(self.timestamps),
272
+ 'Memory Usage (%)': list(self.memory_percent),
273
+ 'Memory Used (GB)': list(self.memory_used),
274
+ 'Memory Available (GB)': list(self.memory_available)
275
+ })
276
+
277
+ def get_per_core_data(self) -> Dict[int, pd.DataFrame]:
278
+ """Get per-core CPU usage data as DataFrames
279
 
280
+ Returns:
281
+ Dictionary of DataFrames with per-core CPU usage data
282
+ """
283
+ if not self.timestamps or not self.cpu_cores_percent:
284
+ return {}
285
+
286
+ core_data = {}
287
+ for core_id, percentages in self.cpu_cores_percent.items():
288
+ # Ensure we don't have more data points than timestamps
289
+ data_length = min(len(percentages), len(self.timestamps))
290
+ core_data[core_id] = pd.DataFrame({
291
+ 'time': list(self.timestamps)[-data_length:],
292
+ f'Core {core_id} Usage (%)': list(percentages)[-data_length:]
293
+ })
294
+
295
+ return core_data
296
 
297
+ # Replace matplotlib methods with DataFrame methods
298
+
299
+ # This method is kept for backward compatibility but returns a DataFrame
300
+ def generate_cpu_plot(self) -> pd.DataFrame:
301
+ """Get CPU usage data for plotting
302
 
303
+ Returns:
304
+ DataFrame with CPU usage data
305
+ """
306
+ return self.get_cpu_data()
307
+
308
+ # This method is kept for backward compatibility but returns a DataFrame
309
+ def generate_memory_plot(self) -> pd.DataFrame:
310
+ """Get memory usage data for plotting
311
 
312
+ Returns:
313
+ DataFrame with memory usage data
314
+ """
315
+ return self.get_memory_data()
 
 
 
316
 
317
+ # This method is kept for backward compatibility but returns a DataFrame of all cores
318
+ def generate_per_core_plot(self) -> pd.DataFrame:
319
+ """Get per-core CPU usage data for plotting
320
 
321
  Returns:
322
+ Combined DataFrame with all cores' usage data
323
  """
324
+ core_data = self.get_per_core_data()
325
+ if not core_data:
326
+ return pd.DataFrame()
 
 
 
 
 
 
 
327
 
328
+ # Combine all core data into a single DataFrame using the first core's timestamps
329
+ first_core_id = list(core_data.keys())[0]
330
+ combined_df = core_data[first_core_id][['time']].copy()
 
 
 
 
 
 
 
 
 
 
 
331
 
332
+ for core_id, df in core_data.items():
333
+ combined_df[f'Core {core_id} Usage (%)'] = df[f'Core {core_id} Usage (%)']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
+ return combined_df
 
vms/ui/monitoring/tabs/general_tab.py CHANGED
@@ -8,6 +8,7 @@ import time
8
  import logging
9
  from pathlib import Path
10
  import os
 
11
  import psutil
12
  from typing import Dict, Any, List, Optional, Tuple
13
  from datetime import datetime, timedelta
@@ -42,14 +43,30 @@ class GeneralTab(BaseTab):
42
  # CPU and Memory charts in tabs
43
  with gr.Tabs() as metrics_tabs:
44
  with gr.Tab(label="CPU Usage") as cpu_tab:
45
- self.components["cpu_plot"] = gr.Plot()
46
-
 
 
 
 
 
 
 
 
 
47
  with gr.Tab(label="Memory Usage") as memory_tab:
48
- self.components["memory_plot"] = gr.Plot()
 
 
 
 
 
 
 
 
 
 
49
 
50
- #with gr.Tab(label="Per-Core CPU") as per_core_tab:
51
- # self.components["per_core_plot"] = gr.Plot()
52
-
53
  # System information summary in columns
54
  with gr.Row():
55
  with gr.Column(scale=1):
@@ -171,10 +188,9 @@ class GeneralTab(BaseTab):
171
  # current_metrics = self.app.monitoring.get_current_metrics()
172
  metrics_html = "" # self.format_current_metrics(current_metrics)
173
 
174
- # Generate plots
175
- cpu_plot = self.app.monitoring.generate_cpu_plot()
176
- memory_plot = self.app.monitoring.generate_memory_plot()
177
- #per_core_plot = self.app.monitoring.generate_per_core_plot()
178
 
179
  return (
180
  system_info_html,
@@ -182,8 +198,8 @@ class GeneralTab(BaseTab):
182
  memory_info_html,
183
  storage_info_html,
184
  metrics_html,
185
- cpu_plot,
186
- memory_plot,
187
  #per_core_plot
188
  )
189
 
 
8
  import logging
9
  from pathlib import Path
10
  import os
11
+ import pandas as pd
12
  import psutil
13
  from typing import Dict, Any, List, Optional, Tuple
14
  from datetime import datetime, timedelta
 
43
  # CPU and Memory charts in tabs
44
  with gr.Tabs() as metrics_tabs:
45
  with gr.Tab(label="CPU Usage") as cpu_tab:
46
+ empty_cpu_df = pd.DataFrame({'time': [], 'CPU Usage (%)': []})
47
+ self.components["cpu_plot"] = gr.LinePlot(
48
+ empty_cpu_df,
49
+ show_label=False,
50
+ height=400,
51
+ x="time",
52
+ y=["CPU Usage (%)"],
53
+ y_title="Value",
54
+ title="CPU Usage and Temperature"
55
+ )
56
+
57
  with gr.Tab(label="Memory Usage") as memory_tab:
58
+ empty_memory_df = pd.DataFrame({'time': [], 'Memory Usage (%)': [], 'Memory Used (GB)': [], 'Memory Available (GB)': []})
59
+
60
+ self.components["memory_plot"] = gr.LinePlot(
61
+ empty_memory_df,
62
+ show_label=False,
63
+ height=400,
64
+ x="time",
65
+ y=["Memory Usage (%)", "Memory Used (GB)", "Memory Available (GB)"],
66
+ y_title="Value",
67
+ title="Memory Usage"
68
+ )
69
 
 
 
 
70
  # System information summary in columns
71
  with gr.Row():
72
  with gr.Column(scale=1):
 
188
  # current_metrics = self.app.monitoring.get_current_metrics()
189
  metrics_html = "" # self.format_current_metrics(current_metrics)
190
 
191
+ # Get DataFrame from monitoring service
192
+ cpu_plot_df = self.app.monitoring.get_cpu_data()
193
+ memory_plot_df = self.app.monitoring.get_memory_data()
 
194
 
195
  return (
196
  system_info_html,
 
198
  memory_info_html,
199
  storage_info_html,
200
  metrics_html,
201
+ cpu_plot_df,
202
+ memory_plot_df,
203
  #per_core_plot
204
  )
205
 
vms/ui/monitoring/tabs/gpu_tab.py CHANGED
@@ -59,13 +59,34 @@ class GPUTab(BaseTab):
59
  # Display GPU metrics in tabs
60
  with gr.Tabs(visible=self.app.monitoring.gpu.has_nvidia_gpus) as metrics_tabs:
61
  with gr.Tab(label="Utilization") as util_tab:
62
- self.components["utilization_plot"] = gr.Plot()
63
-
 
 
 
 
 
 
 
64
  with gr.Tab(label="Memory") as memory_tab:
65
- self.components["memory_plot"] = gr.Plot()
66
-
 
 
 
 
 
 
 
67
  with gr.Tab(label="Power") as power_tab:
68
- self.components["power_plot"] = gr.Plot()
 
 
 
 
 
 
 
69
 
70
  # Process information
71
  with gr.Row(visible=self.app.monitoring.gpu.has_nvidia_gpus):
@@ -190,6 +211,7 @@ class GPUTab(BaseTab):
190
  Returns:
191
  Updated values for all components
192
  """
 
193
  try:
194
  if not self.app.monitoring.gpu.has_nvidia_gpus:
195
  return (
@@ -226,16 +248,17 @@ class GPUTab(BaseTab):
226
  gpu_info = self.app.monitoring.gpu.get_gpu_info()
227
  gpu_info_html = self.format_gpu_info(gpu_info[self.selected_gpu] if self.selected_gpu < len(gpu_info) else {})
228
 
229
- # Generate plots
230
- utilization_plot = self.app.monitoring.gpu.generate_utilization_plot(self.selected_gpu)
231
- memory_plot = self.app.monitoring.gpu.generate_memory_plot(self.selected_gpu)
232
- power_plot = self.app.monitoring.gpu.generate_power_plot(self.selected_gpu)
 
233
 
234
  return (
235
  metrics_html,
236
- utilization_plot,
237
- memory_plot,
238
- power_plot,
239
  process_info_html,
240
  gpu_info_html
241
  )
 
59
  # Display GPU metrics in tabs
60
  with gr.Tabs(visible=self.app.monitoring.gpu.has_nvidia_gpus) as metrics_tabs:
61
  with gr.Tab(label="Utilization") as util_tab:
62
+ self.components["utilization_plot"] = gr.LinePlot(
63
+ show_label=False,
64
+ height=400,
65
+ x="time",
66
+ y=["GPU Utilization (%)", "Temperature (°C)"],
67
+ y_title="Value",
68
+ title="GPU Utilization and Temperature"
69
+ )
70
+
71
  with gr.Tab(label="Memory") as memory_tab:
72
+ self.components["memory_plot"] = gr.LinePlot(
73
+ show_label=False,
74
+ height=400,
75
+ x="time",
76
+ y=["Memory Usage (%)", "Memory Used (GB)"],
77
+ y_title="Value",
78
+ title="GPU Memory Usage"
79
+ )
80
+
81
  with gr.Tab(label="Power") as power_tab:
82
+ self.components["power_plot"] = gr.LinePlot(
83
+ show_label=False,
84
+ height=400,
85
+ x="time",
86
+ y=["Power Usage (W)", "Power Limit (W)"],
87
+ y_title="Watts",
88
+ title="GPU Power Usage"
89
+ )
90
 
91
  # Process information
92
  with gr.Row(visible=self.app.monitoring.gpu.has_nvidia_gpus):
 
211
  Returns:
212
  Updated values for all components
213
  """
214
+
215
  try:
216
  if not self.app.monitoring.gpu.has_nvidia_gpus:
217
  return (
 
248
  gpu_info = self.app.monitoring.gpu.get_gpu_info()
249
  gpu_info_html = self.format_gpu_info(gpu_info[self.selected_gpu] if self.selected_gpu < len(gpu_info) else {})
250
 
251
+ # Get DataFrame from monitoring service
252
+ utilization_plot_df = self.app.monitoring.gpu.get_utilization_data(self.selected_gpu)
253
+ memory_plot_df = self.app.monitoring.gpu.get_memory_data(self.selected_gpu)
254
+ power_plot_df = self.app.monitoring.gpu.get_power_data(self.selected_gpu)
255
+
256
 
257
  return (
258
  metrics_html,
259
+ utilization_plot_df,
260
+ memory_plot_df,
261
+ power_plot_df,
262
  process_info_html,
263
  gpu_info_html
264
  )