Skip to content

Commit 1fc6871

Browse files
committed
Refeactoring and bug fix of wrongly named module. Add plotting to documentation.
1 parent a0d784e commit 1fc6871

9 files changed

Lines changed: 66 additions & 48 deletions

README.md

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ This library provides tools for aggregating sensor data over time windows, detec
1717
- [Architecture Overview](#architecture-overview)
1818
- [Running Tests](#running-tests)
1919
- [Project Structure](#project-structure)
20+
- [Plotting Results](#plotting-results)
2021
- [Implementation Status](#implementation-status)
2122

2223
---
@@ -41,25 +42,25 @@ This library provides tools for aggregating sensor data over time windows, detec
4142
### Option 1: Using Effekt directly
4243

4344
1. Clone this repository:
44-
```sh
45-
git clone <repo-url>
46-
cd Real-Time-Stream-Processing-Library
47-
```
45+
```sh
46+
git clone <repo-url>
47+
cd Real-Time-Stream-Processing-Library
48+
```
4849

4950
2. Make sure Effekt is installed at version `0.59.0` and available in your PATH. You can verify with:
50-
```sh
51-
effekt --version
52-
```
51+
```sh
52+
effekt --version
53+
```
5354

5455
3. Run the main file:
55-
```sh
56-
effekt src/main.effekt
57-
```
56+
```sh
57+
effekt src/main.effekt
58+
```
5859

5960
4. Run the tests:
60-
```sh
61-
effekt src/test.effekt
62-
```
61+
```sh
62+
effekt src/test.effekt
63+
```
6364

6465
### Option 2: Using Nix
6566

@@ -264,7 +265,6 @@ Tests use the `test` module from Effekt's standard library and return exit code
264265
│ ├── main.effekt # Main entry point
265266
│ ├── test.effekt # Test runner
266267
│ ├── examples.effekt # Usage examples
267-
│ ├── lib.effekt # Library re-exports
268268
│ ├── lib/ # Library modules
269269
│ │ ├── aggregation.effekt
270270
│ │ ├── anomaly_detection.effekt
@@ -284,16 +284,50 @@ Tests use the `test` module from Effekt's standard library and return exit code
284284
│ ├── lib.effekt
285285
│ ├── testdata.csv
286286
│ └── testdata_with_timestamp.csv
287-
├── flake.nix # Nix flake configuration
288-
├── flake.lock # Nix lockfile
289-
├── PROJECT_SPEC.md # Project specification
290-
├── ARCHITECTURE.md # Developer/architecture documentation
287+
├── plot_data.py # Visualization script for results
288+
├── flake.nix # Nix flake configuration
289+
├── flake.lock # Nix lockfile
290+
├── PROJECT_SPEC.md # Project specification
291+
├── ARCHITECTURE.md # Developer/architecture documentation
291292
├── LICENSE
292293
└── README.md
293294
```
294295

295296
---
296297

298+
## Plotting Results
299+
300+
The `plot_data.py` script provides visualization tools for analyzing output from the stream processing library. It generates plots from CSV files produced by the logging handlers.
301+
302+
### Usage
303+
304+
```sh
305+
python plot_data.py --raw <csv_file> --value-name "<Name>" [--out <output.png>]
306+
python plot_data.py --anomalies <csv_file> --value-name "<Name>" [--show-anomaly-values] [--out <output.png>]
307+
```
308+
309+
### Features
310+
311+
- **Raw Data Plotting**: Visualize time-series data with timestamps converted from Unix milliseconds
312+
- **Anomaly Visualization**: Plot data with anomalies highlighted in red, including both point markers and background shading for anomaly regions
313+
- **Anomaly Scores**: Optional secondary y-axis displaying anomaly scores for detailed analysis
314+
- **Export**: Save plots to PNG files or display interactively
315+
316+
### Examples
317+
318+
```sh
319+
# Plot raw CPU usage data
320+
python plot_data.py --raw cpu_usage_raw.csv --value-name "CPU Usage" --out raw_plot.png
321+
322+
# Plot with anomalies and scores
323+
python plot_data.py --anomalies cpu_anomalies.csv --value-name "CPU Usage" --show-anomaly-values --out anomaly_plot.png
324+
```
325+
326+
### Requirements
327+
328+
- `pandas`: Data loading and processing
329+
- `matplotlib`: Plotting and visualization
330+
297331
## Implementation Status
298332

299333
All requirements from the project specification have been implemented:

plot_data.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ def plot_raw_data(csv_file, value_name='Value', out_file=None):
3636
plt.grid(True, alpha=0.3)
3737
plt.legend()
3838

39-
# Rotate x-axis labels by 45 degrees for better readability
40-
plt.xticks(rotation=45, ha='right')
4139
plt.tight_layout()
4240

4341
if out_file:
@@ -123,8 +121,6 @@ def plot_anomalies(csv_file, value_name='Value', show_anomaly_values=False, out_
123121
if not show_anomaly_values:
124122
ax.legend()
125123

126-
# Rotate x-axis by 45 degrees
127-
plt.xticks(rotation=45, ha='right')
128124
plt.tight_layout()
129125

130126
if out_file:

src/examples.effekt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def cpuUsageAnomalyDetectionExample(): Unit = {
1515
with boundary()
1616
with anomaly_logger::logToConsole();
1717
with anomaly_logger::logToFileCsvRethrow("cpu_anomalies.csv");
18-
with minMaxAnomalyDetector(0.0, 0.25);
18+
with minMaxAnomalyDetector(0.0, 0.90);
1919
with event_logger::logToFileCsvRethrow("cpu_usage_aggregated.csv"); // Just for convenience, information is already in cpu_anomalies.csv
2020

2121
with cpuUsagePullStream(100);

src/lib.effekt

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/lib/cpu_utilization_input.effekt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module src/lib/resource_utilization_input
1+
module src/lib/cpu_utilization_input
22

33
import src/lib/event
44
import src/lib/timestamp

src/main.effekt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ import src/examples
44

55

66
def main(): Unit = {
7-
examples::exponentialDistributionWithZScoreAnomalyDetectionExample()
7+
examples::cpuUsageAnomalyDetectionExample()
88
}

src/test/aggregation_test.effekt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,6 @@ import src/lib/event
66
import src/test/lib
77
import process
88

9-
def eventsFromList(values: List[Double]): List[Event] = {
10-
def loop(vals: List[Double], ts: Int): List[Event] = {
11-
vals match {
12-
case Nil() => Nil()
13-
case Cons(h, t) => Cons(Event(ts, h), loop(t, ts + 1))
14-
}
15-
}
16-
loop(values, 0)
17-
}
18-
199
def sameEvent(a: Event, b: Event): Bool = {
2010
a.timestamp == b.timestamp && a.value == b.value
2111
}

src/test/anomaly_detection_test.effekt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,6 @@ import src/lib/event
66
import src/test/lib
77
import process
88

9-
def eventsFromList(values: List[Double]): List[Event] = {
10-
def loop(vals: List[Double], ts: Int): List[Event] = {
11-
vals match {
12-
case Nil() => Nil()
13-
case Cons(h, t) => Cons(Event(ts, h), loop(t, ts + 1))
14-
}
15-
}
16-
loop(values, 0)
17-
}
18-
199
def approx(a: Double, b: Double): Bool = {
2010
abs(a - b) <= 0.000001
2111
}

src/test/lib.effekt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module src/test/lib
22

33
import stream
44
import test
5+
import src/lib/event
56

67
def assertEmits[T](expected: List[T]) { equals: (T, T) => Bool } { program: () => Unit / emit[T] } : Unit / { Assertion } = {
78
var lst = expected
@@ -69,4 +70,14 @@ def assertDoNotRaise[E] {block: () => Unit / Exception[E]} = {
6970
assertTrue(false, "Expected exception not to raise but was raised: " ++ msg)
7071
}
7172
}
73+
}
74+
75+
def eventsFromList(values: List[Double]): List[Event] = {
76+
def loop(vals: List[Double], ts: Int): List[Event] = {
77+
vals match {
78+
case Nil() => Nil()
79+
case Cons(h, t) => Cons(Event(ts, h), loop(t, ts + 1))
80+
}
81+
}
82+
loop(values, 0)
7283
}

0 commit comments

Comments
 (0)