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 matplotlib.pyplot as plt | 
				
			||||
import numpy as np | 
					import numpy as np | 
				
			||||
import json | 
					import json | 
				
			||||
 | 
					import sys | 
				
			||||
 | 
					import argparse | 
				
			||||
 | 
					__author__ = 'm3x1m0m' | 
				
			||||
 | 
					
 | 
				
			||||
with open("ecar.json", "r") as rf: | 
					class c_settings_extractor: | 
				
			||||
    settings = json.load(rf) | 
					    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 | 
				
			||||
     | 
					     | 
				
			||||
kilometer_price = np.array( [settings["ecar"]["kwh_per_kilometer"] * settings["kwh_price_home"], | 
					class c_ecar_comparator: | 
				
			||||
                             settings["ccar"]["litre_per_kilometer"] * settings["petrol_litre_price"]]) | 
					    def __init__(self, fname): | 
				
			||||
labels = [settings["ecar"]["label"], settings["ccar"]["label"]] | 
					        self.settings_extractor = c_settings_extractor(fname) | 
				
			||||
price = np.array([settings["ecar"]["price"], settings["ccar"]["price"]]) | 
					    def calculate_costs_a_year(self): | 
				
			||||
taxes = np.array([settings["ecar"]["taxes"], settings["ccar"]["taxes"]]) | 
					        taxes = self.settings_extractor.get_taxes() | 
				
			||||
insurance = np.array([settings["ecar"]["insurance"], settings["ccar"]["insurance"]]) | 
					        insurance = self.settings_extractor.get_insurance() | 
				
			||||
kilometer_price_ecar =      (settings["ecar"]["charging_behaviour"]["percent_home_charges"] * settings["kwh_price_home"] | 
					        driving = self.settings_extractor.get_driving() | 
				
			||||
                        +    settings["ecar"]["charging_behaviour"]["percent_commercial_charges"] * settings["kwh_price_commercial"]) / 100.0 | 
					        maintenance = self.settings_extractor.get_maintenance() | 
				
			||||
driving = np.array([kilometer_price_ecar * settings["kilometers_per_year"], kilometer_price[1] * settings["kilometers_per_year"]]) | 
					        return taxes + insurance + driving + maintenance | 
				
			||||
maintenance = np.array([settings["ecar"]["maintenance"], settings["ecar"]["maintenance"]]) | 
					    def calculate_costs(self, years, months): | 
				
			||||
width = 0.3 | 
					        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 | 
				
			||||
 | 
					
 | 
				
			||||
fig, ax = plt.subplots() | 
					def main(): | 
				
			||||
ax.bar(labels, price, width, label = "Price", color = "gray") | 
					    parser = argparse.ArgumentParser(description='This script allows to calculate if an electric car makes sense financially for you') | 
				
			||||
currenty = price | 
					    parser.add_argument('-a','--settings', help='Settings file', required=True, metavar=('FILENAME')) | 
				
			||||
y = 0 | 
					    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 | 
				
			||||
 | 
					
 | 
				
			||||
for i in range(settings["years"]): | 
					    for i in range(args.plot): | 
				
			||||
#while currenty[0] > currenty[1]: | 
					        ax.bar(labels, taxes, width, bottom = current_y, label = "Taxes".format(y), color = "darkgreen") | 
				
			||||
    ax.bar(labels, taxes, width, bottom = currenty, label = "Taxes".format(y), color = "darkgreen") | 
					        current_y = current_y + taxes | 
				
			||||
    currenty = currenty + taxes | 
					        ax.bar(labels, insurance, width, bottom = current_y, label = "Insurance".format(y), color = "royalblue") | 
				
			||||
    ax.bar(labels, insurance, width, bottom = currenty, label = "Insurance".format(y), color = "royalblue") | 
					        current_y = current_y + insurance | 
				
			||||
    currenty = currenty + insurance | 
					        ax.bar(labels, driving, width, bottom = current_y, label = "Driving".format(y), color = "midnightblue") | 
				
			||||
    ax.bar(labels, driving, width, bottom = currenty, label = "Driving".format(y), color = "midnightblue") | 
					        current_y = current_y + driving | 
				
			||||
    currenty = currenty + driving | 
					        ax.bar(labels, maintenance, width, bottom = current_y, label = "Maintenance".format(y), color = "lavender") | 
				
			||||
    ax.bar(labels, maintenance, width, bottom = currenty, label = "Maintenance".format(y), color = "lavender") | 
					        current_y = current_y + maintenance | 
				
			||||
    currenty = currenty + maintenance | 
					        y += 1 | 
				
			||||
    y += 1 | 
					    ecar_top = current_y[0] | 
				
			||||
ecar_top = currenty[0] | 
					    #ax.plot(np.linspace(-0.2, 1.2, 10), [ecar_top]*10, "--", color = "firebrick", label = "Break even") | 
				
			||||
#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.text(0.3, ecar_top * 0.95, "Break even: {} years, {} kilometers".format(y, y*settings["kilometers_per_year"])) | 
					    ax.set_ylabel("CHF") | 
				
			||||
ax.set_ylabel("CHF") | 
					    ax.set_title("Comparision of economics electric vs. combustion car") | 
				
			||||
ax.set_title("Comparision of economics electric vs. combustion car") | 
					    ax.legend(["Price", "Taxes", "Insurance", "Driving", "Maintenance"]) | 
				
			||||
ax.legend(["Price", "Taxes", "Insurance", "Driving", "Maintenance"]) | 
					    ax.grid(axis = "y") | 
				
			||||
ax.grid(axis = "y") | 
					    #print("Break even after {} years and {} kilometers. {}".format(y, y*settings["kilometers_per_year"], current_y[0]-current_y[1])) | 
				
			||||
print("Break even after {} years and {} kilometers. {}, {}".format(y, y*settings["kilometers_per_year"], currenty[0], currenty[1])) | 
					    plt.show() | 
				
			||||
plt.show() | 
					
 | 
				
			||||
 | 
					if __name__ == "__main__": | 
				
			||||
 | 
					    main() | 
				
			||||
 | 
				
			|||||
					Loading…
					
					
				
		Reference in new issue