Setting up VS Code for Python Development like RStudio

[This article was first published on stevenmortimer.com, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.


In this article I will highlight the features of VS Code that match RStudio
exactly, such as the “interactive notebook window” (called the Console in R) or
the “variable explorer” (like running View() on a data frame in RStudio). At
the bottom of this post I will provide two JSON files (settings.json and
keybindings.json) and a block of code to install from the command line a list
of extensions that I recommend. By using these files as a guide you can
configure your VS Code installation to do a pretty good job at mimicking
RStudio.

First, why try to write Python like you write R code in RStudio??

RStudio is a great all around IDE for data analysis. A few years ago I was
transitioning from writing a lot of R code to more Python code at work. I
initially chose PyCharm as my Python IDE for a variety of reasons outlined in
another blog post of mine: An R User
Chooses a Python IDE
. However, as of last summer (June 2019), I switched to
VS Code as a Python IDE and never looked back. In hindsight, PyCharm just seems
too clunky with an over-engineered GUI of buttons to click and not really be
sure what’s going on. VS Code is making great strides towards becoming an IDE
that works well for the REPL (read–eval–print loop) style of coding that RStudio
excels at supporting. I love how lightweight VS Code feels and how the
configurations are portable via JSON files making it easier to share a common
config with team members. I’ll keep writing R code in RStudio, but VS Code is
quckly becoming a second home for me to write Python code.

How to Configure VS Code to run like RStudio

Aesthetics (Textmate theme and margin column ruler)

You may know that the default theme in RStudio is “Textmate”. This is found in
Tools -> Global Options -> Appearance. To get the color scheme in VS Code you
can install this with the Textmate theme extension.

I tend to not change much beyond the default RStudio installation just so that I
don’t need to maintain a unique and unfamiliar setup compared to other
colleagues who are also using RStudio. The only customization I recommend is
adding a vertical line at 80 characters. This is a must-have feature to keep
your code readable and you can do the same with VS Code by specifying
"editor.rulers" in your user settings. More detail on how to configure that is in
the section of this post entitled Settings JSON File.

Running Code

As far as running code in RStudio, it is fairly common to write code in the
“Source” pane (normally above the console), then send the code to the “Console”
pane to run using CMD+ENTER (CRTL+ENTER if on Windows – please assume
anywhere I refer to CMD in this article it is CTRL if you use Windows). In
VS Code you can think of the Editor pane as having the exact same purpose
(writing a script), but instead of sourcing lines to the “Console” you use the same
command (CMD+ENTER) to run the code in the Python Interactive Window. More
specifically, the keyboard shortcut you need to set in VS Code is for the
command "python.datascience.execSelectionInteractive".

This is a game changer when writing Python code for analysis because you no
longer need to code in a Jupyter Notebook to execute your analysis. Simply write
your code in a .py file and press CMD+ENTER to execute line-by-line in the
Python Interactive Window. Repeat this process as you run code, explore, and
build out your analysis. Note that you can also type Python directly into the
Interactive Window just like you can type directly in R’s Console as well to
execute code.

Variable Explorer (“Environment” tab in R)

Notebooks always seem clunky in terms of executing single lines of code and
reviewing variables in the global environment, but VS Code has a variable
explorer just like the “Environment” tab in R.

Data Viewer (Like running View() in R)

Once you’ve created a pandas DataFrame you can explore a dynamic view of the
data frame with basic filtering and sorting. I have found this be exactly like
the View() function in RStudio. The only difference is it does seem to
struggle a bit when viewing data frames over 1 million rows. It is laggy or
crashes VS Code, but I don’t find that too much of a problem because you can
always save a sample of your dataset into a variable or aggregate your data
prior to viewing.

Plot Viewer (“Plots” tab in R)

You can flip through prior plots, save them, resize, and interact with plots the
same way as you would in the “Plots” pane of RStudio. Nothing different here.

Version Control (“Git” tab in R)

Just like RStudio you can stage files, write a commit message, and push to a git
repository. Instead of ticking a checkbox to stage files, you will have to press
the + sign, which is about the only difference. Everything else is the similar
as far as clicking on the files to see “diffs”, writing the commit message, and
pushing code to a remote repository.

All of these git features can be made even
better with Eric Amodio’s GitLens
extension
, which I highly recommend. It makes it easier to navigate
branches, see when files were changed and by whom.

What’s missing or different in VS Code?

R’s Document Outline (aka Minimap in VS Code)

RStudio creates a nice outline of your scripts based on your functions and
comments that start with:

# A new section ----
code here...

This table of contents style view is helpful. As a somewhat suitable alternative
I have become accustomed to annotating Python code blocks with region folding
syntax which creates collapsible code sections in the VS Code editor.

# region ----

code here...

# endregion

Debugging

RStudio has a nice feature that will ask you if you want to run a piece of code
with debug mode on if it initially errors. VS Code’s Python Interactive Window
also prints out error messages, but will not let you debug with the click of a
button. You can however set breakpoints and run your script in debug mode, which
is a familiar experience, just not as seamless as RStudio.

There are obviously many other features, like having a built-in terminal, remote
connections, app development via Shiny, etc. that make R/RStudio and Python/VS
Code different tools, but if you’re just running analysis the two can provide
very similar workflows, right down to the keyboard shortcuts. The only challenge
you may have left is figuring out how to make your pandas code as legible and
well organized as dplyr code… but that is for another day. (Hint: It’s possible
with a strong commitment to method chaining).

Setup Files and Scripts

Settings JSON File

In order to update your settings.json file, open the Command Palette with
CMD+SHIFT+P and select "Preferences: Open Settings (JSON)" to edit the JSON
file where your settings are held. You can copy/paste the entire block of JSON
below or just individual lines.

Note: These settings files were automatically generated from my VS Code
installation using Shan Khan’s Settings Sync extension.

settings.json (User Settings, as opposed to workspace/project-specific settings)

{
    "window.zoomLevel": 1,
    "explorer.confirmDelete": false,
    "explorer.confirmDragAndDrop": false,
    "files.associations": {},
    "files.autoSave": "off",
    "files.exclude": {
        "**/.git": true,
        "**/.svn": true,
        "**/.hg": true,
        "**/CVS": true,
        "**/.DS_Store": true,
        "**/.history/**": true,
        "**/History_**": true
    },
    "workbench.colorTheme": "textmate",
    "workbench.editor.enablePreview": false,
    "workbench.startupEditor": "welcomePageInEmptyWorkbench",
    "terminal.integrated.fontSize": 14,
    "terminal.integrated.cursorStyle": "line",
    "terminal.integrated.copyOnSelection": true,
    "terminal.integrated.confirmOnExit": false,
    "editor.largeFileOptimizations": false,
    "editor.suggest.shareSuggestSelections": true,
    "editor.suggestSelection": "first",
    "editor.minimap.enabled": false,
    "editor.foldingStrategy": "indentation",
    "editor.showFoldingControls": "always",
    "editor.rulers": [
        80
    ],
    "editor.formatOnSave": true,
    "python.linting.enabled": true,
    "python.linting.flake8Enabled": true,
    "python.linting.flake8Args": [
        "--ignore=E203, E266, E501, W503",
        "--max-line-length=79",
        "--select=B,C,E,F,W,T4,B9",
        "--max-complexity=18"
    ],
    "python.formatting.provider": "autopep8",
    "python.formatting.autopep8Args": [
        "--ignore=E501,E402"
    ],
    "sonarlint.rules": {
        "python:S3776": {
            "level": "off"
        }
    },
    "python.languageServer": "Microsoft",
    "python.dataScience.askForKernelRestart": false,
    "python.dataScience.runStartupCommands": "%load_ext autoreload\\n%autoreload 2",
    "python.dataScience.sendSelectionToInteractiveWindow": true,
    "python.dataScience.useNotebookEditor": false,
    "git.autofetch": true,
    "git.confirmSync": false,
    "gitlens.views.repositories.location": "gitlens",
    "gitlens.views.repositories.files.layout": "list",
    "gitlens.views.fileHistory.location": "gitlens",
    "gitlens.views.lineHistory.enabled": false,
    "gitlens.views.compare.location": "gitlens",
    "gitlens.views.search.location": "gitlens",
    "gitlens.mode.statusBar.enabled": true,
    "gitlens.mode.statusBar.alignment": "left",
    "gitlens.currentLine.enabled": false,
    "gitlens.hovers.enabled": false,
    "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
    "tabnine.experimentalAutoImports": true,
    "indentRainbow.errorColor": "rgba(255,255,255,0.0)",
    "todo-tree.tree.flat": true,
    "todo-tree.highlights.defaultHighlight": {
        "type": "text-and-comment",
        "foreground": "grey"
    },
    "better-comments.tags": [
        {
            "tag": "?",
            "color": "#8f5785",
            "strikethrough": false,
            "backgroundColor": "transparent"
        }
        {
            "tag": "*",
            "color": "#69a800",
            "strikethrough": false,
            "backgroundColor": "transparent"
        }
    ],
    "bracket-pair-colorizer-2.colors": [
        "#992e24",
        "#ffb997",
        "#263859"
    ],
    "cSpell.userWords": [
        "YYYYMMDD",
        "groupby",
        "idxmax",
        "inplace",
        "itertools",
        "multindex",
        "rfind",
        "strptime"
    ]
}

Keyboard Shortcuts JSON File

Updating the keyboard shortcuts JSON file is similar to editing settings.json.
Open the Command Palette with CMD+SHIFT+P and select "Preferences: Open Keyboard Shortcuts (JSON)" to edit the JSON file where your settings are held.
You can copy/paste the entire block of JSON below or just individual lines.

In addition to setting the keyboard shortcut CMD+ENTER to execute lines in the
Interactive Window I have set a few other two keyboard shortcuts to work exactly
like RStudio. For example, clearing the console and restarting the R session:

  • CRTL+L – “Clear Console” (in RStudio) => Clear Cells (in Python Interactive Window)
  • CMD+SHIFT+F10 – “Restart R” (in RStudio) => Restart Kernel (in Python Interactive Window)

Of course there are other shortcuts that you can configure like R’s block
comment command (Code -> Comment/Uncomment Lines) (CMD+SHIFT+C). Simply set
the VS Code command "editor.action.commentLine" to that shortcut.

Another example is R’s command (Code -> Reflow Comment) which hard wraps code
to 80 characters using CMD+SHIFT+/. VS Code can do the same after installing
the extension called “rewrap” and then giving its command
"rewrap.rewrapComment" the same keyboard shortcut. It is really up to you to
configure the shortcuts that you use most often.

keybindings.json

// Place your key bindings in this file to override the defaultsauto[]
[
    {
        "key": "cmd+enter",
        "command": "python.datascience.execSelectionInteractive",
        "when": "editorTextFocus && python.datascience.featureenabled && python.datascience.ownsSelection && !findInputFocussed && !notebookEditorFocused && !replaceInputFocussed && editorLangId == 'python'"
    },
    {
        "key": "shift+enter",
        "command": "-python.datascience.execSelectionInteractive",
        "when": "editorTextFocus && python.datascience.featureenabled && python.datascience.ownsSelection && !findInputFocussed && !notebookEditorFocused && !replaceInputFocussed && editorLangId == 'python'"
    },
    {
        "key": "cmd+enter",
        "command": "python.datascience.runcurrentcell",
        "when": "editorTextFocus && python.datascience.featureenabled && python.datascience.hascodecells && !editorHasSelection && !notebookEditorFocused"
    },
    {
        "key": "ctrl+enter",
        "command": "-python.datascience.runcurrentcell",
        "when": "editorTextFocus && python.datascience.featureenabled && python.datascience.hascodecells && !editorHasSelection && !notebookEditorFocused"
    },    
    {
        "key": "cmd+enter",
        "command": "notebook.cell.executeAndSelectBelow",
        "when": "notebookEditorFocused && activeEditor == 'workbench.editor.notebook'"
    },
    {
        "key": "shift+enter",
        "command": "-notebook.cell.executeAndSelectBelow",
        "when": "notebookEditorFocused && activeEditor == 'workbench.editor.notebook'"
    },    
    {
        "key": "ctrl+l",
        "command": "python.datascience.removeallcells",
        "when": "python.datascience.featureenabled && !terminalFocus"
    },
    {
        "key": "ctrl+l",
        "command": "workbench.action.terminal.clear",
        "when": "terminalFocus"
    },    
    {
        "key": "cmd+shift+f10",
        "command": "python.datascience.restartkernel"
    },
    {
        "key": "cmd+shift+c",
        "command": "editor.action.commentLine",
        "when": "editorTextFocus && !editorReadonly"
    },
    {
        "key": "cmd+/",
        "command": "-editor.action.commentLine",
        "when": "editorTextFocus && !editorReadonly"
    },
    {
        "key": "cmd+i",
        "command": "python.datascience.showhistorypane"
    },
    {
        "key": "ctrl+shift+/",
        "command": "rewrap.rewrapComment",
        "when": "editorTextFocus"
    },
    {
        "key": "alt+q",
        "command": "-rewrap.rewrapComment",
        "when": "editorTextFocus"
    },
    {
        "key": "ctrl+shift+s",
        "command": "extension.updateSettings"
    },
    {
        "key": "shift+alt+u",
        "command": "-extension.updateSettings"
    }
]

Extensions Installation Script

You can run each of the lines below in your Terminal or other Command Prompt
after installing VS Code in order to install the extensions. Or you can search
for them in the VS Code Marketplace (more detail is available here:
https://code.visualstudio.com/docs/editor/extension-gallery#_browse-for-extensions)

# editor visual aids
code --install-extension CoenraadS.bracket-pair-colorizer-2
code --install-extension oderwat.indent-rainbow
code --install-extension gerane.Theme-textmate

# development aids
code --install-extension eamodio.gitlens
code --install-extension aaron-bond.better-comments
code --install-extension Gruntfuggly.todo-tree
code --install-extension mikestead.dotenv
code --install-extension streetsidesoftware.code-spell-checker

# code formatting
code --install-extension ms-python.python
code --install-extension VisualStudioExptTeam.vscodeintellicode
code --install-extension TabNine.tabnine-vscode
code --install-extension christian-kohler.path-intellisense
code --install-extension stkb.rewrap
code --install-extension SonarSource.sonarlint-vscode

# file viewer tools
code --install-extension DotJoshJohnson.xml
code --install-extension jithurjacob.nbpreviewer
code --install-extension GrapeCity.gc-excelviewer

# remote development tools
code --install-extension ms-azuretools.vscode-docker
code --install-extension ms-vscode-remote.remote-containers
code --install-extension ms-vscode-remote.remote-ssh
code --install-extension ms-vscode-remote.remote-ssh-edit
code --install-extension ms-vscode-remote.remote-wsl
code --install-extension ms-vscode-remote.vscode-remote-extensionpack

# tool to save your settings as a gist
code --install-extension Shan.code-settings-sync

To leave a comment for the author, please follow the link and comment on their blog: stevenmortimer.com.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)