This is the best calculator you will ever use because it packs the Python ecosystem into a fast and familiar user interface. This project is an experiment to see what happens when you wrap a Python interpreter in an RPN calculator interface. The result is a fast way to interact with Python through familiar calculator controls.
I spent years using the Python terminal, Spyder, and now Jupyter notebooks. While each has its strengths, none offers the simplicity or immediacy of a good old-fashioned calculator when working through math problems. But a traditional calculator lacks the history and explanations of a Jupyter notebook and the power and vast catalog of tools available in Python. Why not combine their strengths in one app?
So this project was born and has become a go-to tool for daily engineering math and quick Python scripting.
-
Feature-rich RPN calculator with user functions, variables, plotting, and history.
-
Novel RPN-style interface for interacting with a live Python interpreter
-
Built-in support for the math, NumPy, and Matplotlib libraries
-
Import Python modules and use their functions in the calculator
-
Customizable Tkinter/ttk interface with stack, variable, and user function views
-
Support for copying and pasting between Excel and the calculator
-
Session history with undo and redo
-
Store variables of any type, including numbers, arrays, functions, class instances, and more
-
Save and restore sessions and state; restore the last state on launch by default
-
Dark and light themes that follow the system theme
What makes this program different from other calculators and IDEs is its ability to interact with Python
objects in an RPN-style stack. For example, as shown in the first picture, if you have a NumPy array at
stack position 0 and an integer at stack position 1, pressing * multiplies the array by the integer
and puts the result at stack position 0.
The new app builder packages PyCalc as a desktop application with its own icon.
On macOS, it creates PyCalc.app, which can be opened from Finder without launching Python manually.
A Launching PyCalc… popup provides feedback while the calculator starts, and Matplotlib loads only
when plotting is needed. The builder clears previous build outputs automatically to avoid stale copies.
See Building the desktop app below for instructions.
Navigate to Functions -> Edit User Functions to see all user functions in memory, edit them in a text editor, and save changes. Buttons let you load a function onto the stack or run it directly from the popup. You can also edit user functions in the IDLE editor.
Search: Use this field to find text in the user function names.
Save Changes: Saves the changes currently shown in the text editor.
To Stack: Puts the function onto the stack so that you can enter arguments by typing them in.
Run: Runs the function directly using the current stack values and saved variables.
You can now load any library on launch.
Navigate to File -> Load Python Module and enter the name of an installed Python module or a local module, as shown above. Any module on the list will be loaded the next time the calculator launches. You can also use this window to load modules while the calculator is running. The list of modules to load is saved with the calculator state.
You can run PyCalc from source using Python and your terminal or IDE, or build a desktop application using the instructions below. Python is required to run from source and to build the app; the packaged app includes its Python runtime.
-
Download the repository.
-
In Terminal on macOS or Linux, or PowerShell on Windows, navigate to the directory containing
main.py. -
Run
python main.pyusing a Python environment with NumPy, Matplotlib, and Tkinter available. -
The calculator UI will open. See Prepare the environment for setup instructions.
The UI behaves like an RPN calculator. If you prefer infix notation, as used on a regular calculator,
wrap your expression in parentheses, for example: (sin(40.2 + pi) + 1.42/24). Press Enter to
evaluate the expression and display the result in the stack view and message window.
-
You don't need buttons to use math functions. For example, to calculate nCr(5, 3), type 5, Enter, 3, Enter, ncr, Enter. The result appears on the stack. You can also type
ncr(5, 3)and press Enter. See the Python math library reference for available functions. -
PyCalc follows calculator notation:
lnis the natural logarithm andlogis base 10. The calculator'slogwrapper accepts one argument, solog(3, 10)raises an error. Usemath.log(3, 10)to specify a base explicitly.
-
Press: 1
-
Press Enter in the UI or on the keyboard.
-
Press: 2
-
Press: +
-
The result,
3, appears in stack position X.
-
Press: 2
-
Press: enter
-
Press log, or type
logand press Enter. -
The result of
log(2), approximately0.30103, appears in stack position X.
-
Press: 2
-
Press: enter
-
Type: my_var=
-
Press: enter
-
The value
2is stored asmy_varand appears in the variable view.
-
Enter
(1+1). The parentheses identify it as a math expression. -
Press Enter to evaluate the expression and display
2in the stack view.
Any expression can use saved variables. For example, with a value assigned to y, try
(sin(pi)/cos(y) + log(5.3*7)).
You can create Python objects directly on the stack and pass them to NumPy functions:
-
Enter
[sin(x/3) for x in range(200)]and press Enter to create a list of 200 values. -
Enter
np.arrayand press Enter to convert the list to a NumPy array. -
Enter
np.tanand press Enter to apply the tangent function to the array. -
Enter
a=and press Enter to store the result in the variablea. -
Enter
np.mean(a)and press Enter to calculate its mean.
You can also copy values from Excel or Google Sheets and paste them directly into the calculator. The calculator converts the pasted selection to a list on the stack.
The calculator uses Matplotlib to plot data.
-
Enter: [10, 7, 4, 2, 7, 4, 9, 0, 1, -3]
-
Press: enter -- this will evaluate the value on the stack to a list
-
Press: plot -- this will plot the list using Matplotlib and display the plot in a new window
You can copy rows and columns from Excel or Google Sheets and paste them directly into the calculator.
You can define custom Y, XY, and XYZ plots from the plot menu. Lists and arrays stored as variables appear in the plot dialogs' dropdown menus, with their lengths shown in parentheses. Select X and Y variables of the same length to plot Y against X. Use Add Plot to add traces to the same graph. Give each trace a unique name; reusing a name overwrites the existing trace.
You can also call Matplotlib directly:
-
Enter
np.linspace(0, 10, 100)and press Enter to create 100 evenly spaced points from 0 to 10. -
Enter
x=and press Enter to store the array asx. -
Enter
np.sin(x/7)and press Enter. -
Enter
a=and press Enter to store the sine values asa. -
Enter
np.cos(x/5)and press Enter. -
Enter
b=and press Enter to store the cosine values asb. -
Enter
plt.plot(a, b, "r-")and press Enter to plotbagainstawith a red line. -
Enter
plt.show()and press Enter to display the plot.
On launch, the calculator imports:
import math as math
import numpy as npMatplotlib's pyplot interface is available as plt and loads when you first use it. You can call
library functions by typing expressions such as np.sin([1, 2, 3, 4, 5]) and pressing Enter.
To use another installed library, import it from the stack:
-
Enter
import randomand press Enter. -
Enter
random.randint(1, 100)and press Enter to generate a random integer.
For a function that takes one argument, you can enter the function name alone to apply it to the value on the stack:
-
Enter
[1, 2, 3, 4, 5]and press Enter. -
Enter
sumand press Enter to calculate the sum of the list.
For functions that take multiple arguments, include the arguments in the expression, as in
random.randint(1, 100).
You can define your own functions and save them with the calculator session.
-
Navigate to Functions -> Add User Functions.
-
In the dialog that appears, enter the function using standard Python syntax and indentation. For example:
def sqr_x(x): return x**2
-
Press OK to add the function to the calculator.
User functions can use variables saved in the calculator. For example, this function calculates the output voltage of a resistor divider:
def voltage_divider(Vin):
Vout = Vin * (R2 / (R1 + R2))
return VoutHere, R1 and R2 are variables saved in the calculator. A function with one argument, Vin in this
case, is convenient for applying the function to a number or array on the stack. Other values can be
defined inside the function or saved as calculator variables.
To reproduce the example below, define voltage_divider and save values for R1 and R2. Enter
np.arange(0, 12) and press Enter, then enter x= and press Enter to save the array as x.
With the array in stack position X, open Options -> Function Buttons and click voltage_divider.
The function puts the calculated output voltages on the stack. Press Plot to display them.
You can also enter voltage_divider(x) directly and press Enter.
- Navigate to View -> Show User Functions.
-
Navigate to Options -> Remove Function.
-
Select a function from the list and press Remove.
Use Functions -> Edit User Functions to view and edit functions in memory. Select a function to load it into the text editor. Click Save Changes to save your edits or Cancel to revert them. The To Stack and Run buttons provide two ways to use a function:
- To Stack loads the function into stack position X so you can type arguments and press Enter.
- Run evaluates the selected function using values from stack positions X, Y, Z, and so on, plus saved variables as needed.
Use the Options menu to change calculator settings:
- Save State on Exit saves the current session when you quit. Turn it off to start with a fresh session.
- Edit plot format string sets the plot format. See the fmt parameter in the Matplotlib plot reference.
- Edit numeric display format sets the format for integers and floating-point numbers. See this formatting cheat sheet. Select Use Engineering Notation to display floats with exponents that are multiples of 3. Number of digits shown controls the displayed precision.
Use the View menu to control the visibility and appearance of the calculator views:
- Show Message Field -- toggles the message field visibility
- Show Variable Viewer -- toggles the variable viewer visibility
- Show User Functions -- toggles the user functions window visibility
- Standard View -- shows all buttons, the message field, the variable viewer and the stack.
- Mini View -- shows only the stack view and sets the number of stack rows to 2.
- Set Number of Stack Rows -- opens a dialog to set the number of stack, variable and message rows to show in the UI.
- Set Font parameters -- opens a dialog to set the font family and size for the stack, variable viewer and message field.
- Edit numeric display format -- opens a dialog to set the numeric display format (see above section on User Options)
Mini View is shown above with the message field and stack view.
By default, the calculator saves its state on exit and restores it on launch. The state is saved as
last_state_autosave.pycalc in the working directory. It includes the stack, history, variables, and
calculator settings.
To save a session:
-
With values on the stack or in variables, press Ctrl+S or select File -> Save.
-
Choose a location and filename, then press Save.
To restore a session:
-
Press Ctrl+O or select File -> Open.
-
Select the session file and press Open.
To use the calculator without the UI, import calc.py and create a Calculator instance:
import calc
c = calc.Calculator()
ue = c.user_entry
ue('sin(43.7) + 17.3')
ue('enter')
# Evaluated: sin(43.7) + 17.3 to 17.0214373937804
c.return_stack_for_display()
# [17.0214373937804]The calculator is designed to support a UI but also works from the command line. It accepts input one
character at a time, so you can also enter sin(3) like this:
ue('s')
ue('i')
ue('n')
ue('(')
ue('3')
ue(')')
c.enter_press()
# Evaluated: sin(3) to 0.1411200080598672This lets another user interface send keyboard events directly to the calculator. If you already have a calculator UI, you can use PyCalc as its backend. I'm looking at you, Flutter and JavaScript developers!
The builder uses PyInstaller and has been tested on macOS with Python 3.13. Build on the operating system you intend to run the app on; a macOS build does not produce a Windows executable.
Open a terminal in the repository directory. On macOS, create and activate a virtual environment:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install numpy matplotlib pyinstaller pillow pystrayUse a Python installation with Tkinter support. You can check it with python -m tkinter, which should
open a small test window. In PyCharm, select the same environment as the project interpreter before
running the builder.
On Windows PowerShell, create the environment with python -m venv .venv, activate it with
.\.venv\Scripts\Activate.ps1, and install the same packages.
Quit any running copy of PyCalc, then run:
python pyinstaller_script.pyAlternatively, right-click pyinstaller_script.py in PyCharm and select Run 'pyinstaller_script'.
Wait for the build to finish successfully before opening the app.
On macOS, double-click dist/PyCalc.app in Finder or run this from the repository directory:
open dist/PyCalc.appYou can copy PyCalc.app to Applications. If you keep a copy there, replace it after rebuilding;
the builder only updates the copy in this repository. On Windows, launch dist/PyCalc/PyCalc.exe
and keep the entire dist/PyCalc directory together with its dependencies.
The builder uses --onedir to avoid extracting dependencies at every launch. Before each build, it
removes generated PyCalc and former main outputs from build/ and dist/, plus their generated
.spec files. After a successful build, it removes intermediate files and, on macOS, the duplicate
dist/PyCalc directory, leaving dist/PyCalc.app and the generated PyCalc.spec.
The window icon and macOS app icon come from media/pycalc_icon_a.png. The Windows executable icon
comes from media/pycalc_icon_a.ico. To change the icons, replace these images and rebuild.
The PNG is bundled automatically so the window icon also works in the packaged app.
One of the goals I had for this project was to explore the use of Tkinter. I have used various other software packages to create UIs, and I wanted to give Tkinter a turn. So far, Tkinter has been fast and easy to work with.
It has taken me about twice as long to write this README as it took to write the code itself, but the process has been useful because I found a few bugs along the way.







