File size: 2,921 Bytes
4a6abf3
 
7bfdab4
4a6abf3
7bfdab4
 
 
59f38cb
4a6abf3
7bfdab4
1924724
4a6abf3
1924724
beac226
 
4842302
e8144d2
 
 
 
 
 
 
 
1924724
e8144d2
 
 
1924724
 
e8144d2
 
1924724
e8144d2
1924724
 
 
 
 
7bfdab4
e8144d2
1924724
e8144d2
1924724
59f38cb
 
1924724
 
59f38cb
 
 
 
 
 
 
 
 
 
 
 
 
 
1924724
 
 
 
59f38cb
 
 
1924724
 
 
59f38cb
 
 
 
1924724
 
 
 
 
 
 
 
 
 
59f38cb
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import streamlit as st
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
import imageio
from io import BytesIO
import tempfile
import math

st.set_page_config(layout="wide")
st.title("Market Cap Animation")

tickers_input = st.text_input("Tickers", "AAPL,MSFT,NVDA,GOOG,AMZN,META")
start_date_str = st.text_input("Start Date", "2021-01-01")
end_date_str = st.text_input("End Date", "2025-04-01")

def fetch_market_caps(tickers, start, end):
    data = yf.download(tickers, start=start, end=end)["Close"]
    if isinstance(data, pd.Series):
        data = data.to_frame()
    mcap = pd.DataFrame(index=data.index)
    failed = []
    for t in tickers:
        try:
            shares = yf.Ticker(t).info.get("sharesOutstanding", None)
            if not shares or shares <= 0:
                failed.append(t)
                continue
            mcap[t] = data[t] * shares / 1e6
        except:
            failed.append(t)
    mcap.dropna(how="any", inplace=True)
    return mcap.iloc[::5], failed

if st.button("Generate"):
    tickers = [t.strip().upper() for t in tickers_input.split(",")]
    start = pd.to_datetime(start_date_str)
    end = pd.to_datetime(end_date_str)
    mcap, failed = fetch_market_caps(tickers, start, end)

    if mcap.empty:
        st.error("No data.")
    else:
        frames = []
        fig, ax = plt.subplots(figsize=(12, 6))

        ordered = list(mcap.columns)
        colors = {t: plt.cm.tab10(i % 10) for i, t in enumerate(ordered)}

        # Grid layout dimensions
        n = len(ordered)
        cols = math.ceil(math.sqrt(n))
        rows = math.ceil(n / cols)

        # Fixed positions in a grid
        grid_positions = {}
        for i, t in enumerate(ordered):
            row = i // cols
            col = i % cols
            x = col + 1
            y = rows - row
            grid_positions[t] = (x, y)

        for date, row in mcap.iterrows():
            ax.clear()
            ax.axis("off")
            ax.set_xlim(0, cols + 2)
            ax.set_ylim(0, rows + 2)
            ax.set_title(str(date.date()), fontsize=14)

            for t in ordered:
                val = row[t]
                x, y = grid_positions[t]
                ax.text(x, y, f"{t}\n{val:,.0f}M", fontsize=10,
                        ha='center', va='center',
                        bbox=dict(boxstyle="circle,pad=0.6", fc=colors[t], ec="black"))

            buf = BytesIO()
            plt.savefig(buf, format="png", bbox_inches="tight")
            buf.seek(0)
            frames.append(imageio.v2.imread(buf))
            buf.close()

        with tempfile.NamedTemporaryFile(delete=False, suffix=".gif") as tmp:
            imageio.mimsave(tmp.name, frames, duration=2.5)
            st.image(frames[-1])
            st.download_button("Download GIF", open(tmp.name, "rb").read(),
                               file_name="market_cap.gif", mime="image/gif")