1313# limitations under the License.
1414"""Formatter used to display a data table conversion button next to dataframes."""
1515
16- import logging
1716import textwrap
18- import uuid as _uuid
19- import weakref as _weakref
2017
2118from google .colab import _generate_with_variable
2219from google .colab import _interactive_table_hint_button
23- from google .colab import _quickchart
24- from google .colab import output
2520import IPython as _IPython
2621
2722
28- _output_callbacks = {}
29- _MAX_CHART_INSTANCES = 4
3023_ENABLE_GENERATE = False
31- _ENABLE_SUGGEST_PLOTS = False
32- _QUICKCHART_BUTTON_MIN_ROW_COUNT = 2 # Min # rows to enable quickchart button.
33-
34- _ICON_SVG = textwrap .dedent ("""
35- <svg xmlns="http://www.w3.org/2000/svg" height="24px"viewBox="0 0 24 24"
36- width="24px">
37- <g>
38- <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/>
39- </g>
40- </svg>""" )
41-
42- _HINT_BUTTON_CSS = textwrap .dedent ("""
43- <style>
44- .colab-df-quickchart {
45- --bg-color: #E8F0FE;
46- --fill-color: #1967D2;
47- --hover-bg-color: #E2EBFA;
48- --hover-fill-color: #174EA6;
49- --disabled-fill-color: #AAA;
50- --disabled-bg-color: #DDD;
51- }
52-
53- [theme=dark] .colab-df-quickchart {
54- --bg-color: #3B4455;
55- --fill-color: #D2E3FC;
56- --hover-bg-color: #434B5C;
57- --hover-fill-color: #FFFFFF;
58- --disabled-bg-color: #3B4455;
59- --disabled-fill-color: #666;
60- }
61-
62- .colab-df-quickchart {
63- background-color: var(--bg-color);
64- border: none;
65- border-radius: 50%;
66- cursor: pointer;
67- display: none;
68- fill: var(--fill-color);
69- height: 32px;
70- padding: 0;
71- width: 32px;
72- }
73-
74- .colab-df-quickchart:hover {
75- background-color: var(--hover-bg-color);
76- box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);
77- fill: var(--button-hover-fill-color);
78- }
79-
80- .colab-df-quickchart-complete:disabled,
81- .colab-df-quickchart-complete:disabled:hover {
82- background-color: var(--disabled-bg-color);
83- fill: var(--disabled-fill-color);
84- box-shadow: none;
85- }
86-
87- .colab-df-spinner {
88- border: 2px solid var(--fill-color);
89- border-color: transparent;
90- border-bottom-color: var(--fill-color);
91- animation:
92- spin 1s steps(1) infinite;
93- }
94-
95- @keyframes spin {
96- 0% {
97- border-color: transparent;
98- border-bottom-color: var(--fill-color);
99- border-left-color: var(--fill-color);
100- }
101- 20% {
102- border-color: transparent;
103- border-left-color: var(--fill-color);
104- border-top-color: var(--fill-color);
105- }
106- 30% {
107- border-color: transparent;
108- border-left-color: var(--fill-color);
109- border-top-color: var(--fill-color);
110- border-right-color: var(--fill-color);
111- }
112- 40% {
113- border-color: transparent;
114- border-right-color: var(--fill-color);
115- border-top-color: var(--fill-color);
116- }
117- 60% {
118- border-color: transparent;
119- border-right-color: var(--fill-color);
120- }
121- 80% {
122- border-color: transparent;
123- border-right-color: var(--fill-color);
124- border-bottom-color: var(--fill-color);
125- }
126- 90% {
127- border-color: transparent;
128- border-bottom-color: var(--fill-color);
129- }
130- }
131- </style>
132- """ )
133-
134-
135- class DataframeCache (object ):
136- """Cache of dataframes that may be requested for output visualization.
137-
138- Purposely uses weakref to allow memory to be freed for dataframes which are no
139- longer referenced elsewhere, rather than accumulating all dataframes seen so
140- far.
141- """
142-
143- def __init__ (self ):
144- """Constructor."""
145- # Cache of non-interactive dfs that still have live references and could be
146- # printed as interactive dfs.
147- self ._noninteractive_df_refs = _weakref .WeakValueDictionary ()
148- # Single entry cache that stores a shallow copy of the last printed df.
149- self ._last_noninteractive_df = {}
150-
151- def __getitem__ (self , key ):
152- """Gets a dataframe by the given key if it still exists."""
153- if key in self ._last_noninteractive_df :
154- return self ._last_noninteractive_df .pop (key )
155- elif key in self ._noninteractive_df_refs :
156- return self ._noninteractive_df_refs .pop (key )
157- raise KeyError ('Dataframe key "%s" was not found' % key )
158-
159- def __setitem__ (self , key , df ):
160- """Adds the given dataframe to the cache."""
161- self ._noninteractive_df_refs [key ] = df
162-
163- # Ensure our last value cache only contains one item.
164- self ._last_noninteractive_df .clear ()
165- self ._last_noninteractive_df [key ] = df
166-
167- def keys (self ):
168- return list (
169- set (self ._noninteractive_df_refs .keys ()).union (
170- set (self ._last_noninteractive_df .keys ())
171- )
172- )
173-
174-
175- _df_cache = DataframeCache ()
176- _chart_cache = {}
177-
178-
179- def _suggest_charts (df_key ):
180- """Generates and displays a set of charts from the specified dataframe.
181-
182- Args:
183- df_key: (str) The dataframe key (element id).
184- """
185- try :
186- df = _df_cache [df_key ]
187- except KeyError :
188- print (
189- 'WARNING: Runtime no longer has a reference to this dataframe, please'
190- ' re-run this cell and try again.'
191- )
192- return
193-
194- for chart_section in _quickchart .find_charts (
195- df , max_chart_instances = _MAX_CHART_INSTANCES
196- ):
197- for chart in chart_section .charts :
198- _chart_cache [chart .chart_id ] = chart
199- chart_section .display ()
200-
201-
202- def _get_code_for_chart (chart_key ):
203- if chart_key in _chart_cache :
204- chart_code = _chart_cache [chart_key ].get_code ()
205- return _IPython .display .JSON (dict (code = chart_code ))
206- else :
207- logging .error ('Did not find quickchart key %s in chart cache' , chart_key )
208- return f'Could not find code for chart { chart_key } '
209-
210-
211- output .register_callback ('getCodeForChart' , _get_code_for_chart )
212- output .register_callback ('suggestCharts' , _suggest_charts )
213-
214-
215- def register_df_and_get_html (df ):
216- """Registers a dataframe and returns HTML with a quickchart button.
217-
218- Args:
219- df: (DataFrame) The dataframe to register.
220-
221- Returns:
222- (str) The HTML for the quickchart button.
223- """
224- df_key = f'df-{ str (_uuid .uuid4 ())} '
225- _df_cache [df_key ] = df
226- html = textwrap .dedent (f"""
227- <div id="{ df_key } ">
228- <button class="colab-df-quickchart" onclick="quickchart('{ df_key } ')"
229- title="Suggest charts"
230- style="display:none;">
231- { _ICON_SVG }
232- </button>
233- { _HINT_BUTTON_CSS }
234- <script>
235- async function quickchart(key) {{
236- const quickchartButtonEl =
237- document.querySelector('#' + key + ' button');
238- quickchartButtonEl.disabled = true; // To prevent multiple clicks.
239- quickchartButtonEl.classList.add('colab-df-spinner');
240- try {{
241- const charts = await google.colab.kernel.invokeFunction(
242- 'suggestCharts', [key], {{}});
243- }} catch (error) {{
244- console.error('Error during call to suggestCharts:', error);
245- }}
246- quickchartButtonEl.classList.remove('colab-df-spinner');
247- quickchartButtonEl.classList.add('colab-df-quickchart-complete');
248- }}
249- (() => {{
250- let quickchartButtonEl =
251- document.querySelector('#{ df_key } button');
252- quickchartButtonEl.style.display =
253- google.colab.kernel.accessAllowed ? 'block' : 'none';
254- }})();
255- </script>
256- </div>""" )
257- return html
25824
25925
26026def _df_formatter_with_hint_buttons (df ):
261- """Alternate df formatter with buttons for interactive and quickchart."""
27+ """Alternate df formatter with buttons for interactive."""
28+
26229 buttons = []
263- if _ENABLE_SUGGEST_PLOTS and len (df ) >= _QUICKCHART_BUTTON_MIN_ROW_COUNT :
264- buttons .append (register_df_and_get_html (df ))
26530 if _ENABLE_GENERATE :
26631 buttons .append (_generate_with_variable .get_html (df ))
26732 # pylint: disable=protected-access
@@ -275,7 +40,8 @@ def _df_formatter_with_hint_buttons(df):
27540
27641
27742def _enable_df_interactive_hint_formatter ():
278- """Formatter that surfaces interactive tables and quickchart to user."""
43+ """Formatter that surfaces interactive tables to user."""
44+
27945 shell = _IPython .get_ipython ()
28046 if not shell :
28147 return
0 commit comments