├── requirements.txt ├── images ├── bsc-logo.png ├── axelar-logo.png ├── cosmos-logo.png ├── flow-logo.png ├── gnosis-logo.png ├── near-logo.png ├── solana-logo.png ├── arbitrum-logo.png ├── ethereum-logo.png ├── optimism-logo.png ├── osmosis-logo.png ├── polygon-logo.png ├── avalanche-logo.png └── thorchain-logo.png ├── style.css ├── README.md ├── LICENSE ├── .devcontainer └── devcontainer.json ├── data.py ├── Home.py └── pages ├── 1_🌍_Macro.py ├── 2_🪙_Fees.py ├── 3_💸_Transfers.py ├── 4_🔄_Swaps.py └── 5_🛍️_NFT_Sales.py /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas 2 | plotly 3 | streamlit -------------------------------------------------------------------------------- /images/bsc-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/bsc-logo.png -------------------------------------------------------------------------------- /images/axelar-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/axelar-logo.png -------------------------------------------------------------------------------- /images/cosmos-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/cosmos-logo.png -------------------------------------------------------------------------------- /images/flow-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/flow-logo.png -------------------------------------------------------------------------------- /images/gnosis-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/gnosis-logo.png -------------------------------------------------------------------------------- /images/near-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/near-logo.png -------------------------------------------------------------------------------- /images/solana-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/solana-logo.png -------------------------------------------------------------------------------- /images/arbitrum-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/arbitrum-logo.png -------------------------------------------------------------------------------- /images/ethereum-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/ethereum-logo.png -------------------------------------------------------------------------------- /images/optimism-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/optimism-logo.png -------------------------------------------------------------------------------- /images/osmosis-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/osmosis-logo.png -------------------------------------------------------------------------------- /images/polygon-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/polygon-logo.png -------------------------------------------------------------------------------- /images/avalanche-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/avalanche-logo.png -------------------------------------------------------------------------------- /images/thorchain-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alitaslimi/cross-chain-monitoring/HEAD/images/thorchain-logo.png -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | [data-testid=metric-container] { 2 | box-shadow: 0 0 3px #cccccc; 3 | padding: 10px; 4 | } 5 | 6 | .plot-container>div { 7 | box-shadow: 0 0 3px #cccccc; 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cross Chain Monitoring Tool 2 | 3 | This [cross chain monitorin tool](https://cross-chain-monitoring.streamlit.app) was originally created for the [Flipside Crypto](https://flipsidecrypto.xyz) World Cup tournament using [Streamlit](https://streamlit.io). 4 | 5 | The data on this application is not updated any longer. The [Outlier](https://outlier.streamlit.app) is the new blockchain analytics tool that I created using the same resources. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ali Taslimi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Python 3", 3 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 4 | "image": "mcr.microsoft.com/devcontainers/python:1-3.11-bullseye", 5 | "customizations": { 6 | "codespaces": { 7 | "openFiles": [ 8 | "README.md", 9 | "Home.py" 10 | ] 11 | }, 12 | "vscode": { 13 | "settings": {}, 14 | "extensions": [ 15 | "ms-python.python", 16 | "ms-python.vscode-pylance" 17 | ] 18 | } 19 | }, 20 | "updateContentCommand": "[ -f packages.txt ] && sudo apt update && sudo apt upgrade -y && sudo xargs apt install -y {f.read()}", unsafe_allow_html = True) 29 | 30 | # Data Sources 31 | transactions_overview = data.get_data('Transactions Overview') 32 | transactions_daily = data.get_data('Transactions Daily') 33 | transactions_heatmap = data.get_data('Transactions Heatmap') 34 | 35 | # Filter 36 | options = st.multiselect( 37 | '**Select your desired blockchains:**', 38 | options=transactions_overview['Blockchain'].unique(), 39 | default=transactions_overview['Blockchain'].unique(), 40 | key='macro_options' 41 | ) 42 | 43 | # Selected Blockchain 44 | if len(options) == 0: 45 | st.warning('Please select at least one blockchain to see the metrics.') 46 | 47 | # Single Chain Analysis 48 | elif len(options) == 1: 49 | st.subheader('Overview') 50 | df = transactions_overview.query("Blockchain == @options") 51 | c1, c2, c3 = st.columns(3) 52 | with c1: 53 | st.metric(label='**Total Transactions**', value=str(df['Transactions'].map('{:,.0f}'.format).values[0])) 54 | with c2: 55 | st.metric(label='**Total Active Users**', value=str(df['Users'].map('{:,.0f}'.format).values[0])) 56 | with c3: 57 | st.metric(label='**Total Blocks**', value=str(df['Blocks'].map('{:,.0f}'.format).values[0])) 58 | 59 | st.subheader('Activity Over Time') 60 | df = transactions_daily.query("Blockchain == @options") 61 | 62 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 63 | fig.add_trace(go.Bar(x=df['Date'], y=df['Transactions'], name='Transactions'), secondary_y=False) 64 | fig.add_trace(go.Line(x=df['Date'], y=df['Users'], name='Users'), secondary_y=True) 65 | fig.update_layout(title_text='Daily Transactions and Users') 66 | fig.update_yaxes(title_text='Transactions', secondary_y=False) 67 | fig.update_yaxes(title_text='Users', secondary_y=True) 68 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 69 | 70 | st.subheader('Activity Heatmap') 71 | df = transactions_heatmap.query('Blockchain == @options') 72 | 73 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Transactions', histfunc='avg', title='Heatmap of Transactions', nbinsx=24) 74 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 1}, coloraxis_colorbar=dict(title='Transactions')) 75 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 76 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 77 | 78 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Users', histfunc='avg', title='Heatmap of Active Addresses', nbinsx=24) 79 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 1}, coloraxis_colorbar=dict(title='Users')) 80 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 81 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 82 | 83 | # Cross Chain Comparison 84 | else: 85 | st.subheader('Overview') 86 | df = transactions_overview.query('Blockchain == @options') 87 | c1, c2, c3 = st.columns(3) 88 | with c1: 89 | fig = px.bar(df, x='Blockchain', y='Transactions', color='Blockchain', title='Total Transactions', log_y=True) 90 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Transactions', xaxis={'categoryorder':'total ascending'}, hovermode='x unified') 91 | fig.update_traces(hovertemplate='%{y:,.0f}') 92 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 93 | with c2: 94 | fig = px.bar(df, x='Blockchain', y='Users', color='Blockchain', title='Total Active Users') 95 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Users', xaxis={'categoryorder':'total ascending'}, hovermode='x unified') 96 | fig.update_traces(hovertemplate='%{y:,.0f}') 97 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 98 | with c3: 99 | fig = px.bar(df, x='Blockchain', y='Blocks', color='Blockchain', title='Total Blocks') 100 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Blocks', xaxis={'categoryorder':'total ascending'}, hovermode='x unified') 101 | fig.update_traces(hovertemplate='%{y:,.0f}') 102 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 103 | 104 | st.subheader('Activity Over Time') 105 | 106 | df = transactions_daily.query('Blockchain == @options').sort_values(['Date', 'Transactions'], ascending=[False, False]) 107 | fig = px.line(df, x='Date', y='Transactions', color='Blockchain', custom_data=['Blockchain'], title='Daily Total Transactions', log_y=True) 108 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Transactions', hovermode='x unified') 109 | fig.update_traces(hovertemplate='%{customdata}: %{y:,.0f}') 110 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 111 | 112 | df = transactions_daily.query('Blockchain == @options').sort_values(['Date', 'Users'], ascending=[False, False]) 113 | fig = px.line(df, x='Date', y='Users', color='Blockchain', custom_data=['Blockchain'], title='Daily Active Users', log_y=True) 114 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Active Users', hovermode='x unified') 115 | fig.update_traces(hovertemplate='%{customdata}: %{y:,.0f}') 116 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 117 | 118 | df = transactions_daily.query('Blockchain == @options').sort_values(['Date', 'Blocks'], ascending=[False, False]) 119 | fig = px.line(df, x='Date', y='Blocks', color='Blockchain', custom_data=['Blockchain'], title='Daily Blocks', log_y=True) 120 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Blocks', hovermode='x unified') 121 | fig.update_traces(hovertemplate='%{customdata}: %{y:,.0f}') 122 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 123 | 124 | st.subheader('Activity Heatmap') 125 | 126 | c1, c2 = st.columns(2) 127 | with c1: 128 | df = transactions_heatmap.query('Blockchain == @options') 129 | df['Transactions'] = df.groupby('Blockchain')['Transactions'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 130 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Transactions', histfunc='avg', title='Daily Heatmap of Normalized Transactions') 131 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 132 | fig.update_xaxes(categoryorder='category ascending') 133 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 134 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 135 | 136 | df = transactions_heatmap.query('Blockchain == @options') 137 | df['Users'] = df.groupby('Blockchain')['Users'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 138 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Users', histfunc='avg', title='Daily Heatmap of Normalized Users') 139 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 140 | fig.update_xaxes(categoryorder='category ascending') 141 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 142 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 143 | 144 | df = transactions_heatmap.query('Blockchain == @options') 145 | df['Blocks'] = df.groupby('Blockchain')['Blocks'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 146 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Blocks', histfunc='avg', title='Daily Heatmap of Normalized Blocks') 147 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 148 | fig.update_xaxes(categoryorder='category ascending') 149 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 150 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 151 | with c2: 152 | df = transactions_heatmap.query('Blockchain == @options') 153 | df['Transactions'] = df.groupby('Blockchain')['Transactions'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 154 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Transactions', histfunc='avg', title='Hourly Heatmap of Normalized Transactions', nbinsy=24) 155 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 156 | fig.update_xaxes(categoryorder='category ascending') 157 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 158 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 159 | 160 | df = transactions_heatmap.query('Blockchain == @options') 161 | df['Users'] = df.groupby('Blockchain')['Users'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 162 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Users', histfunc='avg', title='Hourly Heatmap of Normalized Users', nbinsy=24) 163 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 164 | fig.update_xaxes(categoryorder='category ascending') 165 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 166 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 167 | 168 | df = transactions_heatmap.query('Blockchain == @options') 169 | df['Blocks'] = df.groupby('Blockchain')['Blocks'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 170 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Blocks', histfunc='avg', title='Hourly Heatmap of Normalized Blocks', nbinsy=24) 171 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 172 | fig.update_xaxes(categoryorder='category ascending') 173 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 174 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) -------------------------------------------------------------------------------- /pages/2_🪙_Fees.py: -------------------------------------------------------------------------------- 1 | # Libraries 2 | import streamlit as st 3 | import pandas as pd 4 | import plotly.express as px 5 | import plotly.graph_objects as go 6 | import plotly.subplots as sp 7 | import data 8 | 9 | # Global Variables 10 | theme_plotly = None # None or streamlit 11 | week_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] 12 | 13 | # Config 14 | st.set_page_config(page_title='Fees - Cross Chain Monitoring', page_icon=':bar_chart:', layout='wide') 15 | 16 | # Outlier warning 17 | st.warning(""" 18 | The data within this app is no longer being updated. Feel free to check out the same author's 19 | new tool called the [Outlier](https://outlier.streamlit.app/) for a better UI/UX and a more 20 | modern way of presenting the same set of data. 21 | """) 22 | 23 | # Title 24 | st.title('🪙 Transaction Fees') 25 | 26 | # Style 27 | with open('style.css')as f: 28 | st.markdown(f"", unsafe_allow_html = True) 29 | 30 | # Data Sources 31 | transactions_overview = data.get_data('Transactions Overview') 32 | transactions_daily = data.get_data('Transactions Daily') 33 | transactions_heatmap = data.get_data('Transactions Heatmap') 34 | 35 | # Filter 36 | options = st.multiselect( 37 | '**Select your desired blockchains:**', 38 | options=transactions_overview['Blockchain'].unique(), 39 | default=transactions_overview['Blockchain'].unique(), 40 | key='fees_options' 41 | ) 42 | 43 | # Selected Blockchain 44 | if len(options) == 0: 45 | st.warning('Please select at least one blockchain to see the metrics.') 46 | 47 | # Single Chain Analysis 48 | elif len(options) == 1: 49 | st.subheader('Overview') 50 | df = transactions_overview.query("Blockchain == @options") 51 | c1, c2, c3, c4 = st.columns(4) 52 | with c1: 53 | st.metric(label='**Total Transaction Fees**', value=str(df['Fees'].map('{:,.0f}'.format).values[0]), help='USD') 54 | with c2: 55 | st.metric(label='**Average Fee Amount**', value=str(df['FeeAverage'].map('{:,.4f}'.format).values[0]), help='USD') 56 | with c3: 57 | st.metric(label='**Median Fee Amount**', value=str(df['FeeMedian'].map('{:,.4f}'.format).values[0]), help='USD') 58 | with c4: 59 | st.metric(label='**Average Fees/Block**', value=str(df['Fees/Block'].map('{:,.4f}'.format).values[0]), help='USD') 60 | 61 | st.subheader('Activity Over Time') 62 | df = transactions_daily.query("Blockchain == @options") 63 | 64 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 65 | fig.add_trace(go.Bar(x=df['Date'], y=df['Fees'], name='Total Fees'), secondary_y=False) 66 | fig.add_trace(go.Line(x=df['Date'], y=df['Fees/Block'], name='Fees/Block'), secondary_y=True) 67 | fig.update_layout(title_text='Daily Total Transaction Fees and Average Fees/Block') 68 | fig.update_yaxes(title_text='Total Fees [USD]', secondary_y=False) 69 | fig.update_yaxes(title_text='Fees/Block [USD]', secondary_y=True) 70 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 71 | 72 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 73 | fig.add_trace(go.Bar(x=df['Date'], y=df['FeeAverage'], name='Average'), secondary_y=False) 74 | fig.add_trace(go.Line(x=df['Date'], y=df['FeeMedian'], name='Median'), secondary_y=True) 75 | fig.update_layout(title_text='Daily Average and Median Fee') 76 | fig.update_yaxes(title_text='Average [USD]', secondary_y=False) 77 | fig.update_yaxes(title_text='Median [USD]', secondary_y=True) 78 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 79 | 80 | st.subheader('Activity Heatmap') 81 | df = transactions_heatmap.query("Blockchain == @options") 82 | 83 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Fees', histfunc='avg', title='Heatmap of Transaction Fees', nbinsx=24) 84 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 1}, coloraxis_colorbar=dict(title='Fees [USD]')) 85 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 86 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 87 | 88 | c1, c2 = st.columns(2) 89 | with c1: 90 | fig = px.density_heatmap(df, x='Hour', y='Day', z='FeeAverage', histfunc='avg', title='Heatmap of Average Fee', nbinsx=24) 91 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 1}, coloraxis_colorbar=dict(title='Average [USD]')) 92 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 93 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 94 | with c2: 95 | fig = px.density_heatmap(df, x='Hour', y='Day', z='FeeMedian', histfunc='avg', title='Heatmap of Median Fee', nbinsx=24) 96 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 1}, coloraxis_colorbar=dict(title='Median [USD]')) 97 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 98 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 99 | 100 | # Cross Chain Comparison 101 | else: 102 | st.subheader('Overview') 103 | df = transactions_overview.query("Blockchain == @options") 104 | 105 | fig = px.bar(df, x='Blockchain', y='Fees', color='Blockchain', title='Total Transaction Fees', log_y=True) 106 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Fees [USD]', xaxis={'categoryorder':'total ascending'}, hovermode='x unified') 107 | fig.update_traces(hovertemplate='%{y:,.0f}') 108 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 109 | 110 | c1, c2 = st.columns(2) 111 | with c1: 112 | fig = px.bar(df, x='Blockchain', y='FeeAverage', color='Blockchain', title='Average Fee Amount', log_y=True) 113 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Average Fee [USD]', xaxis={'categoryorder':'total ascending'}, hovermode='x unified') 114 | fig.update_traces(hovertemplate='%{y:,.6f}') 115 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 116 | with c2: 117 | fig = px.bar(df, x='Blockchain', y='FeeMedian', color='Blockchain', title='Median Fee Amount', log_y=True) 118 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Median Fee [USD]', xaxis={'categoryorder':'total ascending'}, hovermode='x unified') 119 | fig.update_traces(hovertemplate='%{y:,.6f}') 120 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 121 | 122 | st.subheader('Activity Over Time') 123 | 124 | df = transactions_daily.query('Blockchain == @options').sort_values(['Date', 'Fees'], ascending=[False, False]) 125 | fig = px.line(df, x='Date', y='Fees', color='Blockchain', custom_data=['Blockchain'], title='Daily Total Transaction Fees', log_y=True) 126 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Fees [USD]', hovermode='x unified') 127 | fig.update_traces(hovertemplate='%{customdata}: $%{y:,.0f}') 128 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 129 | 130 | c1, c2 = st.columns(2) 131 | with c1: 132 | df = transactions_daily.query('Blockchain == @options').sort_values(['Date', 'FeeAverage'], ascending=[False, False]) 133 | fig = px.line(df, x='Date', y='FeeAverage', color='Blockchain', custom_data=['Blockchain'], title='Daily Average Fee Amount', log_y=True) 134 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Average Fee [USD]', hovermode='x unified') 135 | fig.update_traces(hovertemplate='%{customdata}: $%{y:,.6f}') 136 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 137 | with c2: 138 | df = transactions_daily.query('Blockchain == @options').sort_values(['Date', 'FeeMedian'], ascending=[False, False]) 139 | fig = px.line(df, x='Date', y='FeeMedian', color='Blockchain', custom_data=['Blockchain'], title='Daily Median Fee Amount', log_y=True) 140 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Median Fee [USD]', hovermode='x unified') 141 | fig.update_traces(hovertemplate='%{customdata}: $%{y:,.6f}') 142 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 143 | 144 | st.subheader('Activity Heatmap') 145 | c1, c2 = st.columns(2) 146 | with c1: 147 | df = transactions_heatmap.query("Blockchain == @options") 148 | df['Fees'] = df.groupby('Blockchain')['Fees'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 149 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Fees', histfunc='avg', title='Daily Heatmap of Normalized Fees') 150 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 151 | fig.update_xaxes(categoryorder='category ascending') 152 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 153 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 154 | 155 | df = transactions_heatmap.query("Blockchain == @options") 156 | df['FeeAverage'] = df.groupby('Blockchain')['FeeAverage'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 157 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='FeeAverage', histfunc='avg', title='Daily Heatmap of Normalized Average Fee') 158 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 159 | fig.update_xaxes(categoryorder='category ascending') 160 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 161 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 162 | 163 | df = transactions_heatmap.query("Blockchain == @options") 164 | df['FeeMedian'] = df.groupby('Blockchain')['FeeMedian'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 165 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='FeeMedian', histfunc='avg', title='Daily Heatmap of Normalized Median Fee') 166 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 167 | fig.update_xaxes(categoryorder='category ascending') 168 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 169 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 170 | with c2: 171 | df = transactions_heatmap.query("Blockchain == @options") 172 | df['Fees'] = df.groupby('Blockchain')['Fees'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 173 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Fees', histfunc='avg', title='Hourly Heatmap of Normalized Fees', nbinsy=24) 174 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 175 | fig.update_xaxes(categoryorder='category ascending') 176 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 177 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 178 | 179 | df = transactions_heatmap.query("Blockchain == @options") 180 | df['FeeAverage'] = df.groupby('Blockchain')['FeeAverage'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 181 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='FeeAverage', histfunc='avg', title='Hourly Heatmap of Normalized Average Fee', nbinsy=24) 182 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 183 | fig.update_xaxes(categoryorder='category ascending') 184 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 185 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 186 | 187 | df = transactions_heatmap.query("Blockchain == @options") 188 | df['FeeMedian'] = df.groupby('Blockchain')['FeeMedian'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 189 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='FeeMedian', histfunc='avg', title='Hourly Heatmap of Normalized Median Fee', nbinsy=24) 190 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 191 | fig.update_xaxes(categoryorder='category ascending') 192 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 193 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) -------------------------------------------------------------------------------- /pages/3_💸_Transfers.py: -------------------------------------------------------------------------------- 1 | # Libraries 2 | import streamlit as st 3 | import pandas as pd 4 | import plotly.express as px 5 | import plotly.graph_objects as go 6 | import plotly.subplots as sp 7 | import data 8 | 9 | # Global Variables 10 | theme_plotly = None # None or streamlit 11 | week_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] 12 | 13 | # Config 14 | st.set_page_config(page_title='USDC Transfers - Cross Chain Monitoring', page_icon=':bar_chart:', layout='wide') 15 | 16 | # Outlier warning 17 | st.warning(""" 18 | The data within this app is no longer being updated. Feel free to check out the same author's 19 | new tool called the [Outlier](https://outlier.streamlit.app/) for a better UI/UX and a more 20 | modern way of presenting the same set of data. 21 | """) 22 | 23 | # Title 24 | st.title('💸 USDC Transfers') 25 | 26 | # Style 27 | with open('style.css')as f: 28 | st.markdown(f"", unsafe_allow_html = True) 29 | 30 | # Data Sources 31 | transfers_overview = data.get_data('Transfers Overview') 32 | transfers_daily = data.get_data('Transfers Daily') 33 | transfers_heatmap = data.get_data('Transfers Heatmap') 34 | 35 | # Filter 36 | options = st.multiselect( 37 | '**Select your desired blockchains:**', 38 | options=transfers_overview['Blockchain'].unique(), 39 | default=transfers_overview['Blockchain'].unique(), 40 | key='transfers_options' 41 | ) 42 | 43 | # Selected Blockchain 44 | if len(options) == 0: 45 | st.warning('Please select at least one blockchain to see the metrics.') 46 | 47 | # Single Chain Analysis 48 | elif len(options) == 1: 49 | st.subheader('Overview') 50 | df = transfers_overview.query('Blockchain == @options') 51 | c1, c2, c3 = st.columns(3) 52 | with c1: 53 | st.metric(label='**Total Transferred Volume**', value=str(df['Volume'].map('{:,.0f}'.format).values[0]), help='USD') 54 | st.metric(label='**Average Transferred Volume/Day**', value=str(df['Volume/Day'].map('{:,.0f}'.format).values[0]), help='USD') 55 | with c2: 56 | st.metric(label='**Total Transfers**', value=str(df['Transfers'].map('{:,.0f}'.format).values[0])) 57 | st.metric(label='**Average Transfers/Day**', value=str(df['Transfers/Day'].map('{:,.0f}'.format).values[0])) 58 | with c3: 59 | st.metric(label='**Total Transferring Users**', value=str(df['Users'].map('{:,.0f}'.format).values[0])) 60 | st.metric(label='**Average Transferring Users/Day**', value=str(df['Users/Day'].map('{:,.0f}'.format).values[0])) 61 | c1, c2, c3, c4 = st.columns(4) 62 | with c1: 63 | st.metric(label='**Average Transferred Amount**', value=str(df['AmountAverage'].map('{:,.0f}'.format).values[0]), help='USD') 64 | with c2: 65 | st.metric(label='**Median Transferred Amount**', value=str(df['AmountMedian'].map('{:,.2f}'.format).values[0]), help='USD') 66 | with c3: 67 | st.metric(label='**Average Volume/User**', value=str(df['Volume/User'].map('{:,.0f}'.format).values[0]), help='USD') 68 | with c4: 69 | st.metric(label='**Average Transfers/User**', value=str(df['Transfers/User'].map('{:,.0f}'.format).values[0])) 70 | 71 | st.subheader('Activity Over Time') 72 | df = transfers_daily.query('Blockchain == @options') 73 | 74 | fig = px.area(df, x='Date', y='Volume', title='Daily Transferred Volume') 75 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Volume [USD]') 76 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 77 | 78 | c1, c2 = st.columns(2) 79 | with c1: 80 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 81 | fig.add_trace(go.Bar(x=df['Date'], y=df['Transfers'], name='Transfers'), secondary_y=False) 82 | fig.add_trace(go.Line(x=df['Date'], y=df['Users'], name='Users'), secondary_y=True) 83 | fig.update_layout(title_text='Daily Transfers and Transferring Users') 84 | fig.update_yaxes(title_text='Transfers', secondary_y=False) 85 | fig.update_yaxes(title_text='Users', secondary_y=True) 86 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 87 | with c2: 88 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 89 | fig.add_trace(go.Bar(x=df['Date'], y=df['AmountAverage'], name='Average'), secondary_y=False) 90 | fig.add_trace(go.Line(x=df['Date'], y=df['AmountMedian'], name='Median'), secondary_y=True) 91 | fig.update_layout(title_text='Daily Average and Median Transferred Amount') 92 | fig.update_yaxes(title_text='Average [USD]', secondary_y=False) 93 | fig.update_yaxes(title_text='Median [USD]', secondary_y=True) 94 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 95 | 96 | st.subheader('Activity Heatmap') 97 | df = transfers_heatmap.query('Blockchain == @options') 98 | 99 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Volume', histfunc='avg', title='Heatmap of Transferred Volume', nbinsx=24) 100 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 1}, coloraxis_colorbar=dict(title='Volume [USD]')) 101 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 102 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 103 | c1, c2 = st.columns(2) 104 | with c1: 105 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Transfers', histfunc='avg', title='Heatmap of Transfers', nbinsx=24) 106 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Transfers')) 107 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 108 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 109 | 110 | fig = px.density_heatmap(df, x='Hour', y='Day', z='AmountAverage', histfunc='avg', title='Heatmap of Average Transferred Amount', nbinsx=24) 111 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Average [USD]')) 112 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 113 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 114 | with c2: 115 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Users', histfunc='avg', title='Heatmap of Transferring Users', nbinsx=24) 116 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Users')) 117 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 118 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 119 | 120 | fig = px.density_heatmap(df, x='Hour', y='Day', z='AmountMedian', histfunc='avg', title='Heatmap of Median Transferred Amount', nbinsx=24) 121 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Median [USD]')) 122 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 123 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 124 | 125 | # Cross Chain Comparison 126 | else: 127 | subtab_overview, subtab_heatmap = st.tabs(['**Overview**', '**Heatmap**']) 128 | 129 | with subtab_overview: 130 | st.subheader('Overview') 131 | df = transfers_overview.query('Blockchain == @options') 132 | c1, c2, c3 = st.columns(3) 133 | with c1: 134 | fig = px.bar(df, x='Blockchain', y='Volume', color='Blockchain', title='Total Transferred Volume', log_y=True) 135 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Volume [USD]', xaxis={'categoryorder':'total ascending'}) 136 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 137 | 138 | fig = px.bar(df, x='Blockchain', y='Volume/Day', color='Blockchain', title='Average Daily Transferred Volume', log_y=True) 139 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Volume [USD]', xaxis={'categoryorder':'total ascending'}) 140 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 141 | with c2: 142 | fig = px.bar(df, x='Blockchain', y='Transfers', color='Blockchain', title='Total Transfers', log_y=True) 143 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Transfers', xaxis={'categoryorder':'total ascending'}) 144 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 145 | 146 | fig = px.bar(df, x='Blockchain', y='Transfers/Day', color='Blockchain', title='Average Daily Transfers', log_y=True) 147 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Transfers', xaxis={'categoryorder':'total ascending'}) 148 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 149 | 150 | with c3: 151 | fig = px.bar(df, x='Blockchain', y='Users', color='Blockchain', title='Total Transferring Users', log_y=True) 152 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Users', xaxis={'categoryorder':'total ascending'}) 153 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 154 | 155 | fig = px.bar(df, x='Blockchain', y='Users/Day', color='Blockchain', title='Average Daily Transferring Users', log_y=True) 156 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Users', xaxis={'categoryorder':'total ascending'}) 157 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 158 | 159 | c1, c2 = st.columns(2) 160 | with c1: 161 | fig = px.bar(transfers_overview, x='Blockchain', y='AmountAverage', color='Blockchain', title='Average Transferred Amount', log_y=True) 162 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Average [USD]', xaxis={'categoryorder':'total ascending'}) 163 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 164 | with c2: 165 | fig = px.bar(transfers_overview, x='Blockchain', y='AmountMedian', color='Blockchain', title='Median Transferred Amount', log_y=True) 166 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Median [USD]', xaxis={'categoryorder':'total ascending'}) 167 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 168 | 169 | st.subheader('Market Shares') 170 | c1, c2, c3 = st.columns(3) 171 | with c1: 172 | fig = px.pie(df, values='Volume', names='Blockchain', title='Share of Total Transferred Volume') 173 | fig.update_layout(legend_title=None, legend_y=0.5) 174 | fig.update_traces(textinfo='percent+label', textposition='inside') 175 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 176 | with c2: 177 | fig = px.pie(df, values='Transfers', names='Blockchain', title='Share of Total Transfers') 178 | fig.update_layout(legend_title=None, legend_y=0.5) 179 | fig.update_traces(textinfo='percent+label', textposition='inside') 180 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 181 | with c3: 182 | fig = px.pie(df, values='Users', names='Blockchain', title='Share of Total Transferring Users') 183 | fig.update_layout(legend_title=None, legend_y=0.5) 184 | fig.update_traces(textinfo='percent+label', textposition='inside') 185 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 186 | 187 | st.subheader('Activity Over Time') 188 | df = transfers_daily.query('Blockchain == @options') 189 | c1, c2 = st.columns(2) 190 | with c1: 191 | fig = px.line(df, x='Date', y='Volume', color='Blockchain', title='Daily Transferred Volume', log_y=True) 192 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Volume [USD]') 193 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 194 | 195 | fig = px.line(df, x='Date', y='Transfers', color='Blockchain', title='Daily Transfers', log_y=True) 196 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Transfers') 197 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 198 | 199 | fig = px.line(df, x='Date', y='Users', color='Blockchain', title='Daily Transferring Users', log_y=True) 200 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Users') 201 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 202 | 203 | fig = px.line(df, x='Date', y='AmountAverage', color='Blockchain', title='Daily Average Transferred Amount') 204 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Amount [USD]') 205 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 206 | with c2: 207 | fig = go.Figure() 208 | for i in options: 209 | fig.add_trace(go.Scatter( 210 | name=i, 211 | x=df.query("Blockchain == @i")['Date'], 212 | y=df.query("Blockchain == @i")['Volume'], 213 | mode='lines', 214 | stackgroup='one', 215 | groupnorm='percent' 216 | )) 217 | fig.update_layout(title='Daily Share of Transferred Volume') 218 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 219 | 220 | fig = go.Figure() 221 | for i in options: 222 | fig.add_trace(go.Scatter( 223 | name=i, 224 | x=df.query("Blockchain == @i")['Date'], 225 | y=df.query("Blockchain == @i")['Transfers'], 226 | mode='lines', 227 | stackgroup='one', 228 | groupnorm='percent' 229 | )) 230 | fig.update_layout(title='Daily Share of Transfers') 231 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 232 | 233 | fig = go.Figure() 234 | for i in options: 235 | fig.add_trace(go.Scatter( 236 | name=i, 237 | x=df.query("Blockchain == @i")['Date'], 238 | y=df.query("Blockchain == @i")['Users'], 239 | mode='lines', 240 | stackgroup='one', 241 | groupnorm='percent' 242 | )) 243 | fig.update_layout(title='Daily Share of Transferring Users') 244 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 245 | 246 | fig = px.line(df, x='Date', y='AmountMedian', color='Blockchain', title='Daily Median Transferred Amount') 247 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Median [USD]') 248 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 249 | 250 | with subtab_heatmap: 251 | st.subheader('Activity Heatmap') 252 | c1, c2 = st.columns(2) 253 | with c1: 254 | df = transfers_heatmap.query("Blockchain == @options") 255 | df['Volume'] = df.groupby('Blockchain')['Volume'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 256 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Volume', histfunc='avg', title='Daily Heatmap of Normalized Transferred Volume') 257 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 258 | fig.update_xaxes(categoryorder='category ascending') 259 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 260 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 261 | 262 | df = transfers_heatmap.query("Blockchain == @options") 263 | df['Transfers'] = df.groupby('Blockchain')['Transfers'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 264 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Transfers', histfunc='avg', title='Daily Heatmap of Normalized Transfers') 265 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 266 | fig.update_xaxes(categoryorder='category ascending') 267 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 268 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 269 | 270 | df = transfers_heatmap.query("Blockchain == @options") 271 | df['Users'] = df.groupby('Blockchain')['Users'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 272 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Users', histfunc='avg', title='Daily Heatmap of Normalized Transferring Users') 273 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 274 | fig.update_xaxes(categoryorder='category ascending') 275 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 276 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 277 | 278 | df = transfers_heatmap.query("Blockchain == @options") 279 | df['AmountAverage'] = df.groupby('Blockchain')['AmountAverage'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 280 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='AmountAverage', histfunc='avg', title='Daily Heatmap of Normalized Average Transferred Amount') 281 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 282 | fig.update_xaxes(categoryorder='category ascending') 283 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 284 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 285 | 286 | df = transfers_heatmap.query("Blockchain == @options") 287 | df['AmountMedian'] = df.groupby('Blockchain')['AmountMedian'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 288 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='AmountMedian', histfunc='avg', title='Daily Heatmap of Normalized Median Transferred Amount') 289 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 290 | fig.update_xaxes(categoryorder='category ascending') 291 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 292 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 293 | with c2: 294 | df = transfers_heatmap.query("Blockchain == @options") 295 | df['Volume'] = df.groupby('Blockchain')['Volume'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 296 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Volume', histfunc='avg', title='Hourly Heatmap of Normalized Transferred Volume', nbinsy=24) 297 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 298 | fig.update_xaxes(categoryorder='category ascending') 299 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 300 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 301 | 302 | df = transfers_heatmap.query("Blockchain == @options") 303 | df['Transfers'] = df.groupby('Blockchain')['Transfers'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 304 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Transfers', histfunc='avg', title='Hourly Heatmap of Normalized Transfers', nbinsy=24) 305 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 306 | fig.update_xaxes(categoryorder='category ascending') 307 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 308 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 309 | 310 | df = transfers_heatmap.query("Blockchain == @options") 311 | df['Users'] = df.groupby('Blockchain')['Users'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 312 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Users', histfunc='avg', title='Hourly Heatmap of Normalized Transferring Users', nbinsy=24) 313 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 314 | fig.update_xaxes(categoryorder='category ascending') 315 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 316 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 317 | 318 | df = transfers_heatmap.query("Blockchain == @options") 319 | df['AmountAverage'] = df.groupby('Blockchain')['AmountAverage'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 320 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='AmountAverage', histfunc='avg', title='Hourly Heatmap of Normalized Average Transferred Amount', nbinsy=24) 321 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 322 | fig.update_xaxes(categoryorder='category ascending') 323 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 324 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 325 | 326 | df = transfers_heatmap.query("Blockchain == @options") 327 | df['AmountMedian'] = df.groupby('Blockchain')['AmountMedian'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 328 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='AmountMedian', histfunc='avg', title='Hourly Heatmap of Normalized Median Transferred Amount', nbinsy=24) 329 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 330 | fig.update_xaxes(categoryorder='category ascending') 331 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 332 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) -------------------------------------------------------------------------------- /pages/4_🔄_Swaps.py: -------------------------------------------------------------------------------- 1 | # Libraries 2 | import streamlit as st 3 | import pandas as pd 4 | import plotly.express as px 5 | import plotly.graph_objects as go 6 | import plotly.subplots as sp 7 | import data 8 | 9 | # Global Variables 10 | theme_plotly = None # None or streamlit 11 | week_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] 12 | 13 | # Config 14 | st.set_page_config(page_title='Swaps - Cross Chain Monitoring', page_icon=':bar_chart:', layout='wide') 15 | 16 | # Outlier warning 17 | st.warning(""" 18 | The data within this app is no longer being updated. Feel free to check out the same author's 19 | new tool called the [Outlier](https://outlier.streamlit.app/) for a better UI/UX and a more 20 | modern way of presenting the same set of data. 21 | """) 22 | 23 | # Title 24 | st.title('🔄 Swaps') 25 | 26 | # Style 27 | with open('style.css')as f: 28 | st.markdown(f"", unsafe_allow_html = True) 29 | 30 | # Data Sources 31 | swaps_overview = data.get_data('Swaps Overview') 32 | swaps_daily = data.get_data('Swaps Daily') 33 | swaps_heatmap = data.get_data('Swaps Heatmap') 34 | 35 | # Filter 36 | options = st.multiselect( 37 | '**Select your desired blockchains:**', 38 | options=swaps_overview['Blockchain'].unique(), 39 | default=swaps_overview['Blockchain'].unique(), 40 | key='swaps_options' 41 | ) 42 | 43 | # Selected Blockchain 44 | if len(options) == 0: 45 | st.warning('Please select at least one blockchain to see the metrics.') 46 | 47 | # Single Chain Analysis 48 | elif len(options) == 1: 49 | st.subheader('Overview') 50 | df = swaps_overview.query('Blockchain == @options') 51 | c1, c2, c3 = st.columns(3) 52 | with c1: 53 | st.metric(label='**Total Swapped Volume**', value=str(df['Volume'].map('{:,.0f}'.format).values[0]), help='USD') 54 | st.metric(label='**Average Swapped Volume/Day**', value=str(df['Volume/Day'].map('{:,.0f}'.format).values[0]), help='USD') 55 | with c2: 56 | st.metric(label='**Total Swaps**', value=str(df['Swaps'].map('{:,.0f}'.format).values[0])) 57 | st.metric(label='**Average Swaps/Day**', value=str(df['Swaps/Day'].map('{:,.0f}'.format).values[0])) 58 | with c3: 59 | st.metric(label='**Total Swappers**', value=str(df['Swappers'].map('{:,.0f}'.format).values[0])) 60 | st.metric(label='**Average Swappers/Day**', value=str(df['Swappers/Day'].map('{:,.0f}'.format).values[0])) 61 | c1, c2, c3, c4 = st.columns(4) 62 | with c1: 63 | st.metric(label='**Average Swapped Amount**', value=str(df['AmountAverage'].map('{:,.2f}'.format).values[0]), help='USD') 64 | with c2: 65 | st.metric(label='**Median Swapped Amount**', value=str(df['AmountMedian'].map('{:,.2f}'.format).values[0]), help='USD') 66 | with c3: 67 | st.metric(label='**Average Volume/Swapper**', value=str(df['Volume/Swapper'].map('{:,.0f}'.format).values[0]), help='USD') 68 | with c4: 69 | st.metric(label='**Average Swaps/Swapper**', value=str(df['Swaps/Swapper'].map('{:,.0f}'.format).values[0])) 70 | 71 | st.subheader('Activity Over Time') 72 | df = swaps_daily.query('Blockchain == @options') 73 | 74 | fig = px.area(df, x='Date', y='Volume', title='Daily Swapped Volume of') 75 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Volume [USD]') 76 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 77 | 78 | c1, c2 = st.columns(2) 79 | with c1: 80 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 81 | fig.add_trace(go.Bar(x=df['Date'], y=df['Swaps'], name='Swaps'), secondary_y=False) 82 | fig.add_trace(go.Line(x=df['Date'], y=df['Swappers'], name='Swappers'), secondary_y=True) 83 | fig.update_layout(title_text='Daily Swaps and Swappers') 84 | fig.update_yaxes(title_text='Swaps', secondary_y=False) 85 | fig.update_yaxes(title_text='Swappers', secondary_y=True) 86 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 87 | with c2: 88 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 89 | fig.add_trace(go.Bar(x=df['Date'], y=df['AmountAverage'], name='Average'), secondary_y=False) 90 | fig.add_trace(go.Line(x=df['Date'], y=df['AmountMedian'], name='Median'), secondary_y=True) 91 | fig.update_layout(title_text='Daily Average and Median Swapped Amount') 92 | fig.update_yaxes(title_text='Average [USD]', secondary_y=False) 93 | fig.update_yaxes(title_text='Median [USD]', secondary_y=True) 94 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 95 | 96 | st.subheader('Activity Heatmap') 97 | df = swaps_heatmap.query('Blockchain == @options') 98 | 99 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Volume', histfunc='avg', title='Heatmap of Swapped Volume', nbinsx=24) 100 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 1}, coloraxis_colorbar=dict(title='Volume [USD]')) 101 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 102 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 103 | c1, c2 = st.columns(2) 104 | with c1: 105 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Swaps', histfunc='avg', title='Heatmap of Swaps', nbinsx=24) 106 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Swaps')) 107 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 108 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 109 | 110 | fig = px.density_heatmap(df, x='Hour', y='Day', z='AmountAverage', histfunc='avg', title='Heatmap of Average Swapped Amount', nbinsx=24) 111 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Average [USD]')) 112 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 113 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 114 | with c2: 115 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Swappers', histfunc='avg', title='Heatmap of Swappers', nbinsx=24) 116 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Swappers')) 117 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 118 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 119 | 120 | fig = px.density_heatmap(df, x='Hour', y='Day', z='AmountMedian', histfunc='avg', title='Heatmap of Median Swapped Amount', nbinsx=24) 121 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Median [USD]')) 122 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 123 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 124 | 125 | # Cross Chain Comparison 126 | else: 127 | subtab_overview, subtab_heatmap = st.tabs(['Overview', 'Heatmap']) 128 | with subtab_overview: 129 | st.subheader('Overview') 130 | df = swaps_overview.query('Blockchain == @options') 131 | c1, c2, c3 = st.columns(3) 132 | with c1: 133 | fig = px.bar(df, x='Blockchain', y='Volume', color='Blockchain', title='Total Swapped Volume', log_y=True) 134 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Volume [USD]', xaxis={'categoryorder':'total ascending'}) 135 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 136 | 137 | fig = px.bar(df, x='Blockchain', y='Volume/Day', color='Blockchain', title='Average Swapped Volume/Day', log_y=True) 138 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Daily Volume [USD]', xaxis={'categoryorder':'total ascending'}) 139 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 140 | 141 | with c2: 142 | fig = px.bar(df, x='Blockchain', y='Swaps', color='Blockchain', title='Total Swaps', log_y=True) 143 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Swaps', xaxis={'categoryorder':'total ascending'}) 144 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 145 | 146 | fig = px.bar(df, x='Blockchain', y='Swaps/Day', color='Blockchain', title='Average Swaps/Day', log_y=True) 147 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Daily Swaps', xaxis={'categoryorder':'total ascending'}) 148 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 149 | 150 | with c3: 151 | fig = px.bar(df, x='Blockchain', y='Swappers', color='Blockchain', title='Total Swappers', log_y=True) 152 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Swappers', xaxis={'categoryorder':'total ascending'}) 153 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 154 | 155 | fig = px.bar(df, x='Blockchain', y='Swappers/Day', color='Blockchain', title='Average Swappers/Day', log_y=True) 156 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Daily Swappers', xaxis={'categoryorder':'total ascending'}) 157 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 158 | 159 | c1, c2 = st.columns(2) 160 | with c1: 161 | fig = px.bar(df, x='Blockchain', y='Volume/Swapper', color='Blockchain', title='Average Volume/Swapper', log_y=True) 162 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Volume/Swapper [USD]', xaxis={'categoryorder':'total ascending'}) 163 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 164 | 165 | fig = px.bar(df, x='Blockchain', y='AmountAverage', color='Blockchain', title='Average Swapped Amount', log_y=True) 166 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Average [USD]', xaxis={'categoryorder':'total ascending'}) 167 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 168 | with c2: 169 | fig = px.bar(df, x='Blockchain', y='Swaps/Swapper', color='Blockchain', title='Average Swaps/Swapper', log_y=True) 170 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Swaps/Swapper', xaxis={'categoryorder':'total ascending'}) 171 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 172 | 173 | fig = px.bar(df, x='Blockchain', y='AmountMedian', color='Blockchain', title='Median Swapped Amount', log_y=True) 174 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Median [USD]', xaxis={'categoryorder':'total ascending'}) 175 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 176 | 177 | st.subheader('Market Shares') 178 | c1, c2, c3 = st.columns(3) 179 | with c1: 180 | fig = px.pie(df, values='Volume', names='Blockchain', title='Share of Total Swapped Volume') 181 | fig.update_layout(legend_title=None, legend_y=0.5) 182 | fig.update_traces(textinfo='percent+label', textposition='inside') 183 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 184 | with c2: 185 | fig = px.pie(df, values='Swaps', names='Blockchain', title='Share of Total Swaps') 186 | fig.update_layout(legend_title=None, legend_y=0.5) 187 | fig.update_traces(textinfo='percent+label', textposition='inside') 188 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 189 | with c3: 190 | fig = px.pie(df, values='Swappers', names='Blockchain', title='Share of Total Swappers') 191 | fig.update_layout(legend_title=None, legend_y=0.5) 192 | fig.update_traces(textinfo='percent+label', textposition='inside') 193 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 194 | 195 | st.subheader('Activity Over Time') 196 | df = swaps_daily.query('Blockchain == @options') 197 | c1, c2 = st.columns(2) 198 | with c1: 199 | fig = px.line(df, x='Date', y='Volume', color='Blockchain', title='Daily Swapped Volume', log_y=True) 200 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Volume [USD]') 201 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 202 | 203 | fig = px.line(df, x='Date', y='Swaps', color='Blockchain', title='Daily Swaps', log_y=True) 204 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Swaps') 205 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 206 | 207 | fig = px.line(df, x='Date', y='Swappers', color='Blockchain', title='Daily Swappers', log_y=True) 208 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Swappers') 209 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 210 | 211 | fig = px.line(df, x='Date', y='AmountAverage', color='Blockchain', title='Daily Average Swapped Amount', log_y=True) 212 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Average [USD]') 213 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 214 | 215 | with c2: 216 | fig = go.Figure() 217 | for i in options: 218 | fig.add_trace(go.Scatter( 219 | name=i, 220 | x=df.query("Blockchain == @i")['Date'], 221 | y=df.query("Blockchain == @i")['Volume'], 222 | mode='lines', 223 | stackgroup='one', 224 | groupnorm='percent' 225 | )) 226 | fig.update_layout(title='Daily Share of Swapped Volume') 227 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 228 | 229 | fig = go.Figure() 230 | for i in options: 231 | fig.add_trace(go.Scatter( 232 | name=i, 233 | x=df.query("Blockchain == @i")['Date'], 234 | y=df.query("Blockchain == @i")['Swaps'], 235 | mode='lines', 236 | stackgroup='one', 237 | groupnorm='percent' 238 | )) 239 | fig.update_layout(title='Daily Share of Swaps') 240 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 241 | 242 | fig = go.Figure() 243 | for i in options: 244 | fig.add_trace(go.Scatter( 245 | name=i, 246 | x=df.query("Blockchain == @i")['Date'], 247 | y=df.query("Blockchain == @i")['Swappers'], 248 | mode='lines', 249 | stackgroup='one', 250 | groupnorm='percent' 251 | )) 252 | fig.update_layout(title='Daily Share of Swappers') 253 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 254 | 255 | fig = px.line(df, x='Date', y='AmountMedian', color='Blockchain', title='Daily Median Swapped Amount', log_y=True) 256 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Median [USD]') 257 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 258 | 259 | with subtab_heatmap: 260 | st.subheader('Heatmap of Swaps') 261 | c1, c2 = st.columns(2) 262 | with c1: 263 | df = swaps_heatmap.query("Blockchain == @options") 264 | df['Volume'] = df.groupby('Blockchain')['Volume'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 265 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Volume', histfunc='avg', title='Daily Heatmap of Normalized Swapped Volume') 266 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 267 | fig.update_xaxes(categoryorder='category ascending') 268 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 269 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 270 | 271 | df = swaps_heatmap.query("Blockchain == @options") 272 | df['Swaps'] = df.groupby('Blockchain')['Swaps'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 273 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Swaps', histfunc='avg', title='Daily Heatmap of Normalized Swaps') 274 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 275 | fig.update_xaxes(categoryorder='category ascending') 276 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 277 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 278 | 279 | df = swaps_heatmap.query("Blockchain == @options") 280 | df['Swappers'] = df.groupby('Blockchain')['Swappers'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 281 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Swappers', histfunc='avg', title='Daily Heatmap of Normalized Swappers') 282 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 283 | fig.update_xaxes(categoryorder='category ascending') 284 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 285 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 286 | 287 | df = swaps_heatmap.query("Blockchain == @options") 288 | df['AmountAverage'] = df.groupby('Blockchain')['AmountAverage'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 289 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='AmountAverage', histfunc='avg', title='Daily Heatmap of Normalized Average Swapped Amount') 290 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 291 | fig.update_xaxes(categoryorder='category ascending') 292 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 293 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 294 | 295 | df = swaps_heatmap.query("Blockchain == @options") 296 | df['AmountMedian'] = df.groupby('Blockchain')['AmountMedian'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 297 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='AmountMedian', histfunc='avg', title='Daily Heatmap of Normalized Median Swapped Amount') 298 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 299 | fig.update_xaxes(categoryorder='category ascending') 300 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 301 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 302 | 303 | with c2: 304 | df = swaps_heatmap.query("Blockchain == @options") 305 | df['Volume'] = df.groupby('Blockchain')['Volume'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 306 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Volume', histfunc='avg', title='Hourly Heatmap of Normalized Swapped Volume', nbinsy=24) 307 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 308 | fig.update_xaxes(categoryorder='category ascending') 309 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 310 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 311 | 312 | df = swaps_heatmap.query("Blockchain == @options") 313 | df['Swaps'] = df.groupby('Blockchain')['Swaps'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 314 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Swaps', histfunc='avg', title='Hourly Heatmap of Normalized Swaps', nbinsy=24) 315 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 316 | fig.update_xaxes(categoryorder='category ascending') 317 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 318 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 319 | 320 | df = swaps_heatmap.query("Blockchain == @options") 321 | df['Swappers'] = df.groupby('Blockchain')['Swappers'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 322 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Swappers', histfunc='avg', title='Hourly Heatmap of Normalized Swappers', nbinsy=24) 323 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 324 | fig.update_xaxes(categoryorder='category ascending') 325 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 326 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 327 | 328 | df = swaps_heatmap.query("Blockchain == @options") 329 | df['AmountAverage'] = df.groupby('Blockchain')['AmountAverage'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 330 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='AmountAverage', histfunc='avg', title='Hourly Heatmap of Normalized Average Swapped Amount', nbinsy=24) 331 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 332 | fig.update_xaxes(categoryorder='category ascending') 333 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 334 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 335 | 336 | df = swaps_heatmap.query("Blockchain == @options") 337 | df['AmountMedian'] = df.groupby('Blockchain')['AmountMedian'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 338 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='AmountMedian', histfunc='avg', title='Hourly Heatmap of Normalized Average Swapped Amount', nbinsy=24) 339 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 340 | fig.update_xaxes(categoryorder='category ascending') 341 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 342 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) -------------------------------------------------------------------------------- /pages/5_🛍️_NFT_Sales.py: -------------------------------------------------------------------------------- 1 | # Libraries 2 | import streamlit as st 3 | import pandas as pd 4 | import plotly.express as px 5 | import plotly.graph_objects as go 6 | import plotly.subplots as sp 7 | import data 8 | 9 | # Global Variables 10 | theme_plotly = None # None or streamlit 11 | week_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] 12 | 13 | # Config 14 | st.set_page_config(page_title='NFTs - Cross Chain Monitoring', page_icon=':bar_chart:', layout='wide') 15 | 16 | # Outlier warning 17 | st.warning(""" 18 | The data within this app is no longer being updated. Feel free to check out the same author's 19 | new tool called the [Outlier](https://outlier.streamlit.app/) for a better UI/UX and a more 20 | modern way of presenting the same set of data. 21 | """) 22 | 23 | # Title 24 | st.title('🛍️ NFT Sales') 25 | 26 | # Style 27 | with open('style.css')as f: 28 | st.markdown(f"", unsafe_allow_html = True) 29 | 30 | # Data Sources 31 | nfts_overview = data.get_data('NFTs Overview') 32 | nfts_daily = data.get_data('NFTs Daily') 33 | nfts_heatmap = data.get_data('NFTs Heatmap') 34 | 35 | # Filter 36 | options = st.multiselect( 37 | '**Select your desired blockchains:**', 38 | options=nfts_overview['Blockchain'].unique(), 39 | default=nfts_overview['Blockchain'].unique(), 40 | key='nfts_options' 41 | ) 42 | 43 | # Selected Blockchain 44 | if len(options) == 0: 45 | st.warning('Please select at least one blockchain to see the metrics.') 46 | 47 | # Single Chain Analysis 48 | elif len(options) == 1: 49 | st.subheader('Overview') 50 | df = nfts_overview.query('Blockchain == @options') 51 | c1, c2, c3 = st.columns(3) 52 | with c1: 53 | st.metric(label='**Total Sales Volume**', value=str(df['Volume'].map('{:,.0f}'.format).values[0]), help='USD') 54 | st.metric(label='**Total Traded NFTs**', value=str(df['NFTs'].map('{:,.0f}'.format).values[0])) 55 | st.metric(label='**Average NFT Price**', value=str(df['PriceAverage'].map('{:,.2f}'.format).values[0]), help='USD') 56 | with c2: 57 | st.metric(label='**Total Sales**', value=str(df['Sales'].map('{:,.0f}'.format).values[0])) 58 | st.metric(label='**Total Traded Collections**', value=str(df['Collections'].map('{:,.0f}'.format).values[0])) 59 | st.metric(label='**Median NFT Price**', value=str(df['PriceMedian'].map('{:,.2f}'.format).values[0]), help='USD') 60 | with c3: 61 | st.metric(label='**Total Unique Buyers**', value=str(df['Buyers'].map('{:,.0f}'.format).values[0])) 62 | st.metric(label='**Marketplaces**', value=str(df['Marketplaces'].map('{:,.0f}'.format).values[0])) 63 | st.metric(label='**Highest NFT Price**', value=str(df['PriceMax'].map('{:,.2f}'.format).values[0]), help='USD') 64 | 65 | st.subheader('Averages') 66 | c1, c2, c3, c4 = st.columns(4) 67 | with c1: 68 | st.metric(label='**Average Daily Volume**', value=str(df['Volume/Day'].map('{:,.0f}'.format).values[0]), help='USD') 69 | st.metric(label='**Average Daily Traded NFTs**', value=str(df['NFTs/Day'].map('{:,.0f}'.format).values[0])) 70 | st.metric(label='**Average Volume/Collection**', value=str(df['Volume/Collection'].map('{:,.0f}'.format).values[0]), help='USD') 71 | with c2: 72 | st.metric(label='**Average Volume/Buyer**', value=str(df['Volume/Buyer'].map('{:,.0f}'.format).values[0]), help='USD') 73 | st.metric(label='**Average NFTs/Buyer**', value=str(df['NFTs/Buyer'].map('{:,.2f}'.format).values[0])) 74 | st.metric(label='**Average NFTs/Collection**', value=str(df['NFTs/Collection'].map('{:,.0f}'.format).values[0])) 75 | with c3: 76 | st.metric(label='**Average Daily Sales**', value=str(df['Sales/Day'].map('{:,.0f}'.format).values[0])) 77 | st.metric(label='**Average Daily Traded Collections**', value=str(df['Collections/Day'].map('{:,.0f}'.format).values[0])) 78 | st.metric(label='**Average NFTs/Sale**', value=str(df['NFTs/Sale'].map('{:,.2f}'.format).values[0]), help='USD') 79 | with c4: 80 | st.metric(label='**Average Sales/Buyer**', value=str(df['Sales/Buyer'].map('{:,.2f}'.format).values[0])) 81 | st.metric(label='**Average Collections/Buyer**', value=str(df['Collections/Buyer'].map('{:,.2f}'.format).values[0])) 82 | st.metric(label='**Average Daily Buyers**', value=str(df['Buyers/Day'].map('{:,.0f}'.format).values[0])) 83 | 84 | st.subheader('Activity Over Time') 85 | df = nfts_daily.query('Blockchain == @options') 86 | c1, c2 = st.columns(2) 87 | with c1: 88 | fig = px.area(df, x='Date', y='Volume', title='Daily Sales Volume') 89 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Volume [USD]') 90 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 91 | 92 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 93 | fig.add_trace(go.Bar(x=df['Date'], y=df['PriceAverage'], name='Average'), secondary_y=False) 94 | fig.add_trace(go.Line(x=df['Date'], y=df['PriceMedian'], name='Median'), secondary_y=True) 95 | fig.update_layout(title_text='Daily Average and Median NFT Prices') 96 | fig.update_yaxes(title_text='Average [USD]', secondary_y=False) 97 | fig.update_yaxes(title_text='Median [USD]', secondary_y=True) 98 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 99 | with c2: 100 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 101 | fig.add_trace(go.Bar(x=df['Date'], y=df['Sales'], name='Sales'), secondary_y=False) 102 | fig.add_trace(go.Line(x=df['Date'], y=df['Buyers'], name='Buyers'), secondary_y=True) 103 | fig.update_layout(title_text='Daily Sales and Buyers') 104 | fig.update_yaxes(title_text='Sales', secondary_y=False) 105 | fig.update_yaxes(title_text='Buyers', secondary_y=True) 106 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 107 | 108 | fig = sp.make_subplots(specs=[[{'secondary_y': True}]]) 109 | fig.add_trace(go.Bar(x=df['Date'], y=df['NFTs'], name='NFTs'), secondary_y=False) 110 | fig.add_trace(go.Line(x=df['Date'], y=df['Collections'], name='Collections'), secondary_y=True) 111 | fig.update_layout(title_text='Daily Traded NFTs and Collections') 112 | fig.update_yaxes(title_text='NFTs', secondary_y=False) 113 | fig.update_yaxes(title_text='Collections', secondary_y=True) 114 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 115 | 116 | st.subheader('Activity Heatmap') 117 | df = nfts_heatmap.query('Blockchain == @options') 118 | c1, c2 = st.columns(2) 119 | with c1: 120 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Volume', histfunc='avg', title='Heatmap of Sales Volume', nbinsx=24) 121 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Volume [USD]')) 122 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 123 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 124 | 125 | fig = px.density_heatmap(df, x='Hour', y='Day', z='PriceAverage', histfunc='avg', title='Heatmap of Average NFT Price', nbinsx=24) 126 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Average [USD]')) 127 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 128 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 129 | 130 | fig = px.density_heatmap(df, x='Hour', y='Day', z='PriceMedian', histfunc='avg', title='Heatmap of Median NFT Price', nbinsx=24) 131 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Median [USD]')) 132 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 133 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 134 | 135 | fig = px.density_heatmap(df, x='Hour', y='Day', z='PriceMax', histfunc='avg', title='Heatmap of Max NFT Price', nbinsx=24) 136 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Max Price [USD]')) 137 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 138 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 139 | with c2: 140 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Sales', histfunc='avg', title='Heatmap of Sales', nbinsx=24) 141 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Sales')) 142 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 143 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 144 | 145 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Buyers', histfunc='avg', title='Heatmap of Unique Buyers', nbinsx=24) 146 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Buyers')) 147 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 148 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 149 | 150 | fig = px.density_heatmap(df, x='Hour', y='Day', z='NFTs', histfunc='avg', title='Heatmap of Traded NFTs', nbinsx=24) 151 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='NFTs')) 152 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 153 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 154 | 155 | fig = px.density_heatmap(df, x='Hour', y='Day', z='Collections', histfunc='avg', title='Heatmap of Traded Collections', nbinsx=24) 156 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, xaxis={'dtick': 2}, coloraxis_colorbar=dict(title='Collections')) 157 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 158 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 159 | 160 | # Cross Chain Comparison 161 | else: 162 | subtab_overview, subtab_prices, subtab_heatmap = st.tabs(['Overview', 'Prices', 'Heatmap']) 163 | with subtab_overview: 164 | st.subheader('Overview') 165 | df = nfts_overview.query('Blockchain == @options') 166 | 167 | c1, c2 = st.columns(2) 168 | with c1: 169 | fig = px.bar(df, x='Blockchain', y='Volume', color='Blockchain', title='Total Sales Volume', log_y=True) 170 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Volume [USD]', xaxis={'categoryorder':'total ascending'}) 171 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 172 | with c2: 173 | fig = px.bar(df, x='Blockchain', y='Sales', color='Blockchain', title='Total Sales', log_y=True) 174 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Sales', xaxis={'categoryorder':'total ascending'}) 175 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 176 | 177 | c1, c2, c3 = st.columns(3) 178 | with c1: 179 | fig = px.bar(df, x='Blockchain', y='Buyers', color='Blockchain', title='Total Buyers', log_y=True) 180 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Buyers', xaxis={'categoryorder':'total ascending'}) 181 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 182 | with c2: 183 | fig = px.bar(df, x='Blockchain', y='NFTs', color='Blockchain', title='Total Traded NFTs', log_y=True) 184 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='NFTs', xaxis={'categoryorder':'total ascending'}) 185 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 186 | with c3: 187 | fig = px.bar(df, x='Blockchain', y='Collections', color='Blockchain', title='Total Traded Collections', log_y=True) 188 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Collections', xaxis={'categoryorder':'total ascending'}) 189 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 190 | 191 | st.subheader('Market Shares') 192 | c1, c2 = st.columns(2) 193 | with c1: 194 | fig = px.pie(df, values='Volume', names='Blockchain', title='Share of Total Sales Volume') 195 | fig.update_layout(legend_title=None, legend_y=0.5) 196 | fig.update_traces(textinfo='percent+label', textposition='inside') 197 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 198 | with c2: 199 | fig = px.pie(df, values='Sales', names='Blockchain', title='Share of Total Sales') 200 | fig.update_layout(legend_title=None, legend_y=0.5) 201 | fig.update_traces(textinfo='percent+label', textposition='inside') 202 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 203 | 204 | c1, c2, c3 = st.columns(3) 205 | with c1: 206 | fig = px.pie(df, values='Buyers', names='Blockchain', title='Share of Total Buyers') 207 | fig.update_layout(legend_title=None, legend_y=0.5) 208 | fig.update_traces(textinfo='percent+label', textposition='inside') 209 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 210 | with c2: 211 | fig = px.pie(df, values='NFTs', names='Blockchain', title='Share of Traded NFTs') 212 | fig.update_layout(legend_title=None, legend_y=0.5) 213 | fig.update_traces(textinfo='percent+label', textposition='inside') 214 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 215 | with c3: 216 | fig = px.pie(df, values='Collections', names='Blockchain', title='Share of Total Traded Collections') 217 | fig.update_layout(legend_title=None, legend_y=0.5) 218 | fig.update_traces(textinfo='percent+label', textposition='inside') 219 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 220 | 221 | st.subheader('Activity Over Time') 222 | df = nfts_daily.query('Blockchain == @options') 223 | c1, c2 = st.columns(2) 224 | with c1: 225 | fig = px.line(df, x='Date', y='Volume', color='Blockchain', title='Daily Sales Volume', log_y=True) 226 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Volume [USD]') 227 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 228 | 229 | fig = px.line(df, x='Date', y='Sales', color='Blockchain', title='Daily Sales', log_y=True) 230 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Sales') 231 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 232 | 233 | fig = px.line(df, x='Date', y='Buyers', color='Blockchain', title='Daily Buyers', log_y=True) 234 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Buyers') 235 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 236 | 237 | fig = px.line(df, x='Date', y='NFTs', color='Blockchain', title='Daily Traded NFTs', log_y=True) 238 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='NFTs') 239 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 240 | 241 | fig = px.line(df, x='Date', y='Collections', color='Blockchain', title='Daily Traded Collections', log_y=True) 242 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Collections') 243 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 244 | with c2: 245 | fig = go.Figure() 246 | for i in options: 247 | fig.add_trace(go.Scatter( 248 | name=i, 249 | x=df.query("Blockchain == @i")['Date'], 250 | y=df.query("Blockchain == @i")['Volume'], 251 | mode='lines', 252 | stackgroup='one', 253 | groupnorm='percent' 254 | )) 255 | fig.update_layout(title='Daily Share of Sales Volume') 256 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 257 | 258 | fig = go.Figure() 259 | for i in options: 260 | fig.add_trace(go.Scatter( 261 | name=i, 262 | x=df.query("Blockchain == @i")['Date'], 263 | y=df.query("Blockchain == @i")['Sales'], 264 | mode='lines', 265 | stackgroup='one', 266 | groupnorm='percent' 267 | )) 268 | fig.update_layout(title='Daily Share of Sales') 269 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 270 | 271 | fig = go.Figure() 272 | for i in options: 273 | fig.add_trace(go.Scatter( 274 | name=i, 275 | x=df.query("Blockchain == @i")['Date'], 276 | y=df.query("Blockchain == @i")['Buyers'], 277 | mode='lines', 278 | stackgroup='one', 279 | groupnorm='percent' 280 | )) 281 | fig.update_layout(title='Daily Share of Buyers') 282 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 283 | 284 | fig = go.Figure() 285 | for i in options: 286 | fig.add_trace(go.Scatter( 287 | name=i, 288 | x=df.query("Blockchain == @i")['Date'], 289 | y=df.query("Blockchain == @i")['NFTs'], 290 | mode='lines', 291 | stackgroup='one', 292 | groupnorm='percent' 293 | )) 294 | fig.update_layout(title='Daily Share of Traded NFTs') 295 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 296 | 297 | fig = go.Figure() 298 | for i in options: 299 | fig.add_trace(go.Scatter( 300 | name=i, 301 | x=df.query("Blockchain == @i")['Date'], 302 | y=df.query("Blockchain == @i")['Collections'], 303 | mode='lines', 304 | stackgroup='one', 305 | groupnorm='percent' 306 | )) 307 | fig.update_layout(title='Daily Share of Traded Collections') 308 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 309 | 310 | with subtab_prices: 311 | st.subheader('Overview') 312 | df = nfts_overview.query('Blockchain == @options') 313 | c1, c2, c3 = st.columns(3) 314 | with c1: 315 | fig = px.bar(df, x='Blockchain', y='PriceAverage', color='Blockchain', title='Average NFT Prices', log_y=True) 316 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Average [USD]', xaxis={'categoryorder':'total ascending'}) 317 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 318 | with c2: 319 | fig = px.bar(df, x='Blockchain', y='PriceMedian', color='Blockchain', title='Median NFT Prices', log_y=True) 320 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Median [USD]', xaxis={'categoryorder':'total ascending'}) 321 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 322 | with c3: 323 | fig = px.bar(df, x='Blockchain', y='PriceMax', color='Blockchain', title='Maximum NFT Prices', log_y=True) 324 | fig.update_layout(showlegend=False, xaxis_title=None, yaxis_title='Maximum [USD]', xaxis={'categoryorder':'total ascending'}) 325 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 326 | 327 | st.subheader('Activity Over Time') 328 | df = nfts_daily.query('Blockchain == @options') 329 | 330 | fig = px.line(df, x='Date', y='PriceAverage', color='Blockchain', title='Daily Average NFT Prices', log_y=True) 331 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Average [USD]') 332 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 333 | 334 | fig = px.line(df, x='Date', y='PriceMedian', color='Blockchain', title='Daily Median NFT Prices', log_y=True) 335 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Median [USD]') 336 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 337 | 338 | fig = px.line(df, x='Date', y='PriceMax', color='Blockchain', title='Daily Maximum NFT Prices', log_y=True) 339 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title='Maximum [USD]') 340 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 341 | 342 | with subtab_heatmap: 343 | st.subheader('Sales') 344 | df = nfts_heatmap.query('Blockchain == @options') 345 | c1, c2 = st.columns(2) 346 | with c1: 347 | df = nfts_heatmap.query("Blockchain == @options") 348 | df['Volume'] = df.groupby('Blockchain')['Volume'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 349 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Volume', histfunc='avg', title='Daily Heatmap of Normalized Sales Volume') 350 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 351 | fig.update_xaxes(categoryorder='category ascending') 352 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 353 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 354 | 355 | df = nfts_heatmap.query("Blockchain == @options") 356 | df['Sales'] = df.groupby('Blockchain')['Sales'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 357 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Sales', histfunc='avg', title='Daily Heatmap of Normalized Sales') 358 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 359 | fig.update_xaxes(categoryorder='category ascending') 360 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 361 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 362 | 363 | df = nfts_heatmap.query("Blockchain == @options") 364 | df['Buyers'] = df.groupby('Blockchain')['Buyers'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 365 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Buyers', histfunc='avg', title='Daily Heatmap of Normalized Buyers') 366 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 367 | fig.update_xaxes(categoryorder='category ascending') 368 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 369 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 370 | 371 | df = nfts_heatmap.query("Blockchain == @options") 372 | df['NFTs'] = df.groupby('Blockchain')['NFTs'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 373 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='NFTs', histfunc='avg', title='Daily Heatmap of Normalized Traded NFTs') 374 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 375 | fig.update_xaxes(categoryorder='category ascending') 376 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 377 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 378 | 379 | df = nfts_heatmap.query("Blockchain == @options") 380 | df['Collections'] = df.groupby('Blockchain')['Collections'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 381 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='Collections', histfunc='avg', title='Daily Heatmap of Normalized Traded Collections') 382 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 383 | fig.update_xaxes(categoryorder='category ascending') 384 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 385 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 386 | 387 | with c2: 388 | df = nfts_heatmap.query("Blockchain == @options") 389 | df['Volume'] = df.groupby('Blockchain')['Volume'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 390 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Volume', histfunc='avg', title='Hourly Heatmap of Normalized Sales Volume', nbinsy=24) 391 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 392 | fig.update_xaxes(categoryorder='category ascending') 393 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 394 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 395 | 396 | df = nfts_heatmap.query("Blockchain == @options") 397 | df['Sales'] = df.groupby('Blockchain')['Sales'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 398 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Sales', histfunc='avg', title='Hourly Heatmap of Normalized Sales', nbinsy=24) 399 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 400 | fig.update_xaxes(categoryorder='category ascending') 401 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 402 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 403 | 404 | df = nfts_heatmap.query("Blockchain == @options") 405 | df['Buyers'] = df.groupby('Blockchain')['Buyers'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 406 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Buyers', histfunc='avg', title='Hourly Heatmap of Normalized Buyers', nbinsy=24) 407 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 408 | fig.update_xaxes(categoryorder='category ascending') 409 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 410 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 411 | 412 | df = nfts_heatmap.query("Blockchain == @options") 413 | df['NFTs'] = df.groupby('Blockchain')['NFTs'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 414 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='NFTs', histfunc='avg', title='Hourly Heatmap of Normalized Traded NFTs', nbinsy=24) 415 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 416 | fig.update_xaxes(categoryorder='category ascending') 417 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 418 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 419 | 420 | df = nfts_heatmap.query("Blockchain == @options") 421 | df['Collections'] = df.groupby('Blockchain')['Collections'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 422 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='Collections', histfunc='avg', title='Hourly Heatmap of Normalized Traded Collections', nbinsy=24) 423 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 424 | fig.update_xaxes(categoryorder='category ascending') 425 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 426 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 427 | 428 | st.subheader('Prices') 429 | c1, c2 = st.columns(2) 430 | with c1: 431 | df = nfts_heatmap.query("Blockchain == @options") 432 | df['PriceAverage'] = df.groupby('Blockchain')['PriceAverage'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 433 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='PriceAverage', histfunc='avg', title='Daily Heatmap of Normalized Average NFT Prices') 434 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 435 | fig.update_xaxes(categoryorder='category ascending') 436 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 437 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 438 | 439 | df = nfts_heatmap.query("Blockchain == @options") 440 | df['PriceMedian'] = df.groupby('Blockchain')['PriceMedian'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 441 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='PriceMedian', histfunc='avg', title='Daily Heatmap of Normalized Median NFT Prices') 442 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 443 | fig.update_xaxes(categoryorder='category ascending') 444 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 445 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 446 | 447 | df = nfts_heatmap.query("Blockchain == @options") 448 | df['PriceMax'] = df.groupby('Blockchain')['PriceMax'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 449 | fig = px.density_heatmap(df, x='Blockchain', y='Day', z='PriceMax', histfunc='avg', title='Daily Heatmap of Normalized Maximum NFT Prices') 450 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 451 | fig.update_xaxes(categoryorder='category ascending') 452 | fig.update_yaxes(categoryorder='array', categoryarray=week_days) 453 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 454 | 455 | with c2: 456 | df = nfts_heatmap.query("Blockchain == @options") 457 | df['PriceAverage'] = df.groupby('Blockchain')['PriceAverage'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 458 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='PriceAverage', histfunc='avg', title='Hourly Heatmap of Normalized Average NFT Prices', nbinsy=24) 459 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 460 | fig.update_xaxes(categoryorder='category ascending') 461 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 462 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 463 | 464 | df = nfts_heatmap.query("Blockchain == @options") 465 | df['PriceMedian'] = df.groupby('Blockchain')['PriceMedian'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 466 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='PriceMedian', histfunc='avg', title='Hourly Heatmap of Normalized Median NFT Prices', nbinsy=24) 467 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 468 | fig.update_xaxes(categoryorder='category ascending') 469 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 470 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) 471 | 472 | df = nfts_heatmap.query("Blockchain == @options") 473 | df['PriceMax'] = df.groupby('Blockchain')['PriceMax'].transform(lambda x: (x - x.min()) / (x.max() - x.min())) 474 | fig = px.density_heatmap(df, x='Blockchain', y='Hour', z='PriceMax', histfunc='avg', title='Hourly Heatmap of Normalized Maximum NFT Prices', nbinsy=24) 475 | fig.update_layout(legend_title=None, xaxis_title=None, yaxis_title=None, coloraxis_colorbar=dict(title='Min/Max')) 476 | fig.update_xaxes(categoryorder='category ascending') 477 | fig.update_yaxes(categoryorder='array', categoryarray=week_days, dtick=2) 478 | st.plotly_chart(fig, use_container_width=True, theme=theme_plotly) --------------------------------------------------------------------------------