from data.data import * data = ambil_data_emas() def generate(d_h=default_hari, is_img=False, data = ambil_data_emas()): fig = go.Figure() df = pd.DataFrame(data['data']['priceList'])[::-1][:max(lhs)] df['hargaBeli'] = pd.to_numeric(df['hargaBeli']) * 100 df['hargaJual'] = pd.to_numeric(df['hargaJual']) * 100 df['lastUpdate'] = pd.to_datetime(df['lastUpdate'], format='%Y-%m-%d %H:%M:%S') df = df.sort_values('lastUpdate').reset_index(drop=True) df.rename(columns={ "hargaBeli": "Harga Jual", "hargaJual": "Harga Beli" }, inplace=True) # Persiapkan semua traces (per hari opsi) all_traces = [] buttons = [] slider_steps = [] option_sizes = {"btn": [], "ss": []} x_rng_list = {"btn": [], "ss": []} y_ax_rng_list = {"btn": [], "ss": []} htd_list = {"btn": [], "ss": []} freq_list = {"btn": [], "ss": []} tickvals_list = {"btn": [], "ss": []} default_idx = {"btn": 0, "ss": 0} slyc_list = {"btn": [], "ss": []} lch = 0 def generateTP(i, hari, dfc, x_rng, isBtn): nonlocal lch htd = int((x_rng[1] - x_rng[0]).days + 1) htd_list["btn" if isBtn else "ss"].append(htd) default_idx["btn" if isBtn else "ss"] = int(i if htd == d_h else default_idx["btn" if isBtn else "ss"]) freq = get_freq(htd) freq_list["btn" if isBtn else "ss"].append(freq) tickvals = pd.date_range( start=x_rng[0].normalize(), end=x_rng[1].normalize(), freq=freq ) tickvals_list["btn" if isBtn else "ss"].append(tickvals) y_ax_rng_list["btn" if isBtn else "ss"].append( [min(dfc["Harga Jual"]) - 100_000, max(dfc["Harga Beli"]) + 100_000] ) hasil = [] mindf = min(dfc["lastUpdate"]) isstb = [] isstbt = [] validTB = [] harga_jual_sekarang = dfc.iloc[-1]['Harga Jual'] for k, tb in (enumerate(tanggal_beli)): idx = (dfc['lastUpdate'] - tb).abs().idxmin() row = dfc.loc[idx] harga_beli = row['Harga Beli'] harga_jual = row['Harga Jual'] tanggal_beli_riil = row['lastUpdate'].date() if tb > mindf: validTB.append(tb) tanggal_jual = dfc.iloc[-1]['lastUpdate'].date() nilai_jual = harga_jual_sekarang * berat_gram[k] profit = nilai_jual - uang_awal[k] hasil.append({ "No": (k - len(isstb) + len(isstbt)) + 1, "TglB": tanggal_beli_riil, "HBg": harga_beli, "g": berat_gram[k], "M": uang_awal[k], "TglJ": tanggal_jual, "HJg": harga_jual, "NJ": nilai_jual, "PL": profit }) if len(isstb) >=1: isstb.append(True) isstbt.append(True) continue isstb.append(True) # Tambahkan total total_berat = sum([h["g"] for h in hasil]) total_modal = sum([h["M"] for h in hasil]) total_nilai_jual = sum([h["NJ"] for h in hasil]) total_profit = sum([h["PL"] for h in hasil]) # --- Tabel Transaksi --- header = [ "No", "Tgl Beli", "Harga Beli/g (Rp)", "Berat (g)", "Modal (Rp)", "Tgl Jual", "Harga Jual/g (Rp)", f"Nilai Jual Rp{harga_jual_sekarang:,.0f}/g", "Profit/Loss (Rp)" ] profit_loss_values = [row['PL'] for row in hasil] + [total_profit] cells = [ [row["No"] for row in hasil], [row["TglB"].strftime("%Y-%m-%d") for row in hasil], [f"Rp {row['HBg']:,.0f}" for row in hasil], [f"{row['g']:.4f} g" for row in hasil], [f"Rp {row['M']:,.0f}" for row in hasil], [row["TglJ"].strftime("%Y-%m-%d") for row in hasil], [f"Rp {row['HJg']:,.0f}" for row in hasil], [f"Rp {row['NJ']:,.0f}" for row in hasil], [f"Rp {PL:,.0f}" for PL in profit_loss_values], ] # Tambahkan total ke akhir tabel for h, val in enumerate([ "Total", misy*len(cells[1][0])+misy*(round(len(cells[1][0])/7.5)), misy*len(cells[2][0])+misy*(round(len(cells[2][0])/7.5)), f"{total_berat:.4f} g", f"Rp {total_modal:,.0f}", misy*len(cells[5][0])+misy*(round(len(cells[5][0])/7.5)), misy*len(cells[6][0])+misy*(round(len(cells[6][0])/7.5)), f"Rp {total_nilai_jual:,.0f}", ]): cells[h].append(val) lc = len(cells[0]) + 1 lch = lc if lc > lch else lch profit_loss_header_color = "#b3f3b3" if all(v > 0 for v in profit_loss_values) else ( "#f7b3b3" if all(v < 0 for v in profit_loss_values) else "#ffd6e7" ) profit_loss_cell_colors = [ "#d4fcd4" if v > 0 else "#ffd6e0" if v < 0 else "#ffffff" for v in profit_loss_values ] header_fill_color[-1] = profit_loss_header_color cells_fill_color[-1] = profit_loss_cell_colors # Tambahkan tabel transaksi emas table = go.Table( header=dict(values=header, fill_color=header_fill_color, align='center'), cells=dict(values=cells, fill_color=cells_fill_color, align='center'), columnwidth=cwta, visible=(hari == d_h) if not isBtn else False ) # Harga Beli t1 = go.Scatter( x=dfc['lastUpdate'], y=dfc['Harga Beli'], name='Harga Beli', line=dict(color='green'), visible=(hari==d_h) if not isBtn else False ) t2 = go.Scatter( x=dfc['lastUpdate'], y=dfc['Harga Jual'], name='Harga Jual', line=dict(color='red'), visible=(hari==d_h) if not isBtn else False ) # titik beli markers = [] lbp = None slyc = 3 for j, tb in (enumerate(validTB)): lbp = "top" if j % 2 == 0 else "bottom" markers.append( go.Scatter( x=[tb], y=[hasil[j]["HBg"]], mode='markers+text', name=f'Transaksi ke-{j+1} (Beli)', text=[# f'Beli ke-{j+1}
(Rp {hasil[j]["M"]:,.0f})' if hari <= 80 else f'B{j+1}'], textposition=f'{lbp} center', # textfont=dict(size=10), marker=dict(color='green', size=10), visible=(hari==d_h) if not isBtn else False ) ) slyc += 1 slyc_list["btn" if isBtn else "ss"].append(makeslcy(slyc)) # titik jual terakhir sell_marker = go.Scatter( x=[dfc.iloc[-1]['lastUpdate']], y=[dfc.iloc[-1]['Harga Jual']], mode='markers+text', name='Harga Jual Terakhir', text=[# 'Jual Sekarang' if hari <= 60 else 'JS'], textposition=f'{"top" if lbp == "bottom" else lbp} center', # textfont=dict(size=10), marker=dict(color='red', size=10), visible=(hari==d_h) if not isBtn else False ) # kumpulkan semua trace untuk opsi ini traces_for_option = [table] + [t1, t2] + markers + [sell_marker] # simpan ukuran dan rentang untuk opsi ini option_sizes["btn" if isBtn else "ss"].append(len(traces_for_option)) x_rng_list["btn" if isBtn else "ss"].append(x_rng) all_traces.append(traces_for_option) rlhs = [i for i in range(7, lhs[7] + 1)] for i, hari in (enumerate(rlhs)): cut = df['lastUpdate'].max() - pd.Timedelta(days=hari) dfc = df[df['lastUpdate'] > cut] x_rng = [dfc['lastUpdate'].min(), dfc['lastUpdate'].max()] generateTP(i, hari, dfc, x_rng, False) for i, hari in (enumerate(lhs[:8])): cut = df['lastUpdate'].max() - pd.Timedelta(days=hari) dfc = df[df['lastUpdate'] > cut] x_rng = [dfc['lastUpdate'].min(), dfc['lastUpdate'].max()] generateTP(i, hari, dfc, x_rng, True) # Buat figure subplot dengan 2 baris: [0]=tabel, [1]=grafik fig = make_subplots( rows=2, cols=1, shared_xaxes=False, vertical_spacing=0.1, row_heights=[(lch if lch >= 5 else 5) / 10, 0.5], specs=[[{"type": "table"}], [{"type": "scatter"}]] ) for traces in all_traces: for i, trace in enumerate(traces): fig.add_trace(trace, row=1 if i == 0 else 2, col=1) rlhsd = {hari: idx for idx, hari in enumerate(rlhs)} total_traces = sum(option_sizes["ss"]) + sum(option_sizes["btn"]) generateLMA = lambda vis, tickvals, x_rng, htd, freq, hari, slyc, y_ax_rng: dict( label=f"{hari} Hari", method="update", args=[ {"visible": vis}, { "xaxis.tickvals": tickvals, "xaxis.range": x_rng, "xaxis.autorange": True, "title": { "text": f'📊 Tabel dan Grafik Interaktif Harga Emas Pegadaian Digital per Gram ({htd} Hari Terakhir)

Diambil pada {timestamp_lokal} dengan frekuensi {freq}

', "x": 0.5 }, "updatemenus[0].active": lhsd.get(hari, None), "sliders[0].active": rlhsd.get(hari, None), "sliders[0].y": slyc, "yaxis.range": y_ax_rng, } ] ) start_ss = 0 lhsd = {hari: idx for idx, hari in enumerate(lhs[:8])} for i, hari in enumerate(tqdm(rlhs)): vis = [False] * total_traces cut = df['lastUpdate'].max() - pd.Timedelta(days=hari) dfc = df[df['lastUpdate'] > cut] for j in range(option_sizes["ss"][i]): idx = start_ss + j vis[idx] = True fig.data[idx].visible = (hari == d_h) slider_steps.append(generateLMA( vis, tickvals_list["ss"][i], x_rng_list["ss"][i], htd_list["ss"][i], freq_list["ss"][i], hari, slyc_list["ss"][i], y_ax_rng_list["ss"][i] )) start_ss +=option_sizes["ss"][i] start_btn = sum(option_sizes["ss"]) for i, hari in enumerate(tqdm(lhs[:8])): vis = [False] * total_traces for j in range(option_sizes["btn"][i]): idx = start_btn + j vis[idx] = True # fig.data[idx].visible = (hari == d_h) buttons.append(generateLMA( vis, tickvals_list["btn"][i], x_rng_list["btn"][i], htd_list["btn"][i], freq_list["btn"][i], hari, slyc_list["btn"][i], y_ax_rng_list["btn"][i] )) start_btn +=option_sizes["btn"][i] cut = df['lastUpdate'].max() - pd.Timedelta(days=d_h) dfc = df[df['lastUpdate'] > cut] x_rng = [dfc['lastUpdate'].min(), dfc['lastUpdate'].max()] slyc = slyc_list["btn"][default_idx["btn"]] fig.update_xaxes( tickvals=tickvals_list["ss"][default_idx["ss"]], tickformat="%Y-%m-%d", tickangle=-90, row=2, col=1 ) fig.update_layout( title=dict( text=f'📊 Tabel dan Grafik Interaktif Harga Emas Pegadaian Digital per Gram ({htd_list["btn"][default_idx["btn"]]} Hari Terakhir)

Diambil pada {timestamp_lokal} dengan frekuensi {freq_list["btn"][default_idx["btn"]]}

', x=0.5 ), updatemenus=[dict( type="buttons", direction="down", # tombol ditampilkan ke bawah buttons=buttons, # isi list tombol kamu showactive=True, x=1.033, # posisinya di luar area plot kanan y=0.5, # mulai dari atas xanchor="left", yanchor="top", pad=dict(r=10, t=10), # padding agar tidak mepet active=default_idx["btn"] )], sliders=[dict( active=default_idx["ss"], yanchor="top", xanchor="left", currentvalue=dict( font=dict(size=14), prefix="Rentang Hari: ", visible=True, xanchor="right" ), transition=dict(duration=300, easing="cubic-in-out"), pad=dict(b=10), len=1.0, x=0, y=slyc, steps=slider_steps )], xaxis=dict( tickvals=tickvals_list["ss"][default_idx["ss"]], tickformat="%Y-%m-%d", tickangle=-90, type='date', autorange=True, range=x_rng_list["ss"][default_idx["ss"]], rangeslider=dict(visible=True), ), yaxis=dict( title="Harga per Gram", tickprefix="Rp ", tickformat=",", range=[min(dfc["Harga Jual"]) - 100_000, max(dfc["Harga Beli"]) + 100_000], ), ) html = fig.to_html(full_html=False, include_plotlyjs='cdn') uf("grafik/pegadaian_digital/interaktif.html", html) # fig.show() print("is_img", is_img) return fig.to_image("svg").decode() if is_img else html