mirror of
https://github.com/rio-labs/rio.git
synced 2026-02-09 07:09:00 -06:00
added crypto dashboard project template
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
date,bitcoin,litecoin,ethereum
|
||||
2024-03-08 12:00:00,67599.0,87.74,3948.76
|
||||
2024-03-08 16:00:00,68263.0,87.6,3938.98
|
||||
2024-03-08 20:00:00,68842.0,86.95,3924.4
|
||||
2024-03-09 00:00:00,68315.0,88.36,3893.61
|
||||
2024-03-09 04:00:00,68412.0,88.97,3936.56
|
||||
2024-03-09 08:00:00,68641.0,88.96,3940.13
|
||||
2024-03-09 12:00:00,68389.0,88.0,3918.71
|
||||
2024-03-09 16:00:00,68436.0,89.93,3923.73
|
||||
2024-03-09 20:00:00,68337.0,88.9,3891.06
|
||||
2024-03-10 00:00:00,68508.0,90.95,3916.04
|
||||
2024-03-10 04:00:00,69159.0,89.48,3941.75
|
||||
2024-03-10 08:00:00,69503.0,89.2,3953.62
|
||||
2024-03-10 12:00:00,69752.0,88.79,3940.61
|
||||
2024-03-10 16:00:00,69366.0,87.78,3899.33
|
||||
2024-03-10 20:00:00,69523.0,88.38,3907.77
|
||||
2024-03-11 00:00:00,69076.0,87.52,3887.47
|
||||
2024-03-11 04:00:00,68570.0,86.75,3862.07
|
||||
2024-03-11 08:00:00,71280.0,90.65,4004.27
|
||||
2024-03-11 12:00:00,72115.0,94.93,4046.45
|
||||
2024-03-11 16:00:00,72226.0,102.02,4030.35
|
||||
2024-03-11 20:00:00,72017.0,104.71,4035.06
|
||||
2024-03-12 00:00:00,72131.0,103.82,4070.6
|
||||
2024-03-12 04:00:00,71593.0,99.12,4036.72
|
||||
2024-03-12 08:00:00,72187.0,98.91,4028.14
|
||||
2024-03-12 12:00:00,72089.0,97.66,4023.2
|
||||
2024-03-12 16:00:00,71862.0,96.77,3992.88
|
||||
2024-03-12 20:00:00,71437.0,97.94,3980.26
|
||||
2024-03-13 00:00:00,71467.0,97.44,3978.69
|
||||
2024-03-13 04:00:00,72050.0,98.17,4042.21
|
||||
2024-03-13 08:00:00,72908.0,98.27,4043.54
|
||||
2024-03-13 12:00:00,73107.0,97.48,4049.14
|
||||
2024-03-13 16:00:00,72569.0,95.74,3958.16
|
||||
2024-03-13 20:00:00,73111.0,96.38,3998.11
|
||||
2024-03-14 00:00:00,73098.0,97.21,4007.91
|
||||
2024-03-14 04:00:00,73286.0,95.97,3997.86
|
||||
2024-03-14 08:00:00,73331.0,95.52,3970.7
|
||||
2024-03-14 12:00:00,72876.0,95.85,3954.82
|
||||
2024-03-14 16:00:00,70916.0,93.94,3854.01
|
||||
2024-03-14 20:00:00,69740.0,91.78,3796.04
|
||||
2024-03-15 00:00:00,71420.0,94.04,3879.04
|
||||
2024-03-15 04:00:00,68664.0,89.91,3732.7
|
||||
2024-03-15 08:00:00,68629.0,89.76,3760.8
|
||||
2024-03-15 12:00:00,67677.0,87.53,3680.82
|
||||
2024-03-15 16:00:00,68239.0,88.42,3693.14
|
||||
2024-03-15 20:00:00,68583.0,88.74,3698.82
|
||||
2024-03-16 00:00:00,69498.0,89.76,3738.38
|
||||
2024-03-16 04:00:00,69291.0,89.51,3737.05
|
||||
2024-03-16 08:00:00,69319.0,89.99,3733.34
|
||||
2024-03-16 12:00:00,68363.0,89.76,3697.12
|
||||
2024-03-16 16:00:00,68440.0,88.16,3679.65
|
||||
2024-03-16 20:00:00,67088.0,84.97,3599.44
|
||||
2024-03-17 00:00:00,65292.0,83.99,3514.22
|
||||
2024-03-17 04:00:00,66510.0,86.17,3571.89
|
||||
2024-03-17 08:00:00,65608.0,82.61,3470.38
|
||||
2024-03-17 12:00:00,66914.0,85.94,3576.46
|
||||
2024-03-17 16:00:00,68035.0,86.48,3635.12
|
||||
2024-03-17 20:00:00,68388.0,86.41,3649.0
|
||||
2024-03-18 00:00:00,68425.0,86.0,3643.28
|
||||
2024-03-18 04:00:00,67990.0,85.31,3602.72
|
||||
2024-03-18 08:00:00,68234.0,85.67,3628.4
|
||||
2024-03-18 12:00:00,68166.0,84.97,3596.86
|
||||
2024-03-18 16:00:00,67379.0,82.97,3524.82
|
||||
2024-03-18 20:00:00,66965.0,82.18,3483.63
|
||||
2024-03-19 00:00:00,67709.0,87.45,3525.89
|
||||
2024-03-19 04:00:00,66034.0,83.51,3424.52
|
||||
2024-03-19 08:00:00,64569.0,80.54,3356.92
|
||||
2024-03-19 12:00:00,63098.0,79.22,3264.74
|
||||
2024-03-19 16:00:00,63858.0,80.88,3302.27
|
||||
2024-03-19 20:00:00,64449.0,81.12,3326.83
|
||||
2024-03-20 00:00:00,62133.0,78.69,3171.29
|
||||
2024-03-20 04:00:00,62290.0,79.4,3197.54
|
||||
2024-03-20 08:00:00,62932.0,81.55,3214.48
|
||||
2024-03-20 12:00:00,63262.0,81.1,3272.76
|
||||
2024-03-20 16:00:00,63682.0,80.73,3312.18
|
||||
2024-03-20 20:00:00,65883.0,83.86,3382.99
|
||||
2024-03-21 00:00:00,67819.0,84.8,3515.69
|
||||
2024-03-21 04:00:00,66484.0,85.01,3499.07
|
||||
2024-03-21 08:00:00,66964.0,84.9,3513.59
|
||||
2024-03-21 12:00:00,67065.0,85.36,3530.98
|
||||
2024-03-21 16:00:00,66494.0,86.19,3496.02
|
||||
2024-03-21 20:00:00,65380.0,86.13,3442.28
|
||||
2024-03-22 00:00:00,65536.0,85.81,3493.43
|
||||
2024-03-22 04:00:00,65942.0,85.58,3512.73
|
||||
2024-03-22 08:00:00,66131.0,85.3,3513.87
|
||||
2024-03-22 12:00:00,64260.0,82.78,3410.95
|
||||
2024-03-22 16:00:00,64084.0,83.02,3347.99
|
||||
2024-03-22 20:00:00,64153.0,83.24,3356.17
|
||||
2024-03-23 00:00:00,63509.0,83.16,3322.89
|
||||
2024-03-23 04:00:00,63516.0,83.98,3301.83
|
||||
2024-03-23 08:00:00,64518.0,84.21,3363.15
|
||||
2024-03-23 12:00:00,64555.0,86.15,3359.43
|
||||
2024-03-23 16:00:00,65080.0,86.46,3400.15
|
||||
2024-03-23 20:00:00,64957.0,87.04,3394.56
|
||||
2024-03-24 00:00:00,64286.0,85.63,3353.37
|
||||
2024-03-24 04:00:00,64098.0,86.91,3318.68
|
||||
2024-03-24 08:00:00,64403.0,86.67,3334.59
|
||||
2024-03-24 12:00:00,65247.0,87.78,3382.24
|
||||
2024-03-24 16:00:00,65627.0,89.54,3398.86
|
||||
2024-03-24 20:00:00,65892.0,89.44,3386.51
|
||||
2024-03-25 00:00:00,67311.0,89.79,3454.26
|
||||
2024-03-25 04:00:00,66984.0,89.79,3442.76
|
||||
2024-03-25 08:00:00,66871.0,89.49,3452.12
|
||||
2024-03-25 12:00:00,66827.0,88.77,3435.6
|
||||
2024-03-25 16:00:00,69919.0,91.47,3588.17
|
||||
2024-03-25 20:00:00,70950.0,91.33,3637.92
|
||||
2024-03-26 00:00:00,69939.0,90.23,3588.49
|
||||
2024-03-26 04:00:00,70497.0,91.01,3634.89
|
||||
2024-03-26 08:00:00,70674.0,91.48,3632.06
|
||||
2024-03-26 12:00:00,70719.0,91.32,3635.26
|
||||
2024-03-26 16:00:00,70240.0,88.76,3592.04
|
||||
2024-03-26 20:00:00,69732.0,95.53,3566.54
|
||||
2024-03-27 00:00:00,70082.0,95.79,3591.55
|
||||
2024-03-27 04:00:00,70407.0,97.13,3607.21
|
||||
2024-03-27 08:00:00,69697.0,95.66,3565.21
|
||||
2024-03-27 12:00:00,70166.0,97.34,3582.5
|
||||
2024-03-27 16:00:00,69014.0,94.04,3519.94
|
||||
2024-03-27 20:00:00,68689.0,93.65,3490.66
|
||||
2024-03-28 00:00:00,69436.0,93.68,3505.22
|
||||
2024-03-28 04:00:00,69192.0,95.37,3486.11
|
||||
2024-03-28 08:00:00,70319.0,96.22,3568.91
|
||||
2024-03-28 12:00:00,70643.0,94.8,3577.23
|
||||
2024-03-28 16:00:00,71434.0,94.99,3587.31
|
||||
2024-03-28 20:00:00,70858.0,93.86,3568.63
|
||||
2024-03-29 00:00:00,70710.0,94.16,3560.26
|
||||
2024-03-29 04:00:00,70429.0,94.64,3559.74
|
||||
2024-03-29 08:00:00,69803.0,93.44,3520.88
|
||||
2024-03-29 12:00:00,70179.0,102.77,3548.3
|
||||
2024-03-29 16:00:00,69279.0,104.78,3497.78
|
||||
2024-03-29 20:00:00,69618.0,105.73,3497.88
|
||||
2024-03-30 00:00:00,69919.0,109.27,3516.1
|
||||
2024-03-30 04:00:00,69865.0,105.25,3492.65
|
||||
2024-03-30 08:00:00,69960.0,104.69,3500.01
|
||||
2024-03-30 12:00:00,70203.0,103.47,3560.29
|
||||
2024-03-30 16:00:00,70043.0,102.35,3539.64
|
||||
2024-03-30 20:00:00,69939.0,102.24,3509.25
|
||||
2024-03-31 00:00:00,69702.0,102.9,3507.66
|
||||
2024-03-31 04:00:00,69939.0,102.83,3536.77
|
||||
2024-03-31 08:00:00,70303.0,102.61,3626.24
|
||||
2024-03-31 12:00:00,70389.0,102.22,3608.23
|
||||
2024-03-31 16:00:00,70364.0,102.81,3619.01
|
||||
2024-03-31 20:00:00,71070.0,104.4,3638.99
|
||||
2024-04-01 00:00:00,71247.0,105.14,3644.77
|
||||
2024-04-01 04:00:00,70631.0,110.3,3611.68
|
||||
2024-04-01 08:00:00,69712.0,108.78,3549.56
|
||||
2024-04-01 12:00:00,69535.0,104.47,3540.84
|
||||
2024-04-01 16:00:00,68524.0,98.75,3477.05
|
||||
2024-04-01 20:00:00,69433.0,99.36,3478.01
|
||||
2024-04-02 00:00:00,69786.0,99.57,3508.25
|
||||
2024-04-02 04:00:00,66811.0,95.75,3368.96
|
||||
2024-04-02 08:00:00,66583.0,98.74,3372.58
|
||||
2024-04-02 12:00:00,65429.0,102.03,3305.06
|
||||
2024-04-02 16:00:00,65095.0,106.09,3255.86
|
||||
2024-04-02 20:00:00,66122.0,107.54,3276.87
|
||||
2024-04-03 00:00:00,65440.0,106.93,3274.9
|
||||
2024-04-03 04:00:00,66252.0,103.1,3322.29
|
||||
2024-04-03 08:00:00,66255.0,101.75,3309.57
|
||||
2024-04-03 12:00:00,66185.0,100.53,3322.99
|
||||
2024-04-03 16:00:00,65925.0,98.79,3328.94
|
||||
2024-04-03 20:00:00,65895.0,97.69,3321.85
|
||||
2024-04-04 00:00:00,66124.0,98.78,3316.68
|
||||
2024-04-04 04:00:00,65660.0,97.86,3279.5
|
||||
2024-04-04 08:00:00,66056.0,101.3,3320.72
|
||||
2024-04-04 12:00:00,66407.0,100.3,3346.21
|
||||
2024-04-04 16:00:00,67805.0,99.65,3365.87
|
||||
2024-04-04 20:00:00,68678.0,98.96,3370.51
|
||||
2024-04-05 00:00:00,68542.0,97.86,3332.09
|
||||
2024-04-05 04:00:00,67833.0,98.38,3307.82
|
||||
2024-04-05 08:00:00,66957.0,98.84,3284.9
|
||||
2024-04-05 12:00:00,66485.0,96.62,3249.98
|
||||
2024-04-05 16:00:00,67989.0,97.78,3322.74
|
||||
2024-04-05 20:00:00,67572.0,99.26,3323.64
|
||||
2024-04-06 00:00:00,67979.0,98.17,3320.28
|
||||
2024-04-06 04:00:00,67758.0,98.3,3333.11
|
||||
2024-04-06 08:00:00,68156.0,99.87,3338.67
|
||||
2024-04-06 12:00:00,67745.0,102.03,3335.87
|
||||
2024-04-06 16:00:00,68158.0,100.67,3340.78
|
||||
2024-04-06 20:00:00,68316.0,100.09,3348.47
|
||||
2024-04-07 00:00:00,69001.0,101.24,3362.84
|
||||
2024-04-07 04:00:00,69449.0,104.42,3391.29
|
||||
2024-04-07 08:00:00,69388.0,103.41,3389.81
|
||||
|
@@ -0,0 +1,3 @@
|
||||
from .balance_card import BalanceCard as BalanceCard
|
||||
from .crypto_card import CryptoCard as CryptoCard
|
||||
from .crypto_chart import CryptoChart as CryptoChart
|
||||
@@ -0,0 +1,200 @@
|
||||
from typing import * # type:ignore
|
||||
|
||||
# <additional-imports>
|
||||
import pandas as pd
|
||||
import plotly.express as px
|
||||
|
||||
import rio
|
||||
|
||||
from .. import data_models
|
||||
|
||||
# </additional-imports>
|
||||
|
||||
|
||||
# <component>
|
||||
class BalanceCard(rio.Component):
|
||||
"""
|
||||
The MyBalance class is a component of a dashboard application, designed to handle and
|
||||
display balance-related data.
|
||||
|
||||
The class provides methods to calculate total balance at a given index, calculate the
|
||||
percentual difference in balance between the last and second last balances, and create
|
||||
visual sections for the dashboard.
|
||||
These sections include a balance section displaying the total balance and the percentual
|
||||
difference in balance, and a bar chart section displaying a bar chart with a given color
|
||||
and hidden axes.
|
||||
|
||||
The build method combines these sections into a single rio.Card component, creating a
|
||||
complete balance component for the dashboard.
|
||||
|
||||
Attributes:
|
||||
data: A pandas DataFrame containing the data for the coins in MY_COINS.
|
||||
"""
|
||||
|
||||
data: pd.DataFrame
|
||||
|
||||
def total_balance(self, idx: int) -> float:
|
||||
"""
|
||||
Calculates the total balance for a given index.
|
||||
|
||||
This function iterates over the coins in MY_COINS, and for each coin,
|
||||
it multiplies the coin's value by the value at the given index in the
|
||||
data for that coin. It then adds these products to a total and returns
|
||||
this total.
|
||||
|
||||
Args:
|
||||
idx (int): The index at which to calculate the total balance.
|
||||
|
||||
Returns:
|
||||
float: The total balance at the given index.
|
||||
"""
|
||||
|
||||
total = 0
|
||||
for coin in data_models.MY_COINS:
|
||||
total += data_models.MY_COINS[coin][0] * self.data[coin].iloc[idx]
|
||||
return total
|
||||
|
||||
def percentual_differance_balance(self) -> float:
|
||||
"""
|
||||
Calculates the percentual difference in balance between the last and
|
||||
second last balances.
|
||||
|
||||
This function iterates over the coins in MY_COINS, and for each coin,
|
||||
it multiplies the coin's value by the total balance at the last and
|
||||
second last indices. It then calculates the percentual difference between
|
||||
these two totals and returns this value.
|
||||
|
||||
Returns:
|
||||
float: The percentual difference between the last and second last balances.
|
||||
"""
|
||||
|
||||
total_last = 0
|
||||
total_second_last = 0
|
||||
epsilon = 0.0000001
|
||||
|
||||
for coin in data_models.MY_COINS:
|
||||
total_last += data_models.MY_COINS[coin][0] * self.total_balance(idx=-1)
|
||||
total_second_last += data_models.MY_COINS[coin][0] * self.total_balance(
|
||||
idx=-2
|
||||
)
|
||||
|
||||
# epsilon ensures that the denominator is never zero
|
||||
return ((total_last - total_second_last) / (total_second_last + epsilon)) * 100
|
||||
|
||||
def balance_section(self) -> rio.Component:
|
||||
"""
|
||||
Creates a balance section for the dashboard.
|
||||
|
||||
This function creates a section that displays the total balance and the
|
||||
percentual difference in balance. The total balance is displayed in bold,
|
||||
and the percentual difference is displayed in green if it's positive and
|
||||
in red if it's negative. The section is returned as a Column component
|
||||
from the rio library.
|
||||
|
||||
Returns:
|
||||
rio.Component: A Column component from the rio library, which includes
|
||||
the total balance, the percentual difference in balance, and some
|
||||
text and spacing elements.
|
||||
"""
|
||||
|
||||
return rio.Column(
|
||||
rio.Text(
|
||||
"My Balance",
|
||||
style=rio.TextStyle(font_size=1.2, font_weight="bold"),
|
||||
align_x=0,
|
||||
),
|
||||
rio.Spacer(height=1),
|
||||
rio.Text("Total Balance", style="dim", align_x=0),
|
||||
rio.Row(
|
||||
rio.Text(
|
||||
f"{self.total_balance(idx=-1):,.2f} USD",
|
||||
style=rio.TextStyle(font_size=1.2, font_weight="bold"),
|
||||
align_x=0,
|
||||
),
|
||||
rio.Text(
|
||||
f"({self.percentual_differance_balance():.2f} %)",
|
||||
style=rio.TextStyle(
|
||||
fill=(
|
||||
rio.Color.GREEN
|
||||
if self.percentual_differance_balance() > 0
|
||||
else rio.Color.RED
|
||||
)
|
||||
),
|
||||
),
|
||||
spacing=1,
|
||||
),
|
||||
spacing=1,
|
||||
align_y=1,
|
||||
)
|
||||
|
||||
def bar_chart_section(self, name: str, color: str) -> rio.Component:
|
||||
"""
|
||||
Creates a bar chart section for the dashboard.
|
||||
|
||||
This function creates a bar chart with the given color and hiden axes.
|
||||
The function returns a Column component from the rio library, which includes
|
||||
the Plot, the name of the section, and the total balance in USD.
|
||||
|
||||
Args:
|
||||
name (str): The name of the section.
|
||||
color (str): The color of the bars in the bar chart.
|
||||
|
||||
Returns:
|
||||
rio.Component: A Column component from the rio library, which includes
|
||||
the Plot, the name of the section, and the total balance in USD.
|
||||
"""
|
||||
|
||||
fig = px.bar(
|
||||
data_models.BAR_CHART,
|
||||
height=200,
|
||||
width=200,
|
||||
color_discrete_sequence=[color],
|
||||
)
|
||||
# hide and lock down axes
|
||||
fig.update_xaxes(visible=False, fixedrange=True)
|
||||
fig.update_yaxes(visible=False, fixedrange=True)
|
||||
# remove facet/subplot labels
|
||||
fig.update_layout(annotations=[], overwrite=True)
|
||||
|
||||
# strip down the rest of the plot
|
||||
fig.update_layout(
|
||||
showlegend=False,
|
||||
margin=dict(t=10, l=10, b=10, r=10),
|
||||
)
|
||||
|
||||
return rio.Column(
|
||||
rio.Plot(
|
||||
figure=fig,
|
||||
height=5,
|
||||
width=20,
|
||||
background=self.session.theme.neutral_color,
|
||||
),
|
||||
rio.Text(name, style="dim", align_x=0),
|
||||
rio.Text(
|
||||
f"{self.total_balance(idx=-1):,.2f} USD",
|
||||
style=rio.TextStyle(font_size=1.2, font_weight="bold"),
|
||||
justify="left",
|
||||
),
|
||||
spacing=1,
|
||||
align_y=1,
|
||||
)
|
||||
|
||||
def build(self) -> rio.Component:
|
||||
return rio.Card(
|
||||
rio.Row(
|
||||
# 1. Section
|
||||
self.balance_section(),
|
||||
rio.Separator(),
|
||||
# 2. Section
|
||||
self.bar_chart_section(name="Income", color="green"),
|
||||
rio.Separator(),
|
||||
self.bar_chart_section(name="Expenses", color="red"),
|
||||
margin=1,
|
||||
spacing=4,
|
||||
align_x=0.5,
|
||||
),
|
||||
height=13,
|
||||
)
|
||||
|
||||
|
||||
# </component>
|
||||
@@ -0,0 +1,152 @@
|
||||
from typing import * # type:ignore
|
||||
|
||||
# <additional-imports>
|
||||
import pandas as pd
|
||||
import plotly.express as px
|
||||
|
||||
import rio
|
||||
|
||||
# </additional-imports>
|
||||
|
||||
|
||||
# <component>
|
||||
class CryptoCard(rio.Component):
|
||||
"""
|
||||
The CryptoCard class is a component of a dashboard application, designed to handle
|
||||
and display cryptocurrency-related data. It uses the rio library to create
|
||||
interactive dashboard components and pandas DataFrame to store cryptocurrency data.
|
||||
|
||||
The build method creates a rio.Card component that displays a line plot of the last
|
||||
50 data points of the cryptocurrency, the cryptocurrency's logo, the name and ticker
|
||||
symbol of the cryptocurrency, the amount of the cryptocurrency, and the amount of
|
||||
the cryptocurrency in USD. The layout of the card is a grid with 4 rows and 2 columns.
|
||||
|
||||
If there is no data available for the cryptocurrency, a message is printed to the console.
|
||||
|
||||
|
||||
Attributes:
|
||||
data: A pandas DataFrame that holds the cryptocurrency data.
|
||||
coin: A string representing the name of the cryptocurrency.
|
||||
coin_amount: A float representing the amount of the cryptocurrency.
|
||||
coin_ticker: A string representing the ticker symbol of the cryptocurrency.
|
||||
logo_url: A string representing the URL of the cryptocurrency's logo.
|
||||
"""
|
||||
|
||||
data: pd.DataFrame
|
||||
coin: str
|
||||
coin_amount: float
|
||||
coin_ticker: str
|
||||
color: str
|
||||
logo_url: str
|
||||
|
||||
def build(self) -> rio.Component:
|
||||
fig = px.line(
|
||||
self.data[self.coin].iloc[-50:],
|
||||
color_discrete_sequence=[self.color],
|
||||
height=200,
|
||||
width=200,
|
||||
)
|
||||
|
||||
# hide and lock down axes
|
||||
fig.update_xaxes(visible=False, fixedrange=True)
|
||||
fig.update_yaxes(visible=False, fixedrange=True)
|
||||
|
||||
# remove facet/subplot labels
|
||||
fig.update_layout(annotations=[], overwrite=True)
|
||||
|
||||
# strip down the rest of the plot
|
||||
fig.update_layout(
|
||||
showlegend=False,
|
||||
margin=dict(t=10, l=10, b=10, r=10),
|
||||
)
|
||||
|
||||
grid = rio.Grid(
|
||||
column_spacing=0.5,
|
||||
row_spacing=1,
|
||||
margin=2,
|
||||
)
|
||||
|
||||
# Create a grid layout for the card
|
||||
# The grid will have 4 rows and 2 columns
|
||||
# Because the width of the plot is bigger, the second column will be wider
|
||||
# like shown below:
|
||||
|
||||
############################################
|
||||
# Icon | Plot #
|
||||
# Icon | Plot #
|
||||
# Coin Ticker | Coin Amount #
|
||||
# Coin Name | Coin Amount in USD #
|
||||
############################################
|
||||
|
||||
# Image with grid height 2
|
||||
grid.add(
|
||||
rio.Image(
|
||||
rio.URL(
|
||||
self.logo_url
|
||||
), # logo_url = e.g. "https://cryptologos.cc/logos/bitcoin-btc-logo.svg?v=029"
|
||||
height=2,
|
||||
width=2,
|
||||
align_y=0.5,
|
||||
),
|
||||
row=0,
|
||||
column=0,
|
||||
)
|
||||
|
||||
# Plot with grid height 2
|
||||
grid.add(
|
||||
rio.Plot(
|
||||
figure=fig,
|
||||
corner_radius=0,
|
||||
height=4,
|
||||
background=self.session.theme.neutral_color,
|
||||
),
|
||||
row=0,
|
||||
column=1,
|
||||
height=2,
|
||||
)
|
||||
|
||||
# Text with coin name and grid height 1
|
||||
grid.add(
|
||||
rio.Text(
|
||||
self.coin.capitalize(),
|
||||
style=rio.TextStyle(font_size=1.2, font_weight="bold"),
|
||||
align_x=0,
|
||||
),
|
||||
row=2,
|
||||
column=0,
|
||||
)
|
||||
|
||||
# Text with coin amount and grid height 1
|
||||
grid.add(
|
||||
rio.Text(
|
||||
f"{self.coin_amount:.6f} {self.coin_ticker}",
|
||||
align_x=0,
|
||||
style=rio.TextStyle(font_size=1.2, font_weight="bold"),
|
||||
),
|
||||
row=2,
|
||||
column=1,
|
||||
)
|
||||
|
||||
# Text with coin ticker and grid height 1
|
||||
grid.add(
|
||||
rio.Row(
|
||||
rio.Text(
|
||||
self.coin_ticker,
|
||||
),
|
||||
rio.Text(" / USD", style="dim"),
|
||||
align_x=0,
|
||||
),
|
||||
row=3,
|
||||
column=0,
|
||||
)
|
||||
# Text with coin amount in USD and grid height 1
|
||||
usd_amount = self.coin_amount * self.data[self.coin].iloc[-1]
|
||||
grid.add(rio.Text(f"{usd_amount:,.2f} USD", align_x=0), row=3, column=1)
|
||||
|
||||
return rio.Card(
|
||||
grid,
|
||||
height=13,
|
||||
)
|
||||
|
||||
|
||||
# </component>
|
||||
@@ -0,0 +1,106 @@
|
||||
from typing import * # type:ignore
|
||||
|
||||
# <additional-imports>
|
||||
import pandas as pd
|
||||
import plotly.express as px
|
||||
|
||||
import rio
|
||||
|
||||
from .. import data_models
|
||||
|
||||
# </additional-imports>
|
||||
|
||||
|
||||
# <component>
|
||||
class CryptoChart(rio.Component):
|
||||
data: pd.DataFrame
|
||||
coin: str
|
||||
logo_url: str = data_models.MY_COINS["bitcoin"][3]
|
||||
color: str = data_models.MY_COINS["bitcoin"][2]
|
||||
|
||||
def on_change_coin(self, ev: rio.DropdownChangeEvent) -> None:
|
||||
"""
|
||||
Handles the event of changing the selected coin.
|
||||
|
||||
This function updates the coin, color and logo_url attributes based on the selected coin.
|
||||
|
||||
Parameters:
|
||||
ev (rio.DropdownChangeEvent): The event object containing the selected coin value.
|
||||
"""
|
||||
self.coin = ev.value
|
||||
self.color = data_models.MY_COINS[self.coin][2]
|
||||
self.logo_url = data_models.MY_COINS[self.coin][3]
|
||||
|
||||
def build(self) -> rio.Component:
|
||||
"""
|
||||
Creates a Card component with the selected coin's line plot, logo, name, and dropdown.
|
||||
|
||||
This function creates a line plot of the last 50 data points of the selected coin,
|
||||
using the plotly express library. The plot is displayed in a Plot component from the
|
||||
rio library. The Card component includes the coin's logo, name, and dropdown, as well
|
||||
as the line plot.
|
||||
|
||||
Returns:
|
||||
rio.Card: A Card component with the selected coin's line plot, logo, name, and dropdown.
|
||||
See the layout below:
|
||||
|
||||
############################################
|
||||
# Logo | Coin Name | Dropdown #
|
||||
# Plot #
|
||||
############################################
|
||||
"""
|
||||
|
||||
fig = px.line(
|
||||
self.data[self.coin].iloc[-50:],
|
||||
color_discrete_sequence=[self.color],
|
||||
height=200,
|
||||
width=200,
|
||||
)
|
||||
|
||||
# Set x-axis labels to horizontal and remove labels
|
||||
fig.update_xaxes(tickangle=0, title_text="")
|
||||
fig.update_yaxes(title_text="")
|
||||
|
||||
# strip down the rest of the plot
|
||||
fig.update_layout(
|
||||
showlegend=False,
|
||||
margin=dict(t=10, l=10, b=10, r=10),
|
||||
)
|
||||
|
||||
return rio.Card(
|
||||
rio.Column(
|
||||
rio.Row(
|
||||
rio.Image(
|
||||
rio.URL(self.logo_url),
|
||||
height=2,
|
||||
width=2,
|
||||
),
|
||||
rio.Text(
|
||||
self.coin.capitalize(),
|
||||
style=rio.TextStyle(font_size=1.2, font_weight="bold"),
|
||||
),
|
||||
rio.Dropdown(
|
||||
options={
|
||||
value[1]: key for key, value in data_models.MY_COINS.items()
|
||||
},
|
||||
on_change=self.on_change_coin,
|
||||
),
|
||||
spacing=1,
|
||||
align_x=0.1,
|
||||
),
|
||||
rio.Plot(
|
||||
figure=fig,
|
||||
corner_radius=0,
|
||||
height=20,
|
||||
width=10,
|
||||
background=self.session.theme.neutral_color,
|
||||
# margin=1,
|
||||
),
|
||||
spacing=1,
|
||||
align_y=0.5,
|
||||
margin=2,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
# </component>
|
||||
@@ -0,0 +1,26 @@
|
||||
from typing import * # type:ignore
|
||||
|
||||
import pandas as pd
|
||||
|
||||
BAR_CHART: pd.DataFrame = pd.DataFrame([1, 2, 3, 4, 5, 6, 7], columns=["data"])
|
||||
|
||||
MY_COINS: dict[str, Tuple[float, str, str, str]] = {
|
||||
"bitcoin": (
|
||||
13.344546,
|
||||
"BTC",
|
||||
"#f7931a",
|
||||
"https://cryptologos.cc/logos/bitcoin-btc-logo.svg?v=029",
|
||||
),
|
||||
"litecoin": (
|
||||
40.21321,
|
||||
"LTC",
|
||||
"#365d99",
|
||||
"https://cryptologos.cc/logos/litecoin-ltc-logo.svg?v=029",
|
||||
),
|
||||
"ethereum": (
|
||||
4.239234,
|
||||
"ETH",
|
||||
"#14044d",
|
||||
"https://cryptologos.cc/logos/ethereum-eth-logo.svg?v=029",
|
||||
),
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"level": "intermediate",
|
||||
"summary": "A simple Crypto Dashboard",
|
||||
"dependencies": {
|
||||
"numpy": ">=1.26.4",
|
||||
"plotly": ">=5.20.0",
|
||||
"pycoingecko": ">=3.1.0",
|
||||
"pandas": ">=2.2.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
from .dashboard_page import DashboardPage as DashboardPage
|
||||
@@ -0,0 +1,195 @@
|
||||
import dataclasses
|
||||
from pathlib import Path
|
||||
from typing import * # type:ignore
|
||||
|
||||
import numpy as np
|
||||
|
||||
# <additional-imports>
|
||||
import pandas as pd
|
||||
from pycoingecko import CoinGeckoAPI
|
||||
|
||||
import rio
|
||||
|
||||
from .. import components as comps
|
||||
from .. import data_models
|
||||
|
||||
# </additional-imports>
|
||||
|
||||
|
||||
DIR = Path(__file__).parent.parent
|
||||
ASSET_DIR = DIR / "assets"
|
||||
|
||||
CRYPTO_LIST: list[str] = ["bitcoin", "litecoin", "ethereum"]
|
||||
|
||||
|
||||
FETCH_DATA_FROM_API = True # Set to False to use local data
|
||||
|
||||
|
||||
# <component>
|
||||
class DashboardPage(rio.Component):
|
||||
"""
|
||||
The DashboardPage class is a component of a dashboard application, designed to display
|
||||
a user's cryptocurrency balance and the historical data of three cryptocurrencies.
|
||||
It uses the rio library to create interactive dashboard components and pandas DataFrame
|
||||
to store cryptocurrency data.
|
||||
|
||||
The class contains a coin_data attribute that stores the historical data of three
|
||||
cryptocurrencies: Bitcoin, Litecoin, and Ethereum. The data is fetched from the CoinGecko
|
||||
API using the fetch_coin_data method. The class also contains an on_populate method that
|
||||
fetches the data when the component is populated.
|
||||
|
||||
The build method creates a grid layout for the dashboard, containing a balance component,
|
||||
three cryptocurrency components, and a cryptocurrency chart component. The layout is
|
||||
structured as follows:
|
||||
|
||||
###################################################
|
||||
# BalanceCard | CryptoCard(BTC) #
|
||||
# Crypto Chart | CryptoCard(LTC) #
|
||||
# (Crypto Chart) | CryptoCard(ETH) #
|
||||
###################################################
|
||||
|
||||
Attributes:
|
||||
coin_data: A pandas DataFrame that holds the historical data of three cryptocurrencies:
|
||||
Bitcoin, Litecoin, and Ethereum.
|
||||
"""
|
||||
|
||||
coin_data: pd.DataFrame = dataclasses.field(
|
||||
default=pd.DataFrame(
|
||||
{
|
||||
"date": np.zeros(5),
|
||||
**{coin: np.zeros(5) for coin in CRYPTO_LIST},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@rio.event.on_populate
|
||||
async def on_populate(self) -> None:
|
||||
if FETCH_DATA_FROM_API is True:
|
||||
self.coin_data = self._fetch_coin_data(CRYPTO_LIST)
|
||||
else:
|
||||
self.coin_data = self._read_csv(ASSET_DIR / "cryptos.csv")
|
||||
|
||||
def _read_csv(self, path: Path) -> pd.DataFrame:
|
||||
"""
|
||||
Reads csv file and returns a pandas DataFrame.
|
||||
|
||||
Args:
|
||||
path: A string representing the path to the csv file.
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: A pandas DataFrame containing the data from the csv file.
|
||||
"""
|
||||
df = pd.read_csv(path)
|
||||
df["date"] = pd.to_datetime(df["date"])
|
||||
df.set_index("date", inplace=True)
|
||||
return df
|
||||
|
||||
def _fetch_coin_data(
|
||||
self, coin_names: list[str], vs_currency: str = "usd", days: str = "30"
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
This method fetches historical data for a list of cryptocurrencies from the
|
||||
CoinGecko API and returns it as a pandas DataFrame.
|
||||
|
||||
The method creates an instance of the CoinGeckoAPI and iterates over the list
|
||||
of coin_names. For each coin, it fetches the OHLC (Open, High, Low, Close) data,
|
||||
converts it into a DataFrame, and processes it by converting the date to a
|
||||
datetime object, setting the date as the index, and dropping the "open", "high",
|
||||
and "low" columns. Each processed DataFrame is appended to a list.
|
||||
|
||||
Finally, the method concatenates all the DataFrames in the list into a single
|
||||
DataFrame along the columns axis, sets the column names to the coin_names,
|
||||
and returns the merged DataFrame.
|
||||
|
||||
|
||||
Args:
|
||||
coin_names: A list of strings representing the names of the
|
||||
cryptocurrencies to fetch data for.
|
||||
vs_currency: A string representing the currency to compare
|
||||
against. Defaults to "usd".
|
||||
days: A string representing the number of past days to fetch
|
||||
data for. Defaults to "30".
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: A pandas DataFrame containing the historical (OHL)C data for the
|
||||
specified cryptocurrencies.
|
||||
"""
|
||||
|
||||
df_list = []
|
||||
cg = CoinGeckoAPI()
|
||||
|
||||
for i in range(len(coin_names)):
|
||||
ohlc = cg.get_coin_ohlc_by_id(
|
||||
id=coin_names[i], vs_currency=vs_currency, days=days
|
||||
)
|
||||
df = pd.DataFrame(ohlc, columns=["date", "open", "high", "low", "close"])
|
||||
df["date"] = pd.to_datetime(df["date"], unit="ms")
|
||||
df.set_index("date", inplace=True)
|
||||
df = df.drop(columns=["open", "high", "low"])
|
||||
df_list.append(df)
|
||||
|
||||
merged_df = pd.concat(df_list, axis=1)
|
||||
merged_df.columns = coin_names
|
||||
|
||||
return merged_df
|
||||
|
||||
def build(self) -> rio.Component:
|
||||
"""
|
||||
Creates a grid layout for the dashboard.
|
||||
|
||||
This function creates a grid layout for the dashboard, using the rio library.
|
||||
The grid contains a balance component, three cryptocurrency components, and
|
||||
a cryptocurrency chart component. The components are added to the grid with
|
||||
specific row and column positions, widths, and heights.
|
||||
|
||||
Returns:
|
||||
rio.Grid: A grid layout for the dashboard, containing the balance, cryptocurrency,
|
||||
and cryptocurrency chart components. See the layout below:
|
||||
|
||||
|
||||
###################################################
|
||||
# BalanceCard | CryptoCard(BTC) #
|
||||
# Crypto Chart | CryptoCard(LTC) #
|
||||
# (Crypto Chart) | CryptoCard(ETH) #
|
||||
###################################################
|
||||
"""
|
||||
|
||||
grid = rio.Grid(
|
||||
column_spacing=2,
|
||||
row_spacing=2,
|
||||
align_y=0.5,
|
||||
margin_left=20,
|
||||
margin_right=5,
|
||||
)
|
||||
|
||||
grid.add(comps.BalanceCard(data=self.coin_data), row=0, column=0, width=4)
|
||||
|
||||
# use loop to add cards
|
||||
|
||||
for i, coin in enumerate(CRYPTO_LIST):
|
||||
grid.add(
|
||||
comps.CryptoCard(
|
||||
data=self.coin_data,
|
||||
coin=coin,
|
||||
coin_amount=data_models.MY_COINS[coin][0],
|
||||
coin_ticker=data_models.MY_COINS[coin][1],
|
||||
color=data_models.MY_COINS[coin][2],
|
||||
logo_url=data_models.MY_COINS[coin][3],
|
||||
),
|
||||
row=i,
|
||||
column=4,
|
||||
width=2,
|
||||
)
|
||||
|
||||
grid.add(
|
||||
comps.CryptoChart(data=self.coin_data, coin="bitcoin"),
|
||||
row=1,
|
||||
column=0,
|
||||
width=4,
|
||||
height=2,
|
||||
)
|
||||
|
||||
return grid
|
||||
|
||||
|
||||
# </component>
|
||||
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1000"
|
||||
height="600"
|
||||
viewBox="0 0 264.58333 158.75"
|
||||
version="1.1"
|
||||
id="svg896"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||
sodipodi:docname="thumbnail.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs890">
|
||||
<rect
|
||||
x="24.318259"
|
||||
y="28.991958"
|
||||
width="878.03067"
|
||||
height="524.25413"
|
||||
id="rect1" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#535353"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.1767979"
|
||||
inkscape:cx="758.83888"
|
||||
inkscape:cy="505.60933"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2078"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="45"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata893">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="scale(0.26458333)"
|
||||
id="text1"
|
||||
style="fill:#002c32;-inkscape-font-specification:'Roboto Medium';font-family:Roboto;font-size:21.33333333px;line-height:30.23622047px;paint-order:stroke fill markers;stroke-width:185;font-weight:500;text-align:center;white-space:pre;shape-inside:url(#rect1)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:500;font-size:21.1667px;line-height:30px;font-family:Roboto;-inkscape-font-specification:'Roboto Medium';text-align:center;text-anchor:middle;fill:#ff0000;fill-opacity:1;stroke-width:48.9479;paint-order:stroke fill markers"
|
||||
x="132.78259"
|
||||
y="25.720444"
|
||||
id="text2"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2"
|
||||
style="font-size:21.1667px;line-height:30px;fill:#ff0000;fill-opacity:1;stroke-width:48.9479"
|
||||
x="132.78259"
|
||||
y="25.720444">TODO: Thumbnail</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:500;font-size:50.1539px;line-height:71.0843px;font-family:Roboto;-inkscape-font-specification:'Roboto Medium';text-align:center;text-anchor:middle;fill:#ff0000;fill-opacity:1;stroke-width:48.9479;paint-order:stroke fill markers"
|
||||
x="132.05902"
|
||||
y="77.584312"
|
||||
id="text3"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3"
|
||||
style="font-size:50.1539px;line-height:71.0843px;fill:#ff0000;fill-opacity:1;stroke-width:48.9479"
|
||||
x="132.05902"
|
||||
y="77.584312">Simple</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="font-size:50.1539px;line-height:71.0843px;fill:#ff0000;fill-opacity:1;stroke-width:48.9479"
|
||||
x="132.05902"
|
||||
y="148.66861"
|
||||
id="tspan1">Dashboard</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
Reference in New Issue
Block a user