folioflex 1.2.2__tar.gz → 1.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {folioflex-1.2.2/folioflex.egg-info → folioflex-1.2.3}/PKG-INFO +2 -1
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/budget/budget.py +162 -2
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/configs/portfolio_personal.ini +12 -0
- folioflex-1.2.3/folioflex/dashboard/components/dash_formats.py +105 -0
- folioflex-1.2.3/folioflex/dashboard/pages/budget.py +386 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/portfolio/broker.py +1 -1
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/portfolio/portfolio.py +33 -2
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/version.py +1 -1
- {folioflex-1.2.2 → folioflex-1.2.3/folioflex.egg-info}/PKG-INFO +2 -1
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex.egg-info/SOURCES.txt +1 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex.egg-info/requires.txt +1 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/pyproject.toml +1 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/tests/test_budget.py +24 -4
- folioflex-1.2.2/folioflex/dashboard/pages/budget.py +0 -194
- {folioflex-1.2.2 → folioflex-1.2.3}/LICENSE.md +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/MANIFEST.in +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/README.md +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/docs/source/conf.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/budget/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/budget/models.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/chatbot/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/chatbot/providers.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/chatbot/scraper.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/configs/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/configs/budget_personal.ini +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/configs/config.ini +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/configs/portfolio_dash.ini +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/configs/portfolio_demo.ini +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/configs/transactions_dash.csv +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/configs/transactions_demo.csv +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/app.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/assets/folioflex_logo.ico +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/assets/folioflex_logo.png +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/assets/github-mark-white.png +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/components/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/components/auth.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/components/layouts.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/pages/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/pages/ideas.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/pages/login.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/pages/logout.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/pages/macro.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/pages/personal.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/pages/sectors.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/pages/stocks.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/utils/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/dashboard/utils/dashboard_helper.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/market/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/market/screener.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/portfolio/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/portfolio/heatmap.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/portfolio/helper.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/portfolio/wrappers.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/utils/__init__.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/utils/cli.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/utils/config_helper.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/utils/cq.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/utils/custom_logger.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex/utils/mailer.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex.egg-info/dependency_links.txt +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex.egg-info/entry_points.txt +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/folioflex.egg-info/top_level.txt +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/setup.cfg +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/setup.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/tests/test_chatbot.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/tests/test_portfolio.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/tests/test_utils.py +0 -0
- {folioflex-1.2.2 → folioflex-1.2.3}/tests/test_wrappers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: folioflex
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: A collection of portfolio tracking capabilities
|
|
5
5
|
Author-email: John Koestner <johnkoestner@outlook.com>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -44,6 +44,7 @@ Requires-Dist: sqlalchemy>=2.0.23
|
|
|
44
44
|
Requires-Dist: yfinance>=0.2.32
|
|
45
45
|
Requires-Dist: tzlocal>=5.2
|
|
46
46
|
Requires-Dist: dash>=1.0.2
|
|
47
|
+
Requires-Dist: dash-ag-grid>=31.2.0
|
|
47
48
|
Requires-Dist: dash_bootstrap_components>=1.6.0
|
|
48
49
|
Requires-Dist: dash-core-components>=1.0.0
|
|
49
50
|
Requires-Dist: dash-html-components>=1.0.0
|
|
@@ -136,6 +136,12 @@ class Budget:
|
|
|
136
136
|
"""
|
|
137
137
|
Modify the transactions for the budget.
|
|
138
138
|
|
|
139
|
+
The modifications include:
|
|
140
|
+
- Zero out the amount for the given columns
|
|
141
|
+
- Extract the text between quotes
|
|
142
|
+
- Preprocess the emoji in the text
|
|
143
|
+
- Remove the pending transactions.
|
|
144
|
+
|
|
139
145
|
Parameters
|
|
140
146
|
----------
|
|
141
147
|
tx_df : DataFrame
|
|
@@ -285,6 +291,74 @@ class Budget:
|
|
|
285
291
|
return "Incoming Transfer"
|
|
286
292
|
return "OTHER"
|
|
287
293
|
|
|
294
|
+
def identify_subscriptions(self, tx_df):
|
|
295
|
+
"""
|
|
296
|
+
Identify possible subscriptions in the transactions.
|
|
297
|
+
|
|
298
|
+
The subscriptions are identified by the name and also the amount. If
|
|
299
|
+
the amount is similar for multiple transactions, and there are at least
|
|
300
|
+
a set amount of transcations, then it is likely a subscription.
|
|
301
|
+
|
|
302
|
+
Parameters
|
|
303
|
+
----------
|
|
304
|
+
tx_df : DataFrame
|
|
305
|
+
The transactions to identify subscriptions for.
|
|
306
|
+
|
|
307
|
+
Returns
|
|
308
|
+
-------
|
|
309
|
+
subscriptions : DataFrame
|
|
310
|
+
The subscriptions identified in the transactions.
|
|
311
|
+
|
|
312
|
+
"""
|
|
313
|
+
# default values
|
|
314
|
+
min_transactions = 3
|
|
315
|
+
interval_std_threshold = 5
|
|
316
|
+
amount_std_threshold = 0.1
|
|
317
|
+
|
|
318
|
+
# group data by name
|
|
319
|
+
grouped_df = tx_df.groupby("name")
|
|
320
|
+
|
|
321
|
+
# identify subscriptions
|
|
322
|
+
subscriptions = []
|
|
323
|
+
for name, group in grouped_df:
|
|
324
|
+
if len(group) < min_transactions:
|
|
325
|
+
continue
|
|
326
|
+
|
|
327
|
+
# calculating the intervals and ensure they are regular
|
|
328
|
+
intervals = group["date"].diff().dropna().dt.days
|
|
329
|
+
regular = intervals.std() <= interval_std_threshold
|
|
330
|
+
|
|
331
|
+
# calculate the amount and ensure it is consistent
|
|
332
|
+
amount_mean = group["amount"].mean()
|
|
333
|
+
if amount_mean == 0:
|
|
334
|
+
continue
|
|
335
|
+
relative_std = group["amount"].std() / amount_mean
|
|
336
|
+
consistent_amount = relative_std <= amount_std_threshold
|
|
337
|
+
|
|
338
|
+
# get the last date and amount
|
|
339
|
+
last_date = group["date"].max()
|
|
340
|
+
last_amount = group[group["date"] == last_date]["amount"].values[0]
|
|
341
|
+
|
|
342
|
+
if regular and consistent_amount:
|
|
343
|
+
subscriptions.append(
|
|
344
|
+
{
|
|
345
|
+
"Description": name,
|
|
346
|
+
"Occurrences": len(group),
|
|
347
|
+
"Mean Interval (Days)": intervals.mean(),
|
|
348
|
+
"Amount Mean": group["amount"].mean(),
|
|
349
|
+
"Amount Std Dev": group["amount"].std(),
|
|
350
|
+
"Last Date": last_date,
|
|
351
|
+
"Last Amount": last_amount,
|
|
352
|
+
}
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
subscriptions_df = pd.DataFrame(subscriptions)
|
|
356
|
+
subscriptions_df = subscriptions_df.sort_values(
|
|
357
|
+
by="Occurrences", ascending=False
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
return subscriptions_df
|
|
361
|
+
|
|
288
362
|
def budget_view(self, tx_df, target_date, exclude_labels=None):
|
|
289
363
|
"""
|
|
290
364
|
Provide a view of categories and their budget status.
|
|
@@ -308,6 +382,7 @@ class Budget:
|
|
|
308
382
|
if exclude_labels is not None:
|
|
309
383
|
tx_df = tx_df[~tx_df["label"].isin(exclude_labels)]
|
|
310
384
|
budgets = {k: v for k, v in budgets.items() if k not in exclude_labels}
|
|
385
|
+
|
|
311
386
|
# grouping transactions
|
|
312
387
|
grouped_transactions = (
|
|
313
388
|
tx_df[tx_df["date"].dt.to_period("M") == target_date]
|
|
@@ -316,6 +391,7 @@ class Budget:
|
|
|
316
391
|
.reset_index()
|
|
317
392
|
.sort_values("amount", ascending=True)
|
|
318
393
|
)
|
|
394
|
+
|
|
319
395
|
# adding in the budget
|
|
320
396
|
unused_keys = set(budgets.keys()) - set(grouped_transactions["label"])
|
|
321
397
|
unused_keys_df = pd.DataFrame({"label": list(unused_keys)})
|
|
@@ -327,6 +403,7 @@ class Budget:
|
|
|
327
403
|
grouped_transactions["budget"] = grouped_transactions["budget"].fillna(
|
|
328
404
|
float(self.config_dict["default"])
|
|
329
405
|
)
|
|
406
|
+
|
|
330
407
|
# providing a total
|
|
331
408
|
totals = grouped_transactions.sum(numeric_only=True).to_frame().T
|
|
332
409
|
totals["label"] = "TOTAL"
|
|
@@ -517,7 +594,78 @@ class Budget:
|
|
|
517
594
|
|
|
518
595
|
return fig
|
|
519
596
|
|
|
520
|
-
def
|
|
597
|
+
def display_category_trend(self, tx_df, category):
|
|
598
|
+
"""
|
|
599
|
+
Display the category trend view as a bar chart.
|
|
600
|
+
|
|
601
|
+
Parameters
|
|
602
|
+
----------
|
|
603
|
+
tx_df : DataFrame
|
|
604
|
+
The transactions to view income status for.
|
|
605
|
+
category : str
|
|
606
|
+
The category to view the trend for.
|
|
607
|
+
|
|
608
|
+
Returns
|
|
609
|
+
-------
|
|
610
|
+
fig : Figure
|
|
611
|
+
The category trend view as a line chart.
|
|
612
|
+
|
|
613
|
+
"""
|
|
614
|
+
# filter data for category
|
|
615
|
+
category_df = tx_df[tx_df["label"] == category]
|
|
616
|
+
category_df = category_df.groupby(["month"])["amount"].sum().reset_index()
|
|
617
|
+
|
|
618
|
+
# budgets
|
|
619
|
+
category_budget = self.budgets.get(category, 0)
|
|
620
|
+
average_budget = category_df["amount"].mean()
|
|
621
|
+
twelve_month_avg = category_df["amount"].rolling(window=12).mean()
|
|
622
|
+
|
|
623
|
+
# create bar chart
|
|
624
|
+
fig = px.bar(
|
|
625
|
+
category_df,
|
|
626
|
+
x="month",
|
|
627
|
+
y="amount",
|
|
628
|
+
title=f"'{category}' Spending Trend",
|
|
629
|
+
labels={"month": "Month", "amount": "Amount"},
|
|
630
|
+
color_discrete_sequence=["blue"],
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
# add budget line
|
|
634
|
+
fig.add_scatter(
|
|
635
|
+
x=category_df["month"],
|
|
636
|
+
y=[category_budget] * len(category_df),
|
|
637
|
+
mode="lines",
|
|
638
|
+
line={"color": "red", "dash": "dash"},
|
|
639
|
+
name="Budget",
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
# add average line
|
|
643
|
+
fig.add_scatter(
|
|
644
|
+
x=category_df["month"],
|
|
645
|
+
y=[average_budget] * len(category_df),
|
|
646
|
+
mode="lines",
|
|
647
|
+
line={"color": "black", "dash": "dash"},
|
|
648
|
+
name="Average",
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
# add 12 month average line
|
|
652
|
+
fig.add_scatter(
|
|
653
|
+
x=category_df["month"],
|
|
654
|
+
y=twelve_month_avg,
|
|
655
|
+
mode="lines",
|
|
656
|
+
line={"color": "green", "dash": "dash"},
|
|
657
|
+
name="12-Month Average",
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
return fig
|
|
661
|
+
|
|
662
|
+
def category_tx_view(
|
|
663
|
+
self,
|
|
664
|
+
tx_df,
|
|
665
|
+
target_date,
|
|
666
|
+
category,
|
|
667
|
+
columns=None,
|
|
668
|
+
):
|
|
521
669
|
"""
|
|
522
670
|
Display the transactions view as a table.
|
|
523
671
|
|
|
@@ -529,6 +677,8 @@ class Budget:
|
|
|
529
677
|
The date to view transactions for. Format: YYYY-MM.
|
|
530
678
|
category : str
|
|
531
679
|
The category to view transactions for.
|
|
680
|
+
columns : list (optional)
|
|
681
|
+
The columns to view in the table.
|
|
532
682
|
|
|
533
683
|
Returns
|
|
534
684
|
-------
|
|
@@ -536,10 +686,20 @@ class Budget:
|
|
|
536
686
|
The category of transactions view as a table.
|
|
537
687
|
|
|
538
688
|
"""
|
|
689
|
+
if columns is None:
|
|
690
|
+
columns = [
|
|
691
|
+
"date",
|
|
692
|
+
"amount",
|
|
693
|
+
"name",
|
|
694
|
+
"label",
|
|
695
|
+
"official_name",
|
|
696
|
+
]
|
|
697
|
+
|
|
539
698
|
cat_tx_df = tx_df[
|
|
540
699
|
(tx_df["date"].dt.to_period("M") == target_date)
|
|
541
700
|
& (tx_df["label"].str.contains(category))
|
|
542
|
-
].sort_values(by="
|
|
701
|
+
].sort_values(by="date", ascending=False)
|
|
702
|
+
cat_tx_df = cat_tx_df[columns]
|
|
543
703
|
return cat_tx_df
|
|
544
704
|
|
|
545
705
|
def update_labels_db(self, tx_df, engine=None, label_column="label"):
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
[all]
|
|
8
8
|
tx_file = static.tx_file
|
|
9
|
+
username = static.username
|
|
10
|
+
password = static.password
|
|
9
11
|
filter_type = static.filter_type
|
|
10
12
|
filter_broker = []
|
|
11
13
|
funds = static.funds
|
|
@@ -16,6 +18,8 @@ stock_splits = static.stock_splits
|
|
|
16
18
|
|
|
17
19
|
[fidelity]
|
|
18
20
|
tx_file = static.tx_file
|
|
21
|
+
username = static.username
|
|
22
|
+
password = static.password
|
|
19
23
|
filter_type = static.filter_type
|
|
20
24
|
filter_broker = ["fidelity"]
|
|
21
25
|
funds = static.funds
|
|
@@ -26,6 +30,8 @@ stock_splits = static.stock_splits
|
|
|
26
30
|
|
|
27
31
|
[ib]
|
|
28
32
|
tx_file = static.tx_file
|
|
33
|
+
username = static.username
|
|
34
|
+
password = static.password
|
|
29
35
|
filter_type = static.filter_type
|
|
30
36
|
filter_broker = ["ib"]
|
|
31
37
|
funds = static.funds
|
|
@@ -36,6 +42,8 @@ stock_splits = static.stock_splits
|
|
|
36
42
|
|
|
37
43
|
[roth]
|
|
38
44
|
tx_file = static.tx_file
|
|
45
|
+
username = static.username
|
|
46
|
+
password = static.password
|
|
39
47
|
filter_type = static.filter_type
|
|
40
48
|
filter_broker = ["roth"]
|
|
41
49
|
funds = static.funds
|
|
@@ -46,6 +54,8 @@ stock_splits = static.stock_splits
|
|
|
46
54
|
|
|
47
55
|
[ybr]
|
|
48
56
|
tx_file = static.tx_file
|
|
57
|
+
username = static.username
|
|
58
|
+
password = static.password
|
|
49
59
|
filter_type = static.filter_type
|
|
50
60
|
filter_broker = ["ybr"]
|
|
51
61
|
funds = static.funds
|
|
@@ -56,6 +66,8 @@ stock_splits = static.stock_splits
|
|
|
56
66
|
|
|
57
67
|
[static]
|
|
58
68
|
tx_file = $AWS_TX_FILE
|
|
69
|
+
username = ""
|
|
70
|
+
password = ""
|
|
59
71
|
filter_type = []
|
|
60
72
|
funds = ["BLKEQIX", "BLKRGIX", "BLKRVIX", "HLIEIX", "LIPIX", "TRPILCG", "TRPSV", "DODIX"]
|
|
61
73
|
delisted = [
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Components - dash formats."""
|
|
2
|
+
|
|
3
|
+
from folioflex.utils import custom_logger
|
|
4
|
+
|
|
5
|
+
logger = custom_logger.setup_logging(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_column_defs(table):
|
|
9
|
+
"""
|
|
10
|
+
Get the column definitions.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
table : pd.DataFrame
|
|
15
|
+
The table
|
|
16
|
+
|
|
17
|
+
Returns
|
|
18
|
+
-------
|
|
19
|
+
column_defs : list
|
|
20
|
+
The column definitions
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
column_defs = []
|
|
24
|
+
for col in table.columns:
|
|
25
|
+
# specific case for columns
|
|
26
|
+
if any(substring in col.lower() for substring in ["amount"]):
|
|
27
|
+
column_defs.append(
|
|
28
|
+
{
|
|
29
|
+
"field": col,
|
|
30
|
+
"headerName": col,
|
|
31
|
+
"valueFormatter": {"function": "d3.format(',.2f')(params.value)"},
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
# update integer columns
|
|
35
|
+
elif table[col].dtype.kind in "i":
|
|
36
|
+
if "year" in col.lower():
|
|
37
|
+
column_defs.append(
|
|
38
|
+
{
|
|
39
|
+
"field": col,
|
|
40
|
+
"headerName": col,
|
|
41
|
+
"valueFormatter": {"function": "d3.format('d')(params.value)"},
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
else:
|
|
45
|
+
column_defs.append(
|
|
46
|
+
{
|
|
47
|
+
"field": col,
|
|
48
|
+
"headerName": col,
|
|
49
|
+
"valueFormatter": {"function": "d3.format(',')(params.value)"},
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
# update float columns
|
|
53
|
+
elif table[col].dtype.kind in "f":
|
|
54
|
+
if any(substring in col.lower() for substring in ["pct"]):
|
|
55
|
+
column_defs.append(
|
|
56
|
+
{
|
|
57
|
+
"field": col,
|
|
58
|
+
"headerName": col,
|
|
59
|
+
"valueFormatter": {
|
|
60
|
+
"function": "d3.format('.2%')(params.value)"
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
else:
|
|
65
|
+
column_defs.append(
|
|
66
|
+
{
|
|
67
|
+
"field": col,
|
|
68
|
+
"headerName": col,
|
|
69
|
+
"valueFormatter": {
|
|
70
|
+
"function": "d3.format(',.1f')(params.value)"
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
# update other types
|
|
75
|
+
else:
|
|
76
|
+
column_defs.append(
|
|
77
|
+
{
|
|
78
|
+
"field": col,
|
|
79
|
+
"headerName": col,
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
return column_defs
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def remove_column_defs(column_defs, col_name):
|
|
86
|
+
"""
|
|
87
|
+
Remove a column from the column definitions.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
column_defs : list
|
|
92
|
+
The column definitions
|
|
93
|
+
col_name : str
|
|
94
|
+
The column name to remove
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
column_defs : list
|
|
99
|
+
The column definitions
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
for col in column_defs:
|
|
103
|
+
if col["field"] == col_name:
|
|
104
|
+
column_defs.remove(col)
|
|
105
|
+
return column_defs
|