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: |
|||
class c_settings_extractor: |
|||
def __init__(self, fname): |
|||
with open(fname, "r") as rf: |
|||
settings = json.load(rf) |
|||
|
|||
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_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 |
|||
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 |
|||
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 |
|||
|
|||
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, price, width, label = "Price", color = "gray") |
|||
currenty = price |
|||
ax.bar(labels, purchase, width, label = "Price", color = "gray") |
|||
current_y = extractor.get_purchase() |
|||
y = 0 |
|||
|
|||
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 |
|||
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 = currenty[0] |
|||
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.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])) |
|||
#print("Break even after {} years and {} kilometers. {}".format(y, y*settings["kilometers_per_year"], current_y[0]-current_y[1])) |
|||
plt.show() |
|||
|
|||
if __name__ == "__main__": |
|||
main() |
|||
|
Loading…
Reference in new issue