praiteri commited on
Commit
aa4aab0
·
1 Parent(s): 44a013a

lab template added

Browse files
marimo/app.py CHANGED
@@ -1,7 +1,8 @@
1
  from typing import Annotated, Callable, Coroutine
2
- from fastapi.responses import HTMLResponse, RedirectResponse, FileResponse
3
  import marimo
 
4
  from fastapi import FastAPI, Form, Request, Response
 
5
  import os
6
  from pathlib import Path
7
 
@@ -24,19 +25,38 @@ marimo_server = (
24
  .with_app(path="/surface", root="./surface_adsorption.py")
25
  )
26
 
27
- # Create a route to download a file
28
- @app.get("/download-pdf/{pdf_name}")
29
- async def download_pdf(pdf_name: str):
30
- # Assuming PDFs are stored in a 'pdfs' directory
31
- pdf_path = f"./pdfs/{pdf_name}"
32
 
33
- if os.path.exists(pdf_path):
 
 
 
 
 
 
 
34
  return FileResponse(
35
- pdf_path,
36
- media_type='application/pdf',
37
- filename=pdf_name
38
  )
39
- return {"error": f"PDF not found [./pdfs/{pdf_name}]"}, 404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  @app.get("/calendar", response_class=HTMLResponse)
42
  async def read_root():
 
1
  from typing import Annotated, Callable, Coroutine
 
2
  import marimo
3
+ from fastapi.responses import HTMLResponse, RedirectResponse, FileResponse
4
  from fastapi import FastAPI, Form, Request, Response
5
+ import mimetypes
6
  import os
7
  from pathlib import Path
8
 
 
25
  .with_app(path="/surface", root="./surface_adsorption.py")
26
  )
27
 
28
+ def get_media_type(file_name: str):
29
+ mime_type, _ = mimetypes.guess_type(file_name)
30
+ return mime_type or 'application/octet-stream' # Default to binary if unknown
 
 
31
 
32
+ @app.get("/download-file/{file_name}")
33
+ async def download_file(file_name: str):
34
+ file_path = f"./docs/{file_name}"
35
+ if os.path.exists(file_path):
36
+ # For example:
37
+ # For "document.pdf" - media_type would be "application/pdf"
38
+ # For "document.docx" - media_type would be "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
39
+ # For "document.doc" - media_type would be "application/msword"
40
  return FileResponse(
41
+ file_path,
42
+ media_type=get_media_type(file_name),
43
+ filename=file_name
44
  )
45
+ raise HTTPException(status_code=404, detail=f"Document not found [./docs/{file_name}]")
46
+
47
+ ## Create a route to download a file
48
+ #@app.get("/download-file/{file_name}")
49
+ #async def download_file(file_name: str):
50
+ # # Assuming files are stored in a 'docs' directory
51
+ # file_path = f"./docs/{file_name}"
52
+ #
53
+ # if os.path.exists(file_path):
54
+ # return FileResponse(
55
+ # file_path,
56
+ # media_type='application/pdf',
57
+ # filename=file_name
58
+ # )
59
+ # return {"error": f"Document not found [./docs/{file_name}]"}, 404
60
 
61
  @app.get("/calendar", response_class=HTMLResponse)
62
  async def read_root():
marimo/{pdfs → docs}/LabManualCHEM2000-1.pdf RENAMED
File without changes
marimo/docs/LabReportTemplate.docx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8ee4b0b57305656bf251e9233d34294184a905515533ec86e17700d9b4db4948
3
+ size 17371
marimo/{pdfs → docs}/NotesOfStatistics-1.pdf RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:dda949acff5354afefd6f9e7f466ad7754aba215160d9070e686387fe083c067
3
- size 2606853
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5a06c43e66bd1169ceace01a9a18890e2173f4bec4913c4cb604a40d58bf96c3
3
+ size 2606862
marimo/{pdfs → docs}/calendar.pdf RENAMED
File without changes
marimo/{pdfs → docs}/python_primer.pdf RENAMED
File without changes
marimo/index.html CHANGED
@@ -90,22 +90,26 @@
90
 
91
  <!-- <h2>Labs</h2> -->
92
  <div class="lab-grid">
93
- <a href="/download-pdf/LabManualCHEM2000-1.pdf" class="lab-card">
 
 
 
 
94
  <h3 style="text-align: center">Lab Manual<br>(Download PDF)</h3>
95
  <p style="text-align: center">Version 1 - 20/02/2025</p>
96
  </a>
97
- <a href="/download-pdf/NotesOfStatistics-1.pdf" class="lab-card">
 
 
 
 
98
  <h3 style="text-align: center">Notes of Statistics<br>(Download PDF)</h3>
99
  <p style="text-align: center">Version 1 - 20/02/2025</p>
100
  </a>
101
- <a href="/download-pdf/python_primer.pdf" class="lab-card">
102
  <h3 style="text-align: center">A Python Primer<br>(Download PDF)</h3>
103
  <p style="text-align: center">Version 1 - 20/02/2025</p>
104
  </a>
105
- <a href="/calendar" class="lab-card" >
106
- <h3 style="text-align: center">Calendar</h3>
107
- <p style="text-align: center">Lab schedule and deadlines<br>(2025)</p>
108
- </a>
109
  </div>
110
  <hr style="width: 80%; height: 2px; background-color: #333; border: none;">
111
  <div class="lab-grid">
 
90
 
91
  <!-- <h2>Labs</h2> -->
92
  <div class="lab-grid">
93
+ <a href="/calendar" class="lab-card" >
94
+ <h3 style="text-align: center">Calendar</h3>
95
+ <p style="text-align: center">Lab schedule and deadlines<br>(2025)</p>
96
+ </a>
97
+ <a href="/download-file/LabManualCHEM2000-1.pdf" class="lab-card">
98
  <h3 style="text-align: center">Lab Manual<br>(Download PDF)</h3>
99
  <p style="text-align: center">Version 1 - 20/02/2025</p>
100
  </a>
101
+ <a href="/download-file/LabReportTemplate.docx" class="lab-card">
102
+ <h3 style="text-align: center">Lab Report Template<br>(Download DOCX)</h3>
103
+ <p style="text-align: center">Version 1 - 28/02/2025</p>
104
+ </a>
105
+ <a href="/download-file/NotesOfStatistics-1.pdf" class="lab-card">
106
  <h3 style="text-align: center">Notes of Statistics<br>(Download PDF)</h3>
107
  <p style="text-align: center">Version 1 - 20/02/2025</p>
108
  </a>
109
+ <a href="/download-file/python_primer.pdf" class="lab-card">
110
  <h3 style="text-align: center">A Python Primer<br>(Download PDF)</h3>
111
  <p style="text-align: center">Version 1 - 20/02/2025</p>
112
  </a>
 
 
 
 
113
  </div>
114
  <hr style="width: 80%; height: 2px; background-color: #333; border: none;">
115
  <div class="lab-grid">
marimo/statistics_lab.py CHANGED
@@ -43,7 +43,7 @@ def _(mo):
43
 
44
 
45
  @app.cell
46
- def _(lab, mo):
47
  def set_ID(value):
48
  return cek.set_ID(mo, lab, value)
49
 
 
43
 
44
 
45
  @app.cell
46
+ def _(cek, lab, mo):
47
  def set_ID(value):
48
  return cek.set_ID(mo, lab, value)
49
 
src/pycek_public/cek_labs.py CHANGED
@@ -7,6 +7,18 @@ from collections import OrderedDict
7
  from abc import ABC, abstractmethod
8
 
9
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  class cek_labs(ABC):
11
  def __init__(self, **kwargs):
12
  self.token = None
 
7
  from abc import ABC, abstractmethod
8
 
9
 
10
+ def set_ID(mo, lab, value):
11
+ try:
12
+ student_number = int(value.strip())
13
+ if student_number <= 0:
14
+ error = f"### Invalid Student ID: {value}"
15
+ print(mo.md(error))
16
+ raise ValueError(error)
17
+ print(mo.md(f"Valid Student ID: {student_number}"))
18
+ lab.set_student_ID(int(value))
19
+ except ValueError:
20
+ print(mo.md(f"### Invalid Student ID: {value}"))
21
+
22
  class cek_labs(ABC):
23
  def __init__(self, **kwargs):
24
  self.token = None
src/pycek_public/plotting.py CHANGED
@@ -3,67 +3,79 @@ import numpy as np
3
  from scipy import stats
4
 
5
  class plotting():
6
- def quick_plot(self, scatter=None, line=None, columns=["X","Y"], output=None, hline=None):
7
- """
8
- Plot the data along with the best fit line and its associated confidence band.
9
 
 
 
 
 
 
10
  Parameters:
11
- data (list): List of data to plot
12
- columns (list): Axes labels (default is "X","Y")
13
-
 
 
 
14
  Returns:
15
- None: Displays a matplotlib plot with data, fit line, and confidence band
16
-
17
  Example:
18
- >>> quick_plot(x_data, y_data)
19
  """
20
-
21
  if scatter is None and line is None:
22
  raise ValueError("Either scatter or line should be provided")
23
-
24
- if not isinstance(scatter,list):
25
- scatter = [scatter]
26
- if not isinstance(line,list):
27
- line = [line]
28
-
29
- # Plot the observed data points as a scatter plot
 
 
 
 
30
  idx = 0
31
  for ds in scatter:
32
  if ds is not None:
33
- plt.scatter(ds[:,0],ds[:,1],label="Data "+str(idx)),
34
  idx += 1
35
- # ymin = np.min(ds[:,1] - 0.1*np.abs(np.min(ds[:,1])))
36
- # ymax = np.max(ds[:,1] + 0.1*np.abs(np.max(ds[:,1])))
37
-
38
- # ax = plt.gca()
39
- # ax.set_ylim([ymin, ymax])
40
-
41
  for ds in line:
42
  if ds is not None:
43
- plt.plot(ds[:,0],ds[:,1],color='red',label="Data "+str(idx)),
44
  idx += 1
45
-
46
- # Add labels and title to the plot
47
- plt.xlabel(columns[0])
48
- plt.ylabel(columns[1])
49
-
 
50
  if hline is not None:
51
- plt.axhline(hline, color='black', linestyle='--')
52
-
53
- # Display the legend
54
- plt.legend()
55
-
56
- ax = plt.gca()
57
  ax.text(0.5, 0.5, 'TEMPLATE', transform=ax.transAxes,
58
- fontsize=40, color='gray', alpha=0.5,
59
- ha='center', va='center', rotation=30)
60
-
61
- # Show the plot
62
  if output is None:
63
- plt.show()
 
 
64
  elif output == "marimo":
65
- return plt.gcf()
66
  else:
67
- plt.savefig(output)
68
- plt.close()
 
 
 
 
69
 
 
3
  from scipy import stats
4
 
5
  class plotting():
 
 
 
6
 
7
+ def quick_plot(self, scatter=None, line=None, columns=["X", "Y"], output=None, hline=None):
8
+ """
9
+ Plot the data along with the best fit line and its associated confidence band using
10
+ Matplotlib's object-oriented API to avoid race conditions.
11
+
12
  Parameters:
13
+ scatter (list or array): Data to plot as scatter points
14
+ line (list or array): Data to plot as lines
15
+ columns (list): Axes labels (default is ["X","Y"])
16
+ output (str): If provided, save figure to this path. If "marimo", return the figure object
17
+ hline (float): If provided, add a horizontal line at this y-value
18
+
19
  Returns:
20
+ None or Figure: Displays a matplotlib plot or returns the figure object if output="marimo"
21
+
22
  Example:
23
+ >>> quick_plot(scatter=x_data, line=y_data)
24
  """
25
+ # Input validation
26
  if scatter is None and line is None:
27
  raise ValueError("Either scatter or line should be provided")
28
+
29
+ # Convert inputs to lists if they aren't already
30
+ if not isinstance(scatter, list):
31
+ scatter = [scatter] if scatter is not None else []
32
+ if not isinstance(line, list):
33
+ line = [line] if line is not None else []
34
+
35
+ # Create figure and axes objects (OO approach)
36
+ fig, ax = plt.subplots(figsize=(6, 6))
37
+
38
+ # Plot scatter data
39
  idx = 0
40
  for ds in scatter:
41
  if ds is not None:
42
+ ax.scatter(ds[:, 0], ds[:, 1], label=f"Data {idx}")
43
  idx += 1
44
+
45
+ # Plot line data
 
 
 
 
46
  for ds in line:
47
  if ds is not None:
48
+ ax.plot(ds[:, 0], ds[:, 1], color='red', label=f"Data {idx}")
49
  idx += 1
50
+
51
+ # Set labels
52
+ ax.set_xlabel(columns[0])
53
+ ax.set_ylabel(columns[1])
54
+
55
+ # Add horizontal line if specified
56
  if hline is not None:
57
+ ax.axhline(hline, color='black', linestyle='--')
58
+
59
+ # Add legend
60
+ ax.legend()
61
+
62
+ # Add watermark
63
  ax.text(0.5, 0.5, 'TEMPLATE', transform=ax.transAxes,
64
+ fontsize=40, color='gray', alpha=0.5,
65
+ ha='center', va='center', rotation=30)
66
+
67
+ # Handle output
68
  if output is None:
69
+ # Use this instead of plt.show() to avoid blocking behavior
70
+ fig.canvas.draw_idle()
71
+ plt.show(block=False)
72
  elif output == "marimo":
73
+ return fig
74
  else:
75
+ # Save the figure to the specified path
76
+ fig.savefig(output)
77
+
78
+ # Close the figure to free memory if not returning it
79
+ if output != "marimo":
80
+ plt.close(fig)
81
 
src/pycek_public/statistics_lab.py CHANGED
@@ -27,7 +27,7 @@ class stats_lab(cek.cek_labs):
27
  (1.0, 0.1),
28
  (12., 2.0)
29
  ],
30
- 'exp_values' : (1.0,10.0),
31
  "precision" : 3,
32
  }
33
 
@@ -51,7 +51,7 @@ class stats_lab(cek.cek_labs):
51
  "function" : lambda x,m,q: m*x + q,
52
  "gen_values" : {'m':12.3 , 'q':1.0},
53
  "xrange" : [0.0 , 10.0],
54
- "exp_values" : 11.3,
55
  "precision" : 3,
56
  }
57
 
@@ -94,6 +94,9 @@ class stats_lab(cek.cek_labs):
94
  number_of_values = self.number_of_values,
95
  sample = self.sample,
96
  )
 
 
 
97
 
98
  if self.sample in ["Averages", 'Propagation of uncertainty', 'Comparison of averages']:
99
  data = self._generate_normal_random(self.number_of_values, prm['gen_values'])
 
27
  (1.0, 0.1),
28
  (12., 2.0)
29
  ],
30
+ 'expected_value' : (1.0,10.0),
31
  "precision" : 3,
32
  }
33
 
 
51
  "function" : lambda x,m,q: m*x + q,
52
  "gen_values" : {'m':12.3 , 'q':1.0},
53
  "xrange" : [0.0 , 10.0],
54
+ "expected_value" : (11.3,0.9),
55
  "precision" : 3,
56
  }
57
 
 
94
  number_of_values = self.number_of_values,
95
  sample = self.sample,
96
  )
97
+
98
+ if "expected_value" in prm:
99
+ self.add_metadata( **{"expected_value": prm["expected_value"]} )
100
 
101
  if self.sample in ["Averages", 'Propagation of uncertainty', 'Comparison of averages']:
102
  data = self._generate_normal_random(self.number_of_values, prm['gen_values'])