Jupyter Notebook vs PyCharm for Matplotlib: When to Use Each for Visualization
Problem
When I started learning matplotlib, I worked in PyCharm. Every time I wanted to adjust a plot, I had to edit my script, save the file, and run the entire thing again. The workflow felt slow. Then I saw tutorials using Jupyter Notebook, where plots appeared inline and could be tweaked by re-running single cells. I wondered: should I switch to Jupyter? What am I missing?
Environment
- Python 3.11
- matplotlib 3.8.0
- PyCharm Professional 2023.3
- Jupyter Notebook 7.0.0
- macOS 14.0
What happened?
I was creating visualizations for a dataset, tweaking figure sizes, colors, and labels repeatedly. In PyCharm, my workflow looked like this:
import matplotlib.pyplot as pltimport numpy as np
# Generate datax = np.linspace(0, 10, 100)y = np.sin(x)
# Create plotplt.figure(figsize=(10, 6))plt.plot(x, y, linewidth=2)plt.title('Sine Wave')plt.xlabel('X')plt.ylabel('sin(X)')plt.grid(True)plt.show()Every change meant editing the file, saving, and running python visualize.py again. The plot opened in a separate window. If I wanted to try figsize=(12, 8) or change the line width to 3, I had to repeat the entire cycle.
Then I tried the same thing in Jupyter:
%matplotlib inlineimport matplotlib.pyplot as pltimport numpy as np
x = np.linspace(0, 10, 100)y = np.sin(x)
plt.figure(figsize=(10, 6))plt.plot(x, y, linewidth=2)plt.title('Sine Wave')plt.xlabel('X')plt.ylabel('sin(X)')plt.grid(True)plt.show()The plot appeared right below the code cell. When I changed figsize to (12, 8), I only re-ran that one cell. The plot updated instantly.
The key difference
I realized the difference isn’t about which tool is “better.” It’s about the workflow.
Jupyter’s cell-based approach:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│ Cell 1: Setup │ → │ Cell 2: Plot │ → │ Cell 3: Adjust ││ (imports, │ │ (figure, │ │ (tweak params, ││ data load) │ │ plot) │ │ re-run only) │└─────────────────┘ └─────────────────┘ └─────────────────┘You run cells independently. If you load data once in Cell 1, you can tweak the plot in Cell 2 or Cell 3 without re-loading data. The visual feedback loop is tight.
PyCharm’s script-based approach:
Edit script → Save → Run entire file → View plot → RepeatYou run the whole file every time. This is slower for experimentation but better for production code where you want reproducibility and version control.
Inline plotting in Jupyter
I found two magic commands that change how plots display:
%matplotlib inline (default in most notebooks):
%matplotlib inline
import matplotlib.pyplot as pltimport numpy as np
x = np.linspace(0, 10, 100)y = np.sin(x)
plt.figure(figsize=(10, 6))plt.plot(x, y, linewidth=2)plt.show()This creates static PNG images embedded in the notebook. You can’t zoom or pan, but the plots are portable and work in GitHub repos.
%matplotlib widget (interactive):
%matplotlib widgetimport matplotlib.pyplot as pltimport numpy as np
def plot_wave(frequency=1, amplitude=1): x = np.linspace(0, 4*np.pi, 500) y = amplitude * np.sin(frequency * x)
plt.figure(figsize=(10, 6)) plt.plot(x, y) plt.title(f'Wave: freq={frequency}, amp={amplitude}') plt.grid(True) plt.show()
from ipywidgets import interactinteract(plot_wave, frequency=(1, 10, 0.5), amplitude=(1, 5, 0.5))This creates an interactive plot with zoom, pan, and save buttons. You can add sliders with ipywidgets to adjust parameters dynamically. This is powerful for exploration but requires more setup and doesn’t work well when exported to static formats.
I tried widget mode first. The interactivity was great, but the plots didn’t render when I exported my notebook to PDF or viewed it on GitHub. I switched back to inline for portability.
PyCharm’s scientific mode
I assumed I had to choose between Jupyter and PyCharm. I was wrong.
PyCharm Professional has built-in Jupyter notebook support. You can open .ipynb files directly, and cells execute just like in the browser. You get the same inline plots with the advantage of PyCharm’s debugger and version control.
PyCharm also has “Scientific Mode.” When enabled, plots appear in a “SciView” tool window instead of popping up separately. Here’s how it works:
import matplotlib.pyplot as pltimport numpy as np
# Right-click and choose "Show Plot in Tool Window"data = np.random.randn(1000)plt.hist(data, bins=30, edgecolor='black')plt.title('Distribution')plt.show()When you run this in PyCharm with Scientific Mode, the plot stays docked in the IDE. You can hover over data points to see values, zoom, and pan. It’s not as interactive as Jupyter’s widget mode, but it’s close.
I tried Scientific Mode for a week. The workflow was still script-based (run the whole file), but having plots integrated into the IDE helped. I didn’t have to switch windows as often.
When to use each tool
After using both for several months, I formed a clear rule:
Use Jupyter when:
- You’re exploring a new dataset and don’t know what visualizations you need yet
- You’re creating tutorials or teaching material where narrative + code matters
- You need to present results to non-programmers who can read Markdown but not code
- You want interactive plots with sliders or dropdowns
- You’re prototyping visualizations and will iterate frequently
Use PyCharm/VS Code when:
- You’re building a production application or library
- The visualization code is part of a larger system
- You need advanced debugging (breakpoints, step-through)
- Version control and code review are critical
- You’re working with multiple files and modules
- You want to run automated tests on your plotting code
My recommended workflow
I found that a hybrid approach works best:
Phase 1: Exploration in Jupyter
I start in Jupyter. I load data, try different plots, and adjust parameters rapidly. I use %matplotlib inline so the notebook is portable. I document my findings in Markdown cells between code cells.
Phase 2: Extract to functions
Once I find a visualization that works, I extract the plotting code into a function:
import matplotlib.pyplot as pltimport numpy as np
def create_comparison_plot(data, title, figsize=(10, 6)): """Create standardized comparison plot.""" fig, ax = plt.subplots(figsize=figsize) ax.plot(data['x'], data['y'], linewidth=2) ax.set_title(title) ax.set_xlabel('X') ax.set_ylabel('Y') ax.grid(True) return figPhase 3: Develop in IDE
I move the function to a .py file and develop in PyCharm. I add tests:
import matplotlib.pyplot as pltfrom viz_utils import create_comparison_plot
def test_create_comparison_plot(): data = {'x': [1, 2, 3], 'y': [1, 4, 9]} fig = create_comparison_plot(data, 'Test Plot') assert isinstance(fig, plt.Figure) plt.close(fig)Now the visualization is part of my production codebase. I can import it elsewhere, version it, and refactor it safely.
What I tried that didn’t work
I tried skipping Phase 1 and going straight to PyCharm. I spent too time running scripts repeatedly for minor tweaks. The friction made me lazy—I stopped experimenting as much.
I also tried staying in Jupyter for everything. My notebooks became messy. I couldn’t easily reuse plotting code across projects. Version control was painful because .ipynb files contain output and metadata that changes frequently.
The hybrid workflow solved both problems.
The reason
The key insight is that exploration and production require different tools. Jupyter optimizes for rapid iteration at the cost of structure. IDEs optimize for structure and maintainability at the cost of iteration speed.
Data science is inherently exploratory. You don’t know what visualizations you need until you try them. Jupyter’s cell-based execution matches this workflow.
But once you’ve found what works, you need to turn that insight into maintainable code. IDEs with proper modules, tests, and version control are better for that.
Summary
In this post, I compared Jupyter Notebook and PyCharm for matplotlib visualization work. I showed that Jupyter excels at exploration with its cell-based workflow and inline plots, while PyCharm is better for production code with its testing and debugging tools. The key point is that you don’t have to choose—use Jupyter for experimentation, then extract working code to .py files and develop in your IDE.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments