Report charts: re-basing-on-zoom widget (same as Equity tab); layout fixes
- per-fund report charts now use chart_widget.equity_chart_html (st.iframe) instead of static st.plotly_chart: every visible window re-bases each line to 1.0 at its left edge, so fund/reference/index compare in any zoom level - same semantics as the Equity curves tab - removed 'expand all' checkbox (24 expanded sections drowned the page) - added 'rest of Fund Lab continues below' marker after the report section; the other Fund Lab sections (alpha search, clusters, N-PORT, drawdown, tax, CEF) were never deleted and are unchanged
This commit is contained in:
parent
3fbf332b31
commit
e28f8fcf85
55
app.py
55
app.py
|
|
@ -639,8 +639,6 @@ with tab_fundlab:
|
|||
})
|
||||
st.dataframe(pd.DataFrame(_ag), width="stretch",
|
||||
hide_index=True)
|
||||
_rall = st.checkbox("Expand all fund reports", value=False,
|
||||
key="fl_rpt_expand")
|
||||
for _s in _rorder:
|
||||
_f = _rfunds[_s]
|
||||
_m, _st = _f["meta"], _f.get("stats", {})
|
||||
|
|
@ -649,35 +647,38 @@ with tab_fundlab:
|
|||
f"— {_m['name']}")
|
||||
if _m.get("verdict"):
|
||||
_title += f" [{_m['verdict'][:44]}]"
|
||||
with st.expander(_title, expanded=_rall):
|
||||
with st.expander(_title):
|
||||
if _f.get("narrative"):
|
||||
st.markdown("\n\n".join(_f["narrative"]))
|
||||
# same re-basing-on-zoom widget as the Equity curves tab:
|
||||
# every visible window re-bases each line to 1.0 at its
|
||||
# left edge, so fund/reference/index are comparable no
|
||||
# matter where you zoom
|
||||
_c = _f.get("chart", {})
|
||||
if _c.get("dates"):
|
||||
import plotly.graph_objects as _go
|
||||
_fig = _go.Figure()
|
||||
_fig.add_trace(_go.Scatter(
|
||||
x=pd.to_datetime(_c["dates"]),
|
||||
y=_c["fund"], name=_m["sym"].upper(),
|
||||
line=dict(width=2)))
|
||||
from chart_widget import equity_chart_html
|
||||
_ds = pd.to_datetime(_c["dates"])
|
||||
_series = {_m["sym"].upper():
|
||||
pd.Series(_c["fund"], _ds)}
|
||||
if _c.get("ref"):
|
||||
_fig.add_trace(_go.Scatter(
|
||||
x=pd.to_datetime(_c["ref_dates"]),
|
||||
y=_c["ref"], name="fitted reference",
|
||||
line=dict(width=1.2, dash="dash")))
|
||||
_series["fitted reference"] = pd.Series(
|
||||
_c["ref"], pd.to_datetime(_c["ref_dates"]))
|
||||
if _c.get("ivv"):
|
||||
_fig.add_trace(_go.Scatter(
|
||||
x=pd.to_datetime(_c["ivv_dates"]),
|
||||
y=_c["ivv"], name="S&P 500 (IVV)",
|
||||
line=dict(width=1, dash="dot"),
|
||||
opacity=0.7))
|
||||
_fig.update_layout(
|
||||
height=420, margin=dict(l=10, r=10, t=25, b=10),
|
||||
legend=dict(orientation="h", y=1.1),
|
||||
hovermode="x unified",
|
||||
title=f"total return since "
|
||||
f"{_c['dates'][0][:4]} (rebased 100)")
|
||||
st.plotly_chart(_fig, width="stretch")
|
||||
_series["S&P 500 (IVV)"] = pd.Series(
|
||||
_c["ivv"], pd.to_datetime(_c["ivv_dates"]))
|
||||
st.iframe(equity_chart_html(
|
||||
{k: s / s.iloc[0]
|
||||
for k, s in _series.items()},
|
||||
_ds, height=460, ytitle="growth (1.0 = start)",
|
||||
styles={
|
||||
_m["sym"].upper(): {"width": 2},
|
||||
"fitted reference":
|
||||
{"width": 1, "dash": "dash",
|
||||
"opacity": 0.8},
|
||||
"S&P 500 (IVV)":
|
||||
{"width": 1, "dash": "dot",
|
||||
"opacity": 0.5},
|
||||
}), height=490)
|
||||
if _f.get("perf"):
|
||||
st.dataframe(pd.DataFrame(
|
||||
_f["perf"],
|
||||
|
|
@ -713,6 +714,10 @@ with tab_fundlab:
|
|||
"R² 5y", "alpha 5y", "tax"]),
|
||||
width="stretch", hide_index=True)
|
||||
st.caption(_pe["proscons"])
|
||||
st.caption("← the rest of the Fund Lab continues below: "
|
||||
"alpha search, return-driver clusters, N-PORT "
|
||||
"cross-check, drawdown resilience, tax location, "
|
||||
"and the CEF ranking.")
|
||||
|
||||
# --- alpha search: all screened funds (shortlist + longlist + harvest)
|
||||
with st.expander("Alpha search — all screened funds, ranked"):
|
||||
|
|
|
|||
|
|
@ -1136,3 +1136,16 @@ chart, period table, drivers, reference mix, tax, peers) + an "expand
|
|||
all" checkbox. Static build so the page stays fast; regenerate with
|
||||
`python -m fundlab.reportdata` (~8 s) and `python -m fundlab.report`
|
||||
(~11 s for the HTML).
|
||||
|
||||
**Report charts: re-basing-on-zoom widget (2nd pass).** The first report
|
||||
build used static st.plotly_chart with pre-rebased series — zooming to a
|
||||
window left the lines starting at different levels (no comparison
|
||||
possible). Replaced with the SAME widget as the Equity curves tab
|
||||
(`chart_widget.equity_chart_html` + st.iframe): on every relayout each
|
||||
visible line is re-based to 1.0 at its left edge and y fits the visible
|
||||
data, so fund/reference/index are comparable in any window. report_data
|
||||
still stores the full-history series; the app divides by each series'
|
||||
first point before handing it to the widget (per-series 1.0 start, as
|
||||
the widget expects). Also removed the "expand all" checkbox (24 expanded
|
||||
sections made the page unusable and hid the sections below) and added a
|
||||
"rest of the Fund Lab continues below" marker.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user