Skip to content

Commit 146f7aa

Browse files
Hook up variables window to data explorer (microsoft#5205)
1 parent 6123290 commit 146f7aa

13 files changed

Lines changed: 151 additions & 76 deletions

File tree

‎news/1 Enhancements/5187.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hook up the variable explorer to the data frame explorer

‎package.nls.json‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,11 @@
227227
"LanguageService.extractionCompletedOutputMessage": "complete",
228228
"LanguageService.extractionDoneOutputMessage": "done",
229229
"LanguageService.reloadVSCodeIfSeachPathHasChanged": "Search paths have changed for this Python interpreter. Please reload the extension to ensure that the IntelliSense works correctly",
230+
"DataScience.variableExplorerNameColumn": "Name",
231+
"DataScience.variableExplorerTypeColumn": "Type",
232+
"DataScience.variableExplorerSizeColumn": "Size",
233+
"DataScience.variableExplorerValueColumn": "Value",
234+
"DataScience.showDataExplorerTooltip": "Show variable in data explorer.",
230235
"DataScience.dataExplorerInvalidVariableFormat": "'{0}' is not an active variable.",
231236
"DataScience.jupyterGetVariablesExecutionError": "Failure during variable extraction:\r\n{0}",
232237
"DataScience.loadingMessage": "loading ...",

‎pythonFiles/datascience/getJupyterVariableDataFrameInfo.py‎

Lines changed: 65 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,78 @@
22
import json as _VSCODE_json
33
import pandas as _VSCODE_pd
44

5+
# _VSCode_sub_supportsDataExplorer will contain our list of data explorer supported types
6+
_VSCode_supportsDataExplorer = _VSCode_sub_supportsDataExplorer
7+
58
# In IJupyterVariables.getValue this '_VSCode_JupyterTestValue' will be replaced with the json stringified value of the target variable
69
# Indexes off of _VSCODE_targetVariable need to index types that are part of IJupyterVariable
710
_VSCODE_targetVariable = _VSCODE_json.loads('_VSCode_JupyterTestValue')
8-
_VSCODE_evalResult = eval(_VSCODE_targetVariable['name'])
911

10-
# First list out the columns of the data frame (assuming it is one for now)
11-
_VSCODE_columnTypes = []
12-
_VSCODE_columnNames = []
13-
if _VSCODE_targetVariable['type'] == 'list':
14-
_VSCODE_columnTypes = ['string'] # Might be able to be more specific here?
15-
_VSCODE_columnNames = ['_VSCode_JupyterValuesColumn']
16-
elif _VSCODE_targetVariable['type'] == 'Series':
17-
_VSCODE_evalResult = _VSCODE_pd.Series.to_frame(_VSCODE_evalResult)
18-
_VSCODE_columnTypes = list(_VSCODE_evalResult.dtypes)
19-
_VSCODE_columnNames = list(_VSCODE_evalResult)
20-
elif _VSCODE_targetVariable['type'] == 'dict':
21-
_VSCODE_evalResult = _VSCODE_pd.Series(_VSCODE_evalResult)
22-
_VSCODE_evalResult = _VSCODE_pd.Series.to_frame(_VSCODE_evalResult)
23-
_VSCODE_columnTypes = list(_VSCODE_evalResult.dtypes)
24-
_VSCODE_columnNames = list(_VSCODE_evalResult)
25-
elif _VSCODE_targetVariable['type'] == 'ndarray':
26-
_VSCODE_evalResult = _VSCODE_pd.Series(_VSCODE_evalResult)
27-
_VSCODE_evalResult = _VSCODE_pd.Series.to_frame(_VSCODE_evalResult)
28-
_VSCODE_columnTypes = list(_VSCODE_evalResult.dtypes)
29-
_VSCODE_columnNames = list(_VSCODE_evalResult)
30-
elif _VSCODE_targetVariable['type'] == 'DataFrame':
31-
_VSCODE_columnTypes = list(_VSCODE_evalResult.dtypes)
32-
_VSCODE_columnNames = list(_VSCODE_evalResult)
12+
# First check to see if we are a supported type, this prevents us from adding types that are not supported
13+
# and also keeps our types in sync with what the variable explorer says that we support
14+
if _VSCODE_targetVariable['type'] not in _VSCode_supportsDataExplorer:
15+
del _VSCode_supportsDataExplorer
16+
print(_VSCODE_json.dumps(_VSCODE_targetVariable))
17+
del _VSCODE_targetVariable
18+
else:
19+
del _VSCode_supportsDataExplorer
20+
_VSCODE_evalResult = eval(_VSCODE_targetVariable['name'])
21+
22+
# First list out the columns of the data frame (assuming it is one for now)
23+
_VSCODE_columnTypes = []
24+
_VSCODE_columnNames = []
25+
if _VSCODE_targetVariable['type'] == 'list':
26+
_VSCODE_columnTypes = ['string'] # Might be able to be more specific here?
27+
_VSCODE_columnNames = ['_VSCode_JupyterValuesColumn']
28+
elif _VSCODE_targetVariable['type'] == 'Series':
29+
_VSCODE_evalResult = _VSCODE_pd.Series.to_frame(_VSCODE_evalResult)
30+
_VSCODE_columnTypes = list(_VSCODE_evalResult.dtypes)
31+
_VSCODE_columnNames = list(_VSCODE_evalResult)
32+
elif _VSCODE_targetVariable['type'] == 'dict':
33+
_VSCODE_evalResult = _VSCODE_pd.Series(_VSCODE_evalResult)
34+
_VSCODE_evalResult = _VSCODE_pd.Series.to_frame(_VSCODE_evalResult)
35+
_VSCODE_columnTypes = list(_VSCODE_evalResult.dtypes)
36+
_VSCODE_columnNames = list(_VSCODE_evalResult)
37+
elif _VSCODE_targetVariable['type'] == 'ndarray':
38+
_VSCODE_evalResult = _VSCODE_pd.Series(_VSCODE_evalResult)
39+
_VSCODE_evalResult = _VSCODE_pd.Series.to_frame(_VSCODE_evalResult)
40+
_VSCODE_columnTypes = list(_VSCODE_evalResult.dtypes)
41+
_VSCODE_columnNames = list(_VSCODE_evalResult)
42+
elif _VSCODE_targetVariable['type'] == 'DataFrame':
43+
_VSCODE_columnTypes = list(_VSCODE_evalResult.dtypes)
44+
_VSCODE_columnNames = list(_VSCODE_evalResult)
3345

34-
# Make sure we have an index column (see code in getJupyterVariableDataFrameRows.py)
35-
if 'index' not in _VSCODE_columnNames:
36-
_VSCODE_columnNames.insert(0, 'index')
37-
_VSCODE_columnTypes.insert(0, 'int64')
46+
# Make sure we have an index column (see code in getJupyterVariableDataFrameRows.py)
47+
if 'index' not in _VSCODE_columnNames:
48+
_VSCODE_columnNames.insert(0, 'index')
49+
_VSCODE_columnTypes.insert(0, 'int64')
3850

39-
# Then loop and generate our output json
40-
_VSCODE_columns = []
41-
for _VSCODE_n in range(0, len(_VSCODE_columnNames)):
42-
_VSCODE_column_name = _VSCODE_columnNames[_VSCODE_n]
43-
_VSCODE_column_type = _VSCODE_columnTypes[_VSCODE_n]
44-
_VSCODE_colobj = {}
45-
_VSCODE_colobj['key'] = _VSCODE_column_name
46-
_VSCODE_colobj['name'] = _VSCODE_column_name
47-
_VSCODE_colobj['type'] = str(_VSCODE_column_type)
48-
_VSCODE_columns.append(_VSCODE_colobj)
51+
# Then loop and generate our output json
52+
_VSCODE_columns = []
53+
for _VSCODE_n in range(0, len(_VSCODE_columnNames)):
54+
_VSCODE_column_name = _VSCODE_columnNames[_VSCODE_n]
55+
_VSCODE_column_type = _VSCODE_columnTypes[_VSCODE_n]
56+
_VSCODE_colobj = {}
57+
_VSCODE_colobj['key'] = _VSCODE_column_name
58+
_VSCODE_colobj['name'] = _VSCODE_column_name
59+
_VSCODE_colobj['type'] = str(_VSCODE_column_type)
60+
_VSCODE_columns.append(_VSCODE_colobj)
4961

50-
del _VSCODE_columnNames
51-
del _VSCODE_columnTypes
62+
del _VSCODE_columnNames
63+
del _VSCODE_columnTypes
5264

53-
# Save this in our target
54-
_VSCODE_targetVariable['columns'] = _VSCODE_columns
55-
del _VSCODE_columns
65+
# Save this in our target
66+
_VSCODE_targetVariable['columns'] = _VSCODE_columns
67+
del _VSCODE_columns
5668

57-
# Figure out shape if not already there. Use the shape to compute the row count
58-
if (hasattr(_VSCODE_evalResult, "shape")):
59-
_VSCODE_targetVariable['rowCount'] = _VSCODE_evalResult.shape[0]
60-
elif _VSCODE_targetVariable['type'] == 'list':
61-
_VSCODE_targetVariable['rowCount'] = len(_VSCODE_evalResult)
62-
else:
63-
_VSCODE_targetVariable['rowCount'] = 0
69+
# Figure out shape if not already there. Use the shape to compute the row count
70+
if (hasattr(_VSCODE_evalResult, "shape")):
71+
_VSCODE_targetVariable['rowCount'] = _VSCODE_evalResult.shape[0]
72+
elif _VSCODE_targetVariable['type'] == 'list':
73+
_VSCODE_targetVariable['rowCount'] = len(_VSCODE_evalResult)
74+
else:
75+
_VSCODE_targetVariable['rowCount'] = 0
6476

65-
# Transform this back into a string
66-
print(_VSCODE_json.dumps(_VSCODE_targetVariable))
77+
# Transform this back into a string
78+
print(_VSCODE_json.dumps(_VSCODE_targetVariable))
79+
del _VSCODE_targetVariable

‎pythonFiles/datascience/getJupyterVariableList.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@
33
from sys import getsizeof as _VSCODE_getsizeof
44
import json as _VSCODE_json
55

6+
# _VSCode_sub_supportsDataExplorer will contain our list of data explorer supported types
7+
_VSCode_supportsDataExplorer = _VSCode_sub_supportsDataExplorer
8+
69
# who_ls is a Jupyter line magic to fetch currently defined vars
710
_VSCode_JupyterVars = %who_ls
811

912
print(_VSCODE_json.dumps([{'name': var,
1013
'type': type(eval(var)).__name__,
1114
'size': _VSCODE_getsizeof(var),
15+
'supportsDataExplorer': type(eval(var)).__name__ in _VSCode_supportsDataExplorer,
1216
'expensive': True
1317
} for var in _VSCode_JupyterVars]))
1418

19+
del _VSCode_supportsDataExplorer
1520
del _VSCode_JupyterVars
1621
del _VSCODE_json
1722
del _VSCODE_getsizeof

‎src/client/datascience/jupyter/jupyterVariables.ts‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export class JupyterVariables implements IJupyterVariables {
2222
private fetchDataFrameInfoScript?: string;
2323
private fetchDataFrameRowsScript?: string;
2424
private filesLoaded: boolean = false;
25+
// tslint:disable:quotemark
26+
private dataExplorerSupportedTypes: string = "['list', 'Series', 'dict', 'ndarray', 'DataFrame']";
2527

2628
constructor(
2729
@inject(IFileSystem) private fileSystem: IFileSystem,
@@ -36,7 +38,8 @@ export class JupyterVariables implements IJupyterVariables {
3638
return this.runScript<IJupyterVariable[]>(
3739
undefined,
3840
[],
39-
() => this.fetchVariablesScript);
41+
() => this.fetchVariablesScript,
42+
[{key: '_VSCode_sub_supportsDataExplorer', value: this.dataExplorerSupportedTypes}]);
4043
}
4144

4245
public async getValue(targetVariable: IJupyterVariable): Promise<IJupyterVariable> {
@@ -53,7 +56,10 @@ export class JupyterVariables implements IJupyterVariables {
5356
targetVariable,
5457
targetVariable,
5558
() => this.fetchDataFrameInfoScript,
56-
[{key: '_VSCode_JupyterValuesColumn', value: localize.DataScience.valuesColumn()}]);
59+
[
60+
{key: '_VSCode_JupyterValuesColumn', value: localize.DataScience.valuesColumn()},
61+
{key: '_VSCode_sub_supportsDataExplorer', value: this.dataExplorerSupportedTypes}
62+
]);
5763
}
5864

5965
public async getDataFrameRows(targetVariable: IJupyterVariable, start: number, end: number): Promise<JSONObject> {

‎src/client/datascience/types.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ export interface IDataScienceExtraSettings extends IDataScienceSettings {
262262
export interface IJupyterVariable {
263263
name: string;
264264
value: string | undefined;
265+
supportsDataExplorer: boolean;
265266
type: string;
266267
size: number;
267268
shape: string;

‎src/datascience-ui/history-react/MainPanel.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ export class MainPanel extends React.Component<IMainPanelProps, IMainPanelState>
300300
}
301301
}
302302

303-
private showDataViewer = () => {
304-
this.sendMessage(HistoryMessages.ShowDataViewer, 'df');
303+
private showDataViewer = (targetVariable: string) => {
304+
this.sendMessage(HistoryMessages.ShowDataViewer, targetVariable);
305305
}
306306

307307
private sendMessage<M extends IHistoryMapping, T extends keyof M>(type: T, payload?: M[T]) {

‎src/datascience-ui/history-react/cellButton.css‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
--button-size: 18px;
33
}
44

5-
65
.cell-button {
76
border-width: 0px;
87
border-style: solid;

‎src/datascience-ui/history-react/headerPanel.tsx‎

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export interface IHeaderPanelProps {
3434
undo(): void;
3535
redo(): void;
3636
clearAll(): void;
37-
showDataExplorer(): void;
37+
showDataExplorer(targetVariable: string): void;
3838
refreshVariables(): void;
3939
onHeightChange(newHeight: number): void;
4040
}
@@ -74,10 +74,9 @@ export class HeaderPanel extends React.Component<IHeaderPanelProps> {
7474
<CellButton baseTheme={this.props.baseTheme} onClick={this.props.clearAll} tooltip={getLocString('DataScience.clearAll', 'Remove All Cells')}>
7575
<Image baseTheme={this.props.baseTheme} class='cell-button-image' image={ImageName.Cancel}/>
7676
</CellButton>
77-
{this.renderDataFrameTestButton()}
7877
</MenuBar>
7978
{progressBar}
80-
<VariableExplorer baseTheme={this.props.baseTheme} refreshVariables={this.props.refreshVariables} onHeightChange={this.onVariableHeightChange} ref={this.props.variableExplorerRef} />
79+
<VariableExplorer baseTheme={this.props.baseTheme} showDataExplorer={this.props.showDataExplorer} refreshVariables={this.props.refreshVariables} onHeightChange={this.onVariableHeightChange} ref={this.props.variableExplorerRef} />
8180
</div>
8281
);
8382
}
@@ -99,15 +98,4 @@ export class HeaderPanel extends React.Component<IHeaderPanelProps> {
9998

10099
return null;
101100
}
102-
103-
private renderDataFrameTestButton() {
104-
if (getSettings && getSettings().showJupyterVariableExplorer) {
105-
return (
106-
<CellButton baseTheme={'vscode-light'} onClick={this.props.showDataExplorer} tooltip={'Show data explorer for \'df\' variable'}>
107-
D
108-
</CellButton>
109-
);
110-
}
111-
return null;
112-
}
113101
}

‎src/datascience-ui/history-react/variableExplorer.tsx‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { IJupyterVariable } from '../../client/datascience/types';
1010
import { getLocString } from '../react-common/locReactSide';
1111
import { getSettings } from '../react-common/settingsReactSide';
1212
import { CollapseButton } from './collapseButton';
13+
import { VariableExplorerButtonCellFormatter } from './variableExplorerButtonCellFormatter';
1314
import { CellStyle, VariableExplorerCellFormatter } from './variableExplorerCellFormatter';
1415

1516
import * as AdazzleReactDataGrid from 'react-data-grid';
@@ -20,6 +21,7 @@ interface IVariableExplorerProps {
2021
baseTheme: string;
2122
refreshVariables(): void;
2223
onHeightChange(): void;
24+
showDataExplorer(targetVariable: string): void;
2325
}
2426

2527
interface IVariableExplorerState {
@@ -49,9 +51,10 @@ export class VariableExplorer extends React.Component<IVariableExplorerProps, IV
4951
super(prop);
5052
const columns = [
5153
{key: 'name', name: getLocString('DataScience.variableExplorerNameColumn', 'Name'), type: 'string', width: 120, formatter: <VariableExplorerCellFormatter cellStyle={CellStyle.variable} />},
52-
{key: 'type', name: getLocString('DataScience.variableExplorerTypeColumn', 'Type'), type: 'string', width: 120, formatter: <VariableExplorerCellFormatter cellStyle={CellStyle.type} />},
54+
{key: 'type', name: getLocString('DataScience.variableExplorerTypeColumn', 'Type'), type: 'string', width: 120},
5355
{key: 'size', name: getLocString('DataScience.variableExplorerSizeColumn', 'Size'), type: 'number', width: 120, formatter: <VariableExplorerCellFormatter cellStyle={CellStyle.numeric} />},
54-
{key: 'value', name: getLocString('DataScience.variableExplorerValueColumn', 'Value'), type: 'string', width: 300, formatter: <VariableExplorerCellFormatter cellStyle={CellStyle.string} />}
56+
{key: 'value', name: getLocString('DataScience.variableExplorerValueColumn', 'Value'), type: 'string', width: 300},
57+
{key: 'buttons', name: '', type: 'boolean', width: 32, formatter: <VariableExplorerButtonCellFormatter showDataExplorer={this.props.showDataExplorer} baseTheme={this.props.baseTheme} /> }
5558
];
5659
this.state = { open: false,
5760
gridColumns: columns,
@@ -121,7 +124,7 @@ export class VariableExplorer extends React.Component<IVariableExplorerProps, IV
121124
// Help to keep us independent of main history window state if we choose to break out the variable explorer
122125
public newVariablesData(newVariables: IJupyterVariable[]) {
123126
const newGridRows = newVariables.map(newVar => {
124-
return {name: newVar.name, type: newVar.type, size: newVar.size, value: getLocString('DataScience.variableLoadingValue', 'Loading...')};
127+
return { buttons: {name: newVar.name, supportsDataExplorer: newVar.supportsDataExplorer}, name: newVar.name, type: newVar.type, size: newVar.size, value: getLocString('DataScience.variableLoadingValue', 'Loading...')};
125128
});
126129

127130
this.setState({ gridRows: newGridRows});
@@ -160,7 +163,7 @@ export class VariableExplorer extends React.Component<IVariableExplorerProps, IV
160163
if (index >= 0 && index < this.state.gridRows.length) {
161164
return this.state.gridRows[index];
162165
}
163-
return {name: '', type: '', size: '', value: ''};
166+
return {buttons: '', name: '', type: '', size: '', value: ''};
164167
}
165168

166169
private toggleInputBlock = () => {

0 commit comments

Comments
 (0)