How I Created a 5-in-1 Calculator App using Streamlit

5/5 - (1 vote)

Welcome to another interesting project. In this tutorial, I will show you how I created a 5-1 calculator app using Streamlit and deployed it on Streamlit Cloud.

๐Ÿ‘‰ In my tutorial on creating a readability checker app, I told you guys that Streamlit can be used to create virtually anything within its capabilities.

Project Description

Today, letโ€™s learn how to use it to create a 5-1 calculator app. This calculator is not just an ordinary calculator and neither is it a sophisticated one. Itโ€™s a calculator with 5 features:

  • basic math operation,
  • age calculator,
  • loan calculator,
  • statistics, and
  • simultaneous equation solver.

You can try the app for real:

๐Ÿ‘‰ Live App: Check out the live app here!

The purpose of this tutorial is threefold.

  1. To demonstrate the capabilities of Streamlit.
  2. To explain how Python, including its functions, works.
  3. To give you a project idea that you can implement in your projects and thus increase your portfolio.

Certain things are best understood when seen in action.

Hence, I will create a video tutorial for this project to help you understand what you may find difficult to grab in this article. The video is also an aid to understanding certain things which I may not explain here due to the limited time we all have to deal with our busy schedules.

So, you do well to check the video when itโ€™s released.

Getting Started

I started creating this calculator app by wrapping a set of options in the main() function displayed as a sidebar. These options are the five features that make up this app.

import streamlit as st
def main():
    option = st.sidebar.selectbox('What do you want to calculate?', ['Basic Maths', 'loan', 'Age', 'Statistics','Simultaneous Equation'])
    if option == 'Basic Maths':
        basic_maths()
    elif option == 'loan':
        loan()
    elif option == 'Age':
        get_age()
    elif option == 'Statistics':
        stats()
    else:
        simultaneous()

if __name__ == '__main__':
    main()

When selected, a callback function is executed. Some callback functions have other function(s) called, thus making the simple app look more complicated, especially for beginners.

This is why I made the video to show you how to reduce the complexity. The code ended with the __nameยญยญ__ย  variable that enables the main() function to execute immediately after the app is opened, without which it will not run since the code is wrapped in a function.

Basic Math

When Basic Maths is selected, the basic_maths() function is called.

def basic_maths():
    st.header('Basic Maths Operation')
    num1 = st.number_input('Enter a number', value=20)
    num2 = st.number_input('Enter another number', value=5)
    operation = st.radio('Select an operation', ['Add', 'Subtract', 'Multiply', 'Divide'])
    button = st.button('Calculate')
    if button:
        calc_maths(operation, num1, num2)

This function is responsible for performing basic mathematics operations. It has a radio button to choose which operation you want to perform. When the calculate button is pressed, another function is called.

def calc_maths(op, num1, num2):
    result = 0
    if op == 'Add':
        result = num1 + num2
    elif op == 'Subtract':
        result = num1 - num2
    elif op == 'Multiply':
        result = num1 * num2
    elif op == 'Divide':
        result = num1 / num2
    else:
        st.warning('Division by 0 error, please enter a non_zero number.')
        res = 'Undefined'

    st.success(f'Result = {result}') 

This function does the calculation and displays the result.

We also warn when our users try to divide with a zero number.

Notice the different parameters passed to the calc_maths() function. As long as it is a local variable, it is only recognized in its function. Python will treat them differently.

Loan Calculator

Next is the loan() function, which will be run when called.

import streamlit as st
from math import pow


def loan():
    st.header('Loan Calculator')
    principal = st.number_input('Enter loan amount', value=100000)
    interest = st.number_input('Enter the interest rate (%)', value=7.5)
    years = st.number_input('Enter the loan duration in years', value=30)
    button = st.button('Calculate')
    monthly_payment = calc_loan(principal, interest, years)
    total_amount = monthly_payment * years * 12

    res = f'Amount = ${principal}  \
          \nYears = {years} years \
           \nInterest = {interest}% \
          \nMonthly payment =  ${round(monthly_payment, 2)} \
           \n------------------------------------- \
           \nTotal amount to be paid = ${round(total_amount, 2)}'

    if button:
        st.text(res)

So, when our users fill in the required details and click the button, they get their monthly loan repayment plus the total amount to be paid. Itโ€™s as simple as that.

Age Calculator

This feature will tell you how old you are once you fill in the required information, that is, your date of birth.

from datetime import date
import streamlit as st


def get_age():
    st.header('Age Calculator')
    year = st.number_input('Year of Birth', value=1994)
    month = st.number_input('Month of Birth', value=3)
    day = st.number_input('Date of Birth', value=30)
    dob = date(year, month, day)
    today = date.today()
    age = today.year - dob.year - ((today.month, today.day) <
          (dob.month, dob.day))
    button = st.button('Check')
    if button:
        st.text(f'You are {age} years old') 

We use the date function from the datetime module to transform the input details into a DateTime object. We then compare your month and day of birth with the current date. The result is a Boolean.

If the current date is less than your date of birth, it becomes dob.year โ€“ 0 or dob.year โ€“ 1 if it is more.

This ensures it doesnโ€™t add 1 to your age if you havenโ€™t passed the exact month and day you were born. If it isnโ€™t clear, watch the video to see how I demonstrated it in a Python shell.

Statistics

This section demands a thorough explanation. You do well to give me your undivided attention so you can grasp what I did.

import streamlit as st
from statistics import mean, median, mode
import altair as alt
import re
from itertools import repeat
import pandas as pd



def stats():
    st.header('Statistics')
    numbs_only = lambda x: [int(i) for i in re.split('[^0-9]', x) if i != '']
    num = st.text_input('Please enter numbers')
    freq = st.text_input('Please enter frequency')
    x = numbs_only(num)
    y = numbs_only(freq)
    if len(x) != len(y):
        st.error('The numbers should be of equal length')
        return None
    list_merged = flatten(x, y)
    op = st.radio('Select an operation', ['mean', 'median', 'mode', 'bar chart', 'line chart', 'area chart'])
   button = st.button('Calculate')
    df = pd.DataFrame({'Number': x, 'Frequency': y})
    if button:
        if op == 'mean':
            result = mean(list_merged)
            st.text(f'Mean = {round(result, 2)}')
        elif op == 'median': 
            st.text(f'Median = {median(list_merged)}')
        elif op == 'mode':
            st.text(f'Mode = {mode(list_merged)}')
        elif op == 'bar chart':
            bar = alt.Chart(df).mark_bar().encode(
                 y = 'Frequency',
                 x = 'Number'
            )
            st.altair_chart(bar, use_container_width=True)
        elif op == 'line chart':
            st.line_chart(df)
        else: 
            st.area_chart(df)

If our users select statistics from the main() function, the above function will be executed.

I made this so that our users will compute the mean, median, and mode of a grouped data. That is, a set of numbers with a frequency. Streamlit does not have a method that accepts a list of numbers.

As a workaround, we created a lambda function that uses a regular expression to filter out the spaces or letters and accepts only numbers.

We then prompt the user to verify that the length of the two sets of numbers is equal. Then comes another problem.

There is no function to help us compute the mean, mode and, median of data that comes with a frequency. Not even from Pandas or NumPy. One of the things that make one a good programmer is to learn to find a workaround when you happen to hit a dead end.

So, I created the flatten() function that does the heavy lifting for me.

def flatten(x, freq):
    res = []
    for i in zip(x, freq):
        res.append(list(repeat(i[0], i[1])))
    res = [i for k in res for i in k]
    return res

Remember, the frequency indicates how many times the numbers appeared.

This simple function does the job perfectly using the repeat() function from the itertools module. The number and frequency were combined using the zip() function.

Then, in each iteration, we use repeat() to repeat each number(i[0]) according to the frequency(i[1]). We then flatten it using list comprehension.

The result is now a single set of numbers. We then save it in the list_merged variable.

In this statistics calculator, we also gave our users several options to choose from. If they choose the mean, it gets calculated. If they select the bar chart, a bar chart is displayed.

This nicely constructed bar chart was made possible using the altair module. Visit the documentation to understand how it works.

Simultaneous Equation

The simultaneous equation is fairly easy to code. The simultaneous() function that gets executed when called gives our users the option to solve 2 or 3 unknowns variables.

def simultaneous():
    st.header('Simultaneous Equation')
    num = st.radio('Number of unknowns', [2, 3])
    if num == 2:
        simul_2_eqn()
    else:
        simul_3_eqn()

When a choice is made from the radio button, a callback function is called.

def simul_2_eqn():
    left, right = st.columns((2, 2))
    num1 = left.number_input('Enter the first number', value=1)
    num2 = right.number_input('Enter the second number', value=6)
    num3 = left.number_input('Enter the first equal number', value=3)
    num4 = right.number_input('Enter the third number', value=1)
    num5 = left.number_input('Enter the fourth number', value=1)
    num6 = right.number_input('Enter the second equal number', value=-2)
    button = st.button('Solve')
    if button:
        solver(num1, num2, num3, num4, num5, num6)


The simul_2_eqn() function uses st.number_input for our users to input the numbers of the simultaneous equation. Once the solve button is clicked, another function is called.

def solver(num1, num2, num3, num4, num5, num6):
    for x in range(-100, 100):
        for y in range(-50, 50):
            if (num1 * x) + (num2 * y) == num3 and (num4 * x) + (num5 * y) == num6:
                st.text(f'x = {x} \
                        \ny = {y}') 

The solver() function loops through two sets of numbers in a given range. In each iteration, it checks the numbers (x and y) that marched the given condition. Once found, it displays the result using st.text. As simple as that.

We did the same when solving for 3 unknowns. Check my GitHub page for the full code.

The drawback of the simultaneous equation calculator is that in some cases, it doesnโ€™t display the result. For two reasons:

  1. The simultaneous equation cannot be solved.
  2. If the answer is a float, it will not be displayed.

Conclusion

We have created a 5-1 calculator app in just a few lines of code using Streamlit. Imagine if we were to design all these using frontend web development tools, it may take hundreds of lines of code to design. Thanks to Streamlit, everything was reduced and simplified.

No doubt, you have learned something useful today. There are other calculator apps you can add or create separately. We have a fitness calculator and an exchange calculator. Feel free to design them and improve your programming skills.

Stay safe and have a wonderful day. โ™ฅ๏ธ

๐Ÿ‘‰ Recommended: I Made a Password Generator in Streamlit Thatโ€™s Really Secure (Maybe Too Secure!)