Dacho688 commited on
Commit
8a03cf9
·
0 Parent(s):

Initial commit

Browse files
Files changed (6) hide show
  1. .gitattributes +2 -0
  2. .gitignore +3 -0
  3. Dockerfile +7 -0
  4. app/app.py +91 -0
  5. docker-compose.yaml +7 -0
  6. requirements.txt +16 -0
.gitattributes ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ .env
2
+ .vscode/
3
+ .venv/
Dockerfile ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Dockerfile
2
+ FROM python:3.12-slim
3
+ WORKDIR /app
4
+ COPY requirements.txt .
5
+ RUN pip install --no-cache-dir -r requirements.txt
6
+ COPY ./app .
7
+ CMD ["bokeh", "serve", "--port", "5006", "--allow-websocket-origin=*", "app.py"]
app/app.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import threading
2
+ import time
3
+ from functools import partial
4
+ from bokeh.plotting import figure, curdoc
5
+ from bokeh.models import ColumnDataSource, LabelSet
6
+ from datetime import datetime
7
+ import random
8
+ import numpy as np
9
+
10
+ class BokehApp:
11
+ def __init__(self, doc):
12
+ self.doc = doc
13
+ # Create a threading.Event to signal the thread to shut down
14
+ self.stop_event = threading.Event()
15
+
16
+ # Create a sample plot
17
+ x = datetime.now()
18
+ y = random.uniform(0, 100)
19
+ self.source = ColumnDataSource(data=dict(x=[x], y=[y]))
20
+ self.label_source = self.source.clone()
21
+ p = figure(x_axis_type='datetime',
22
+ width = 1800,
23
+ height = 900,
24
+ x_axis_label="Time",
25
+ y_axis_label="Value",
26
+ title="Streaming Random Data",
27
+ )
28
+ p.title.align = "center"
29
+ p.title.text_font_size="20px"
30
+ p.toolbar.autohide = True
31
+ p.line(x='x', y='y', source=self.source)
32
+ p.scatter(x='x', y='y', source=self.source, size=8)
33
+
34
+ #Create value Label
35
+ label = LabelSet(x = 'x',
36
+ y = 'y',
37
+ text= 'y',
38
+ source = self.label_source,
39
+ x_offset=5, y_offset=5,
40
+ text_font_size="10pt")
41
+ p.add_layout(label)
42
+ # Start the background thread
43
+ self.thread = threading.Thread(target=self.get_data, args=(self.stop_event,), daemon=True)
44
+ self.thread.start()
45
+
46
+ # Register the cleanup function
47
+ self.doc.on_session_destroyed(self.on_session_destroyed)
48
+
49
+ # Add the plot to the document
50
+ self.doc.add_root(p)
51
+
52
+ def get_data(self, stop_event):
53
+ """
54
+ Function to run in a separate thread.
55
+ Infinite while loop until stop_event is set to True with on_session_destroyed().
56
+ Simulates a long-running data-fetching task.
57
+ """
58
+ curr_value = self.source.data['y'][-1]
59
+ log_curr_value = np.log(curr_value)
60
+
61
+ while not stop_event.is_set():
62
+ x = datetime.now()
63
+ log_random_growth = random.normalvariate(mu=.00001, sigma=.001)
64
+ log_y = log_curr_value + log_random_growth
65
+ log_curr_value = log_y
66
+ y = np.round(np.exp(log_curr_value),2)
67
+ new_data = dict(x=[x], y=[y])
68
+
69
+ # Safely schedule the update using a next tick callback
70
+ self.doc.add_next_tick_callback(partial(self.update_plot, new_data))
71
+ time.sleep(1)
72
+
73
+ print("Background thread is shutting down gracefully.")
74
+
75
+ def update_plot(self, new_data):
76
+ """
77
+ This function is executed by the next tick callback on the main thread.
78
+ It safely updates the ColumnDataSource.
79
+ """
80
+ self.source.stream(new_data, rollover=1000)
81
+ self.label_source.data = new_data
82
+
83
+ def on_session_destroyed(self, session_context):
84
+ """
85
+ Callback function that runs when a user closes the document.
86
+ """
87
+ print(f"Session {session_context.id} destroyed. Stopping background thread.\n", flush=True)
88
+ self.stop_event.set()
89
+
90
+ # Create an instance of the class when the script is run by the Bokeh server
91
+ BokehApp(curdoc())
docker-compose.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ services:
2
+ app:
3
+ build: .
4
+ container_name: app
5
+ restart: unless-stopped
6
+ ports:
7
+ - "5006:5006"
requirements.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ bokeh==3.8.1
2
+ contourpy==1.3.3
3
+ Jinja2==3.1.6
4
+ MarkupSafe==3.0.3
5
+ narwhals==2.12.0
6
+ numpy==2.3.5
7
+ packaging==25.0
8
+ pandas==2.3.3
9
+ pillow==12.0.0
10
+ python-dateutil==2.9.0.post0
11
+ pytz==2025.2
12
+ PyYAML==6.0.3
13
+ six==1.17.0
14
+ tornado==6.5.2
15
+ tzdata==2025.2
16
+ xyzservices==2025.10.0