Skip to content

Commit

Permalink
Adding caching an state manegement in graph-01.py
Browse files Browse the repository at this point in the history
  • Loading branch information
joao-parana committed Sep 10, 2023
1 parent 07a5033 commit d379366
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 45 deletions.
39 changes: 39 additions & 0 deletions graphics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# graphics

## Description

This directory contains the code to generate the WEB application that displays the graphics with Streamlit under the hood.

## How to run

To run the application, you need to install the requirements in the `requirements.txt` file. You can do this by running the following command:

```bash
python3 -m pip install -e .
```

Then, you can run the test applications by running the following command:

```bash
alias st='streamlit run --server.headless true --theme.base light '
# This start code below is referencing the file graph-01.py and graph-02.py
st graphics/graph-01.py
st graphics/graph-02.py
# You can use Raw URI from GitHub repository like this:
# st https://raw.githubusercontent.com//joao-parana/...whatever-file.py
```

And open the URI in browser.

**Streamlit** implements a series of features to simplify the development of
data analysis applications, including layout management with containers such
as sidebars and tabs, as well as a set of very useful widgets.

With each user interaction with a given widget, the Framework reevaluates the
page and therefore it is necessary to use `@st.cache_data` and `st.cache_resource`
to avoid costly data and I/O reprocessing.

Caching an state manegement are some of the most important features of Streamlit.

For information on **caching** see [https://docs.streamlit.io/library/advanced-features/caching](https://docs.streamlit.io/library/advanced-features/caching)

173 changes: 128 additions & 45 deletions graphics/graph-01.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from __future__ import annotations
from datetime import datetime
import streamlit as st
from streamlit.delta_generator import DeltaGenerator

import altair as alt
import pandas as pd
import numpy as np
Expand All @@ -10,11 +13,34 @@

logger = LogConfig().getLogger()

# Cria uma instância da classe SessionStateProxy
session_state = st.session_state

# Inicializa as variáveis my_count e my_total
if 'counter1' not in session_state: session_state.counter1 = 0
if 'total1' not in session_state: session_state.total1 = 0
if 'counter2' not in session_state: session_state.counter2 = 0
if 'total2' not in session_state: session_state.total2 = 0
if 'counter3' not in session_state: session_state.counter3 = 0
if 'total3' not in session_state: session_state.total3 = 0

plot_cached = 1
st.set_page_config(layout="wide")

# Just add it after st.sidebar:
option_selected: str = ""
# option_selected = st.sidebar.radio('Escolha dentre os 3 exemplos abaixo:',[
option_selected = st.radio('Escolha dentre os 3 exemplos abaixo:',[
'1 - Imputação de valores ausentes',
'2 - Analise de uma máquina rotativa',
'3 - Outro exemplo'
]) or "0 - None"
print(f'option_selected = {option_selected}, type(option_selected) = {type(option_selected)}')

"""
### Visualização gráfica de séries temporais
"""
@st.cache_data(show_spinner="Fetching data from Dataframe...")
def create_df_with_nans_and_mask() -> pd.DataFrame:
# Criando um DataFrame de exemplo
values_a = [8.0, 5.0, 4.0, 3.0, 6.0, 18.0, np.nan, np.nan, np.nan, 14.0, 4.0, 4.0, 8.0, 20.0,
Expand All @@ -29,55 +55,112 @@ def create_df_with_nans_and_mask() -> pd.DataFrame:
ts1 = ts.add_nan_mask(inplace=False, plot=False, method='interpolate')
return ts1.df

@st.cache_data(show_spinner="Fetching data from Parquet file...")
def get_dataframe_from_parquet(f) -> pd.DataFrame:
print(f'Read data and put into cache')
data = pd.read_parquet(f)
print(f'data.shape = {data.shape}')
print('Cache dataframe_from_parquet miss at first run')
return data

chart_data = create_df_with_nans_and_mask()
other_data = get_dataframe_from_parquet('datasets/machine13_01.parquet')

"""
#### Imputação de valores ausentes
match option_selected.split(' - ')[0]:
case "1":
"""
#### Imputação de valores ausentes
O gráfico abaixo mostra uma série temporal com valores ausentes. Os valores ausentes
foram imputados usando o método 'interpolate' com função polinomial de ordem 3, ou
seja, função cubica.
O gráfico abaixo mostra uma série temporal com valores ausentes. Os valores ausentes
foram imputados usando o método 'interpolate' com função polinomial de ordem 3, ou
seja, função cubica.
Valores em Azul são valores os valores originais. Valores em Vermelho são valores imputados.
"""
st._arrow_line_chart(
chart_data,
x = 't',
y = ['a', 'a_nan'],
color = ['#5555FF', '#FF0000'] # NaNs em vermelho. O atributo color é opcional
)
Valores em Azul são valores os valores originais. Valores em Vermelho são valores imputados.
"""
start = datetime.now()
@st.cache_resource()
def build_chart_1(cached:int):
print('Cache chart_1 miss at first run')
chart_1 = st.line_chart(
chart_data,
x = 't',
y = ['a', 'a_nan'],
color = ['#5555FF', '#FF0000'] # NaNs em vermelho. O atributo color é opcional
)
assert isinstance(chart_1, DeltaGenerator)

"""
#### Analise de uma máquina rotativa
build_chart_1(plot_cached)
elapsed = datetime.now() - start
print(f'counter1 = {session_state.counter1}, elapsed chart_1: {elapsed}')
# Incrementa o contador e o totalizador
session_state.counter1 += 1
session_state.total1 += elapsed.total_seconds()
# Forma ta a saida para a página WEB
std = round(1000 * session_state.total1 / session_state.counter1)
st.markdown(f"""
Tempo médio de {std} milissegundos para construir o gráfico após {session_state.counter1} execuções
""")
case "2":
"""
#### Analise de uma máquina rotativa
O gráfico abaixo mostra duas features de um dataset com dados de dois sensores instalados
numa máquina rotativa. A feature 'T6021' mede a temperatura do motor num dado ponto. A
feature 'T6023' mede a temperatura do motor em outro ponto. Observa-se uma anomalia na
medida no dia 2023-08-04. A anomalia é um outlier, ou seja, um valor muito distante dos
demais valores da série temporal. Este aquecimento abrupto pode ser um indicativo de
problemas sistema acoplado ao motor que pode ter causado uma sobrecarga no motor e por
conseguinte, aumentando a sua temperatura em dois pontos específicos.
O gráfico abaixo mostra duas features de um dataset com dados de dois sensores instalados
numa máquina rotativa. A feature 'T6021' mede a temperatura do motor num dado ponto. A
feature 'T6023' mede a temperatura do motor em outro ponto. Observa-se uma anomalia na
medida no dia 2023-08-04. A anomalia é um outlier, ou seja, um valor muito distante dos
demais valores da série temporal. Este aquecimento abrupto pode ser um indicativo de
problemas sistema acoplado ao motor que pode ter causado uma sobrecarga no motor e por
conseguinte, aumentando a sua temperatura em dois pontos específicos.
Uma analise criteriosa dos dados pode ajudar a identificar a causa raiz do problema.
"""
f = 'datasets/machine13_01.parquet'
other_data = pd.read_parquet(f)
st._arrow_line_chart(
other_data,
x = 'TIMESTAMP',
y = ['T6021', 'T6023']
)

chart = alt.Chart(other_data).transform_fold(
['T6021', 'T6023'],
as_=['Sensor', 'Measurement']
).mark_bar(
opacity=0.3,
binSpacing=0
).encode(
alt.X('Measurement:Q').bin(maxbins=100),
alt.Y('count()').stack(None),
alt.Color('Sensor:N')
)

st._arrow_altair_chart(chart, use_container_width=True)
Uma analise criteriosa dos dados pode ajudar a identificar a causa raiz do problema.
"""
start = datetime.now()
@st.cache_resource()
def build_chart_2(cached:int):
print('Cache chart_2 miss at first run')
st._arrow_line_chart(
other_data,
x = 'TIMESTAMP',
y = ['T6021', 'T6023']
)

build_chart_2(plot_cached)
elapsed = datetime.now() - start
print(f'counter2 = {session_state.counter2}, elapsed chart_2: {elapsed}')
# Incrementa o contador e o totalizador
session_state.counter2 += 1
session_state.total2 += elapsed.total_seconds()
# Forma ta a saida para a página WEB
std = round(1000 * session_state.total2 / session_state.counter2)
st.markdown(f"""
Tempo médio de {std} milissegundos para construir o gráfico após {session_state.counter2} execuções
""")
case "3":
start = datetime.now()
@st.cache_resource()
def build_chart_3(cached:int):
print('Cache chart_3 miss at first run')
chart = alt.Chart(other_data).transform_fold(
['T6021', 'T6023'],
as_=['Sensor', 'Measurement']
).mark_bar(
opacity=0.3,
binSpacing=0
).encode(
alt.X('Measurement:Q').bin(maxbins=100),
alt.Y('count()').stack(None),
alt.Color('Sensor:N')
)
st._arrow_altair_chart(chart, use_container_width=True)

build_chart_3(plot_cached)
elapsed = datetime.now() - start
print(f'counter3 = {session_state.counter3}, elapsed chart_3: {elapsed}')
# Incrementa o contador e o totalizador
session_state.counter3 += 1
session_state.total3 += elapsed.total_seconds()
# Forma ta a saida para a página WEB
std = round(1000 * session_state.total3 / session_state.counter3)
st.markdown(f"""
Tempo médio de {std} milissegundos para construir o gráfico após {session_state.counter3} execuções
""")

0 comments on commit d379366

Please sign in to comment.