add pretty-report program

This commit is contained in:
falsycat 2025-07-19 19:59:17 +09:00
parent b8b3d40ece
commit 5ba20a2563
2 changed files with 140 additions and 2 deletions

137
pretty-report/__main__.py Normal file
View File

@ -0,0 +1,137 @@
import sys
import dash
from dash import dcc, html
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
def numerize(df, column):
if isinstance(column, list):
for item in column:
df = numerize(df, item)
else:
df[column] = pd.to_numeric(df[column], errors="coerce")
return df
data = []
with open("financials.txt", "r") as f:
for line in f:
line = line.strip()
if line == "":
pass
elif line.startswith("#"):
data.append([])
else:
data[-1].append(line.split(","))
asset = numerize(pd.DataFrame(data[0], columns=["Name", "Amount"]), "Amount")
debt = numerize(pd.DataFrame(data[2], columns=["Name", "Amount"]), "Amount")
net = numerize(pd.DataFrame(data[3], columns=["Name", "Amount"]), "Amount")
expense = numerize(pd.DataFrame(data[4], columns=["Name", "Amount"]), "Amount")
revenue = numerize(pd.DataFrame(data[5], columns=["Name", "Amount"]), "Amount")
inv_asset = numerize(pd.DataFrame(data[1], columns=["Name", "Amount"]), "Amount")
inv_expense = numerize(pd.DataFrame(data[7], columns=["Name", "Amount"]), "Amount")
inv_revenue = numerize(pd.DataFrame(data[8], columns=["Name", "Amount"]), "Amount")
food_expense = numerize(pd.DataFrame(data[6], columns=["Name", "Amount"]), "Amount")
daily = numerize(pd.DataFrame(data[9], columns=["Date", "Asset", "RealNet", "Risked"]), ["Asset", "RealNet", "Risked"])
# ---- displaying ----
def PieAndTable(title, data):
total = sum(data["Amount"])
fig = px.pie(
data.sort_values(by="Amount", ascending=False),
names="Name",
values="Amount",
hole=0.5,
hover_name="Name",
title=title,
)
fig.update_traces(
hovertemplate="%{label}<br>%{value} (%{percent})",
textinfo="label",
)
fig.update_layout(
annotations=[
dict(
x=0.5, y=0.5,
text=f"{total:,}",
showarrow=False,
),
],
showlegend=False,
)
return dcc.Graph(
style={"flex": "1", "height": "20rem"},
figure=fig,
)
def PlWaterfall(title, e, r):
merged = pd.merge(e, r, on="Name", suffixes=["E", "R"], how="outer")
merged["Amount"] = merged["AmountR"].fillna(0) - merged["AmountE"].fillna(0)
merged = merged.sort_values(by="Amount", ascending=False)
fig = go.Figure(go.Waterfall(
orientation="v",
x=merged["Name"],
y=merged["Amount"],
))
fig.update_layout(title=title)
return dcc.Graph(figure=fig)
def DailyLines(df):
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df["Date"],
y=df["Asset"],
mode="lines",
name="Total"
))
fig.add_trace(go.Scatter(
x=df["Date"],
y=df["RealNet"],
mode="lines",
name="Realtime Net"
))
fig.add_trace(go.Scatter(
x=df["Date"],
y=df["Risked"],
mode="lines",
name="Risked"
))
fig.update_layout(hovermode="x unified")
return dcc.Graph(figure=fig)
app = dash.Dash(__name__)
app.layout = html.Div([
html.H2("WHOLE"),
html.Div(
style={"display": "flex", "gap": "1rem"},
children=[
PieAndTable("Asset", asset),
PieAndTable("Debt", debt),
PieAndTable("Net", net),
],
),
PlWaterfall("P&L", expense, revenue),
html.H2("DAILY"),
html.Div(children=[
DailyLines(daily),
]),
html.H2("DETAILS"),
html.Div(
style={"display": "flex", "gap": "1rem"},
children=[
PieAndTable("Food Expenses", food_expense),
PieAndTable("RiskedAsset", inv_asset),
],
),
PlWaterfall("Investment P&L", inv_expense, inv_revenue),
])
app.run(debug=True)

View File

@ -1,2 +1,3 @@
numpy
matplotlib
pandas
plotly
dash