3 changed files with 251 additions and 44 deletions
			
			
		@ -0,0 +1,148 @@ | 
				
			|||
 | 
				
			|||
# Created by https://www.toptal.com/developers/gitignore/api/python | 
				
			|||
# Edit at https://www.toptal.com/developers/gitignore?templates=python | 
				
			|||
 | 
				
			|||
### Python ### | 
				
			|||
# Byte-compiled / optimized / DLL files | 
				
			|||
__pycache__/ | 
				
			|||
*.py[cod] | 
				
			|||
*$py.class | 
				
			|||
 | 
				
			|||
# C extensions | 
				
			|||
*.so | 
				
			|||
 | 
				
			|||
# Distribution / packaging | 
				
			|||
.Python | 
				
			|||
build/ | 
				
			|||
develop-eggs/ | 
				
			|||
dist/ | 
				
			|||
downloads/ | 
				
			|||
eggs/ | 
				
			|||
.eggs/ | 
				
			|||
lib/ | 
				
			|||
lib64/ | 
				
			|||
parts/ | 
				
			|||
sdist/ | 
				
			|||
var/ | 
				
			|||
wheels/ | 
				
			|||
share/python-wheels/ | 
				
			|||
*.egg-info/ | 
				
			|||
.installed.cfg | 
				
			|||
*.egg | 
				
			|||
MANIFEST | 
				
			|||
 | 
				
			|||
# PyInstaller | 
				
			|||
#  Usually these files are written by a python script from a template | 
				
			|||
#  before PyInstaller builds the exe, so as to inject date/other infos into it. | 
				
			|||
*.manifest | 
				
			|||
*.spec | 
				
			|||
 | 
				
			|||
# Installer logs | 
				
			|||
pip-log.txt | 
				
			|||
pip-delete-this-directory.txt | 
				
			|||
 | 
				
			|||
# Unit test / coverage reports | 
				
			|||
htmlcov/ | 
				
			|||
.tox/ | 
				
			|||
.nox/ | 
				
			|||
.coverage | 
				
			|||
.coverage.* | 
				
			|||
.cache | 
				
			|||
nosetests.xml | 
				
			|||
coverage.xml | 
				
			|||
*.cover | 
				
			|||
*.py,cover | 
				
			|||
.hypothesis/ | 
				
			|||
.pytest_cache/ | 
				
			|||
cover/ | 
				
			|||
 | 
				
			|||
# Translations | 
				
			|||
*.mo | 
				
			|||
*.pot | 
				
			|||
 | 
				
			|||
# Django stuff: | 
				
			|||
*.log | 
				
			|||
local_settings.py | 
				
			|||
db.sqlite3 | 
				
			|||
db.sqlite3-journal | 
				
			|||
 | 
				
			|||
# Flask stuff: | 
				
			|||
instance/ | 
				
			|||
.webassets-cache | 
				
			|||
 | 
				
			|||
# Scrapy stuff: | 
				
			|||
.scrapy | 
				
			|||
 | 
				
			|||
# Sphinx documentation | 
				
			|||
docs/_build/ | 
				
			|||
 | 
				
			|||
# PyBuilder | 
				
			|||
.pybuilder/ | 
				
			|||
target/ | 
				
			|||
 | 
				
			|||
# Jupyter Notebook | 
				
			|||
.ipynb_checkpoints | 
				
			|||
 | 
				
			|||
# IPython | 
				
			|||
profile_default/ | 
				
			|||
ipython_config.py | 
				
			|||
 | 
				
			|||
# pyenv | 
				
			|||
#   For a library or package, you might want to ignore these files since the code is | 
				
			|||
#   intended to run in multiple environments; otherwise, check them in: | 
				
			|||
# .python-version | 
				
			|||
 | 
				
			|||
# pipenv | 
				
			|||
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | 
				
			|||
#   However, in case of collaboration, if having platform-specific dependencies or dependencies | 
				
			|||
#   having no cross-platform support, pipenv may install dependencies that don't work, or not | 
				
			|||
#   install all needed dependencies. | 
				
			|||
#Pipfile.lock | 
				
			|||
 | 
				
			|||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow | 
				
			|||
__pypackages__/ | 
				
			|||
 | 
				
			|||
# Celery stuff | 
				
			|||
celerybeat-schedule | 
				
			|||
celerybeat.pid | 
				
			|||
 | 
				
			|||
# SageMath parsed files | 
				
			|||
*.sage.py | 
				
			|||
 | 
				
			|||
# Environments | 
				
			|||
.env | 
				
			|||
.venv | 
				
			|||
env/ | 
				
			|||
venv/ | 
				
			|||
ENV/ | 
				
			|||
env.bak/ | 
				
			|||
venv.bak/ | 
				
			|||
 | 
				
			|||
# Spyder project settings | 
				
			|||
.spyderproject | 
				
			|||
.spyproject | 
				
			|||
 | 
				
			|||
# Rope project settings | 
				
			|||
.ropeproject | 
				
			|||
 | 
				
			|||
# mkdocs documentation | 
				
			|||
/site | 
				
			|||
 | 
				
			|||
# mypy | 
				
			|||
.mypy_cache/ | 
				
			|||
.dmypy.json | 
				
			|||
dmypy.json | 
				
			|||
 | 
				
			|||
# Pyre type checker | 
				
			|||
.pyre/ | 
				
			|||
 | 
				
			|||
# pytype static type analyzer | 
				
			|||
.pytype/ | 
				
			|||
 | 
				
			|||
# Cython debug symbols | 
				
			|||
cython_debug/ | 
				
			|||
 | 
				
			|||
# End of https://www.toptal.com/developers/gitignore/api/python | 
				
			|||
 | 
				
			|||
*.swp | 
				
			|||
 | 
				
			|||
@ -1,44 +1,103 @@ | 
				
			|||
import matplotlib.pyplot as plt | 
				
			|||
import numpy as np | 
				
			|||
import json | 
				
			|||
import sys | 
				
			|||
import argparse | 
				
			|||
__author__ = 'm3x1m0m' | 
				
			|||
 | 
				
			|||
with open("ecar.json", "r") as rf: | 
				
			|||
    settings = json.load(rf) | 
				
			|||
class c_settings_extractor: | 
				
			|||
    def __init__(self, fname): | 
				
			|||
        with open(fname, "r") as rf: | 
				
			|||
            settings = json.load(rf) | 
				
			|||
            kilometer_price_ccar = settings["ccar"]["litres_per_kilometer"] * settings["petrol_litre_price"] | 
				
			|||
            self.labels = [settings["ecar"]["label"], settings["ccar"]["label"]] | 
				
			|||
            self.purchase = np.array([settings["ecar"]["price"], settings["ccar"]["price"]]) | 
				
			|||
            self.taxes = np.array([settings["ecar"]["taxes"], settings["ccar"]["taxes"]]) | 
				
			|||
            self.insurance = np.array([settings["ecar"]["insurance"], settings["ccar"]["insurance"]]) | 
				
			|||
            kilometer_price_ecar =  (   settings["ecar"]["charging_behaviour"]["percent_home_charges"] * settings["kwh_price_home"] | 
				
			|||
                                      + settings["ecar"]["charging_behaviour"]["percent_commercial_charges"] * settings["kwh_price_commercial"]) / 100.0 | 
				
			|||
            self.driving = np.array([kilometer_price_ecar * settings["kilometers_per_year"], kilometer_price_ccar * settings["kilometers_per_year"]]) | 
				
			|||
            self.maintenance = np.array([settings["ecar"]["maintenance"], settings["ecar"]["maintenance"]]) | 
				
			|||
    def get_labels(self): | 
				
			|||
        return self.labels | 
				
			|||
    def get_purchase(self): | 
				
			|||
        return self.purchase | 
				
			|||
    def get_taxes(self): | 
				
			|||
        return self.taxes | 
				
			|||
    def get_insurance(self): | 
				
			|||
        return self.insurance | 
				
			|||
    def get_driving(self): | 
				
			|||
        return self.driving | 
				
			|||
    def get_maintenance(self): | 
				
			|||
        return self.maintenance | 
				
			|||
     | 
				
			|||
class c_ecar_comparator: | 
				
			|||
    def __init__(self, fname): | 
				
			|||
        self.settings_extractor = c_settings_extractor(fname) | 
				
			|||
    def calculate_costs_a_year(self): | 
				
			|||
        taxes = self.settings_extractor.get_taxes() | 
				
			|||
        insurance = self.settings_extractor.get_insurance() | 
				
			|||
        driving = self.settings_extractor.get_driving() | 
				
			|||
        maintenance = self.settings_extractor.get_maintenance() | 
				
			|||
        return taxes + insurance + driving + maintenance | 
				
			|||
    def calculate_costs(self, years, months): | 
				
			|||
        months_a_year = 12.0 | 
				
			|||
        costs_a_year = self.calculate_costs_a_year() | 
				
			|||
        return costs_a_year * (years + months/months_a_year) | 
				
			|||
    def calculate_break_even(self): | 
				
			|||
        total_costs = self.settings_extractor.get_purchase() | 
				
			|||
        months_a_year = 12.0 | 
				
			|||
        increment = self.calculate_costs_a_year() / months_a_year | 
				
			|||
        months = 0 | 
				
			|||
        while total_costs[0] > total_costs[1]: | 
				
			|||
            total_costs += increment  | 
				
			|||
            months += 1 | 
				
			|||
        return [months/months_a_year, months%months_a_year] # years, months | 
				
			|||
 | 
				
			|||
kilometer_price = np.array( [settings["ecar"]["kwh_per_kilometer"] * settings["kwh_price_home"], | 
				
			|||
                             settings["ccar"]["litre_per_kilometer"] * settings["petrol_litre_price"]]) | 
				
			|||
labels = [settings["ecar"]["label"], settings["ccar"]["label"]] | 
				
			|||
price = np.array([settings["ecar"]["price"], settings["ccar"]["price"]]) | 
				
			|||
taxes = np.array([settings["ecar"]["taxes"], settings["ccar"]["taxes"]]) | 
				
			|||
insurance = np.array([settings["ecar"]["insurance"], settings["ccar"]["insurance"]]) | 
				
			|||
kilometer_price_ecar =      (settings["ecar"]["charging_behaviour"]["percent_home_charges"] * settings["kwh_price_home"] | 
				
			|||
                        +    settings["ecar"]["charging_behaviour"]["percent_commercial_charges"] * settings["kwh_price_commercial"]) / 100.0 | 
				
			|||
driving = np.array([kilometer_price_ecar * settings["kilometers_per_year"], kilometer_price[1] * settings["kilometers_per_year"]]) | 
				
			|||
maintenance = np.array([settings["ecar"]["maintenance"], settings["ecar"]["maintenance"]]) | 
				
			|||
width = 0.3 | 
				
			|||
def main(): | 
				
			|||
    parser = argparse.ArgumentParser(description='This script allows to calculate if an electric car makes sense financially for you') | 
				
			|||
    parser.add_argument('-a','--settings', help='Settings file', required=True, metavar=('FILENAME')) | 
				
			|||
    parser.add_argument('-b','--break_even', help='Calculate the break even point. (When does the EV become cheaper)', action='store_true') | 
				
			|||
    parser.add_argument('-c','--savings_per_year', help='Calculate savings per year', action='store_true') | 
				
			|||
    parser.add_argument('-d','--savings_per_month', help='Calculate savings per month', action='store_true') | 
				
			|||
    parser.add_argument('-e','--plot', help='Visualize costs over one or multiple years', type=int, metavar=('YEARS')) | 
				
			|||
    args = parser.parse_args() | 
				
			|||
    if not args.break_even and not args.savings_per_year and not args.savings_per_month and not args.plot: | 
				
			|||
        sys.exit("Please choose one or multiple options") | 
				
			|||
    comparator = c_ecar_comparator(args.settings) | 
				
			|||
    extractor = c_settings_extractor(args.settings) | 
				
			|||
    if args.plot: | 
				
			|||
        width = 0.3 | 
				
			|||
        labels = extractor.get_labels() | 
				
			|||
        purchase = extractor.get_purchase() | 
				
			|||
        taxes = extractor.get_taxes() | 
				
			|||
        insurance = extractor.get_insurance() | 
				
			|||
        driving = extractor.get_driving() | 
				
			|||
        maintenance = extractor.get_maintenance() | 
				
			|||
        fig, ax = plt.subplots() | 
				
			|||
        ax.bar(labels, purchase, width, label = "Price", color = "gray") | 
				
			|||
        current_y = extractor.get_purchase() | 
				
			|||
        y = 0 | 
				
			|||
 | 
				
			|||
fig, ax = plt.subplots() | 
				
			|||
ax.bar(labels, price, width, label = "Price", color = "gray") | 
				
			|||
currenty = price | 
				
			|||
y = 0 | 
				
			|||
    for i in range(args.plot): | 
				
			|||
        ax.bar(labels, taxes, width, bottom = current_y, label = "Taxes".format(y), color = "darkgreen") | 
				
			|||
        current_y = current_y + taxes | 
				
			|||
        ax.bar(labels, insurance, width, bottom = current_y, label = "Insurance".format(y), color = "royalblue") | 
				
			|||
        current_y = current_y + insurance | 
				
			|||
        ax.bar(labels, driving, width, bottom = current_y, label = "Driving".format(y), color = "midnightblue") | 
				
			|||
        current_y = current_y + driving | 
				
			|||
        ax.bar(labels, maintenance, width, bottom = current_y, label = "Maintenance".format(y), color = "lavender") | 
				
			|||
        current_y = current_y + maintenance | 
				
			|||
        y += 1 | 
				
			|||
    ecar_top = current_y[0] | 
				
			|||
    #ax.plot(np.linspace(-0.2, 1.2, 10), [ecar_top]*10, "--", color = "firebrick", label = "Break even") | 
				
			|||
    #ax.text(0.3, ecar_top * 0.95, "Break even: {} years, {} kilometers".format(y, y*settings["kilometers_per_year"])) | 
				
			|||
    ax.set_ylabel("CHF") | 
				
			|||
    ax.set_title("Comparision of economics electric vs. combustion car") | 
				
			|||
    ax.legend(["Price", "Taxes", "Insurance", "Driving", "Maintenance"]) | 
				
			|||
    ax.grid(axis = "y") | 
				
			|||
    #print("Break even after {} years and {} kilometers. {}".format(y, y*settings["kilometers_per_year"], current_y[0]-current_y[1])) | 
				
			|||
    plt.show() | 
				
			|||
 | 
				
			|||
for i in range(settings["years"]): | 
				
			|||
#while currenty[0] > currenty[1]: | 
				
			|||
    ax.bar(labels, taxes, width, bottom = currenty, label = "Taxes".format(y), color = "darkgreen") | 
				
			|||
    currenty = currenty + taxes | 
				
			|||
    ax.bar(labels, insurance, width, bottom = currenty, label = "Insurance".format(y), color = "royalblue") | 
				
			|||
    currenty = currenty + insurance | 
				
			|||
    ax.bar(labels, driving, width, bottom = currenty, label = "Driving".format(y), color = "midnightblue") | 
				
			|||
    currenty = currenty + driving | 
				
			|||
    ax.bar(labels, maintenance, width, bottom = currenty, label = "Maintenance".format(y), color = "lavender") | 
				
			|||
    currenty = currenty + maintenance | 
				
			|||
    y += 1 | 
				
			|||
ecar_top = currenty[0] | 
				
			|||
#ax.plot(np.linspace(-0.2, 1.2, 10), [ecar_top]*10, "--", color = "firebrick", label = "Break even") | 
				
			|||
ax.text(0.3, ecar_top * 0.95, "Break even: {} years, {} kilometers".format(y, y*settings["kilometers_per_year"])) | 
				
			|||
ax.set_ylabel("CHF") | 
				
			|||
ax.set_title("Comparision of economics electric vs. combustion car") | 
				
			|||
ax.legend(["Price", "Taxes", "Insurance", "Driving", "Maintenance"]) | 
				
			|||
ax.grid(axis = "y") | 
				
			|||
print("Break even after {} years and {} kilometers. {}, {}".format(y, y*settings["kilometers_per_year"], currenty[0], currenty[1])) | 
				
			|||
plt.show() | 
				
			|||
if __name__ == "__main__": | 
				
			|||
    main() | 
				
			|||
 | 
				
			|||
					Loading…
					
					
				
		Reference in new issue