Как исправить ошибку исключения _tkinter.TclError: ожидалось число с плавающей запятой, но получено "Python

Программы на Python
Anonymous
Как исправить ошибку исключения _tkinter.TclError: ожидалось число с плавающей запятой, но получено "

Сообщение Anonymous »

У меня возникли проблемы с приложением, которое я создаю для чтения значений, полученных с чипа ESP32. Я могу правильно подключиться к нему и получить данные, а также сохранить их в формате .csv, по одному на каждый день, в нужной папке. Проблема возникает, когда я меняю вкладку внутри этого приложения на ту, которая отображает 3 графика для каждого типа значений за последние 4 часа, я получаю следующую ошибку:

Код: Выделить всё

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\bacug\anaconda3\envs\deep_learning\lib\tkinter\__init__.py", line 545, in get
return self._tk.getint(value)
_tkinter.TclError: expected integer but got ""
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\bacug\anaconda3\envs\deep_learning\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
File "c:\Users\bacug\Downloads\Bioreacteur\code\graphs.py", line 363, in 
self.lower_edge.trace_add("write", lambda *args: update_graphs())
File "c:\Users\bacug\Downloads\Bioreacteur\code\graphs.py", line 354, in update_graphs
self.create_graphs()
File "c:\Users\bacug\Downloads\Bioreacteur\code\graphs.py", line 216, in create_graphs
self.data = self.get_data()
File "c:\Users\bacug\Downloads\Bioreacteur\code\graphs.py", line 345, in 
func=lambda : self.get_today_data("4H"),
File "c:\Users\bacug\Downloads\Bioreacteur\code\graphs.py", line 259, in get_today_data
lower_hour_time = dt.time((self.lower_edge.get()%24 if graph_type == "4H" else 0), 0, 0) # Pour lire la variable
File "C:\Users\bacug\anaconda3\envs\deep_learning\lib\tkinter\__init__.py", line 547, in get
return int(self._tk.getdouble(value))
_tkinter.TclError: expected floating-point number but got ""
Это не останавливает сохранение данных в файлах .csv, но перестает отображать значения, сохраненные с момента, когда я нажимаю на отображение этих графиков, даже при выходе из приложения и перезагрузке. это. Похоже, это также влияет на две другие вкладки, где я показываю другие графики: один для общей продолжительности сбора данных, а другой для последних 24 часов.
Вот мой код, он довольно длинный и разбит на несколько файлов:
Дляgraphs.py:

Код: Выделить всё

class Graph(ctk.CTkFrame):
def __init__(self, master: Misc,
type: Literal["4H", "Total", "24H"],
title: str, ylabel: str,
color: str, graphs: list[FigureCanvasTkAgg]
):
super().__init__(master=master, corner_radius=0)
self.app = master.master.master
self.graph: FigureCanvasTkAgg = None
self._type = type # Type de graphique 4H , Total ou 24H
self.title = title # Titre du graphique
self.ylabel = ylabel # Nom de l'axe des ordonnées
self.color = color
self.category: Literal["DO", "pH", "Temperature"] = self.title.split("Graph ")[1]
self.graphs: list[FigureCanvasTkAgg] = graphs # Liste des graphiques existants
def initialize_data(self, data: dict[str, list[Union[datetime, float]]]):
if data is None:
self.app.log_error(ValueError(f"Graph {self.category} data is None"))
return
self.timestamps = pd.DatetimeIndex(data["time"]) # Timestamps
self.values = data["values"] # Values of the graph given category
self.data = pd.DataFrame(
{self.category: self.values},
index=self.timestamps)
# Obtention des limites de la catégorie (DO, pH, Température)
self.category_value = get_category_boundaries(self.app, self.category)
# Obtention des limites supérieure et inférieure (seuils) de la catégorie du graphique
self.upper_boundary, self.lower_boundary = self.category_value
self.create_graph()
def create_graph(self):
if self._type == "4H":
self.data = self.data.asfreq(freq="10s")
elif self._type == "24H":
self.data = self.data.asfreq(freq="3min")
elif self._type == "Total":
self.data = self.data.asfreq(freq="2h")
# Création du graphique
ax: plt.Axes
fig: Figure
fig, ax = plt.subplots(dpi=70) #dpi = zoom amount
# Création des points sur le graphique
ax.plot(
self.data.index, self.data[self.category],
marker="s", markersize=1, linewidth=0.7, color=self.color, label=self.ylabel)
# Adding horizontal guide lines at y-values with specified color, linestyle, and linewidth
[ax.axhline(y, color="tab:red", linestyle=":", linewidth=5) for y in self.category_value]
start_date = self.timestamps[0]
end_date = self.timestamps[-1]
ax.set_xlim(mdates.datestr2num([start_date.strftime('%Y-%m-%d %H:%M:%S'), end_date.strftime('%Y-%m-%d %H:%M:%S')]))
ax.set_ylim(self.lower_boundary-2, self.upper_boundary+2)
# Add grids and labels
ax.grid(axis="y", color="gray", linestyle=":", linewidth=0.5)  # Adding grid lines with specified color, linestyle, and linewidth
if self._type == "4H":
ax.grid(axis="x", color="gray", linestyle=":", linewidth=1)
ax.set_ylabel(ylabel=self.ylabel, fontsize = 20)  # Setting xlabel to empty string and ylabel to the category
title = f"{self.category} over time - "
if self._type == "4H":
title += f"CSV: {start_date.strftime('%Y-%m-%d from %H:%M:%S')} to {end_date.strftime('%H:%M:%S')}"
elif self._type == "24H":
title += f"CSV: {start_date.strftime('%Y-%m-%d')}"
elif self._type == "Total":
title += f"from CSV: {start_date.strftime('%Y-%m-%d %H:%M:%S')} to CVS: {end_date.strftime('%Y-%m-%d %H:%M:%S')}"
ax.set_title(label=title, fontsize=25)
if self._type =='4H':
ax.xaxis.set_major_locator(mdates.MinuteLocator(interval=15)) #intervalle de l'axe des x, montre x toutes les 10mins
elif self._type =='24H':
ax.xaxis.set_major_locator(mdates.MinuteLocator(interval=60)) #intervalle de l'axe des x, montre x toutes les 30mins
elif self._type == 'Total':
ax.xaxis.set_major_locator(mdates.HourLocator(interval=24)) #intervalle de l'axe des x, montre x tout les 1 jour
# Using ConciseDateFormatter to format the x-axis dates with specific formats for different date components
formatter = mdates.ConciseDateFormatter(
locator=ax.xaxis.get_major_locator(),
formats=["%Y", "%b", "%d", "%HH", "%H:%M", "%S.%f"],  # Changed '%-HH' to '%H'
zero_formats=["", "%Y", "%b", "%b-%d", "%H:%M", "%H:%M"]
)
ax.xaxis.set_major_formatter(formatter)
# Final formatting
ax.tick_params(axis="both", labelsize=20)
if self.graph is not None:
plt.close(self.graph.figure)
# Création du widget Tkinter pour afficher le graphique
try:
graph = FigureCanvasTkAgg(fig, master=self)
graph.get_tk_widget().place(relx=0, rely=0, relwidth=1, relheight=1)
except Exception as e:
return
class GraphMenu(Menu):
def __init__(self, master,
title: str, func: Callable,
_type: Literal["4H", "Total", "24H"]):
super().__init__(master=master, title=title)
self.extra = lambda: self.create_graphs()
self.get_data = func # Fonction pour obtenir les données du graphique
self.graphs: list[FigureCanvasTkAgg] = [] # Liste des graphiques existants
self._type = _type
self.displayed_graph: ctk.StringVar = self.master.displayed_graph
self.displayed_graph.trace_add("write", self.change_displayed_graph)
self.create_widgets()
def create_widgets(self) ->  None:
self.loading_frame = ctk.CTkFrame(master=self, corner_radius=0)
self.loading_label = ctk.CTkLabel(master=self.loading_frame, text=f"Chargement des données...\n(temps estimé d'attente: {self.get_estimated_time()}s)")
self.loading_label.place(relx=0.5, rely=0.5, anchor="center")
self.graph_frame = ctk.CTkFrame(master=self, corner_radius=0)
# Création des graphiques en fonction de la catégorie
self.graph_temp = Graph(
master=self.graph_frame,
type=self._type,
title="Graph Temperature",
ylabel="Température\n(°C)",
color=ORANGE,
graphs=self.graphs,
)
self.graph_ph = Graph(
master=self.graph_frame,
type=self._type,
title="Graph pH",
ylabel="pH",
color=PURE_GREEN,
graphs=self.graphs,
)
self.graph_do = Graph(
master=self.graph_frame,
type=self._type,
title="Graph DO",
ylabel="DO\n(mg/L)",
color=PURE_BLUE,
graphs=self.graphs,
)
self.last_displayed_graph = self.graph_do
self.place_graphs()
def place_graphs(self):
# Placement des sous-frames dans le frame principal
if self.master._3_graph_at_once.get():
self.graph_do.place(relx=0.01, rely=0, relwidth=0.98, relheight=0.32)
self.graph_ph.place(relx=0.01, rely=0.35, relwidth=0.98, relheight=0.32)
self.graph_temp.place(relx=0.01, rely=0.7, relwidth=0.98, relheight=0.3)
else:
self.graph_do.place(relx=0.01, rely=0, relwidth=0.98, relheight=1)
self.graph_ph.place(relx=0.01, rely=0, relwidth=0.98, relheight=1)
self.graph_temp.place(relx=0.01, rely=0, relwidth=0.98, relheight=1)
def change_displayed_graph(self, *args): #change le graph affiché en fonction de celui choisi dans le combobox, de base affiche les 3 en meme temps
name_to_graph: dict[str, Graph] = {
"DO": self.graph_do,
"pH": self.graph_ph,
"Température": self.graph_temp,
"": None
}
displaying = name_to_graph[self.displayed_graph.get()]
if displaying is None: return
displaying.lift(self.last_displayed_graph)
self.last_displayed_graph = displaying
def create_graphs(self, instant_reload: bool = False) -> None:
if not instant_reload:
self.graph_frame.place_forget()
self.loading_frame.place(relx=0, rely=0, relwidth=1, relheight=1)
self.update()
self.data = self.get_data()
self.graph_frame.place(
relx=0,
rely=0.125 if self._type == "4H" else 0.075,
relwidth=1,
relheight=0.8 if self._type == "4H" else 0.85
)
self.graph_do.initialize_data(data={"time": self.data["time"], "values": self.data["values"]["DO"]})
self.graph_ph.initialize_data(data={"time": self.data["time"], "values": self.data["values"]["pH"]})
self.graph_temp.initialize_data(data={"time": self.data["time"], "values": self.data["values"]["Temperature"]})
self.update()
def get_estimated_time(self) -> float: return 1.5
def get_today_data(self, graph_type: Literal["4H", "24H", "Total"], selected_csv: str = None, data = None) -> dict[Literal["time", "values"], dict[Literal["DO", "pH", "Temperature"], list[float]]]:
timestamps_sorting: list[Literal[0, 1]]
data: dict[str, Union[list[datetime], dict[str, list[float]]]]
if graph_type == "4H":
if self.upper_edge.get() == ""  :
return
self.upper_edge: IntVar
self.lower_edge: IntVar
if selected_csv is None:
selected_csv = self.master.csv_filename.get()
day_carry = 0
if graph_type == "4H":
current_time = dt.time(self.upper_edge.get()%24, 0, 0)
if self.upper_edge.get() == 24: day_carry = 1
else: current_time = dt.time(0, 0, 0)
selected_csv_date = datetime.strptime(selected_csv, "%Y-%m-%d").date()
now = datetime.combine(
date=selected_csv_date + timedelta(days=day_carry),
time=current_time
) # Creer un objet now pour si on veut changer de csv, met a jour l'affichage et la date
now_str = now.strftime("%Y/%m/%d-%H:%M:%S") # Pour avoir la date en date heure
lower_hour_time = dt.time((self.lower_edge.get()%24 if graph_type == "4H" else 0), 0, 0) # Pour lire la variable
lower_hour = datetime.combine(
date=selected_csv_date,
time=lower_hour_time
)
lower_hour_str = lower_hour.strftime("%Y/%m/%d-%H:%M:%S")
day_data = self.master.load_data(self.master.csv_filenames[selected_csv]) # Va chercher la data du csv actuel
day_data_values = list(day_data.values())[0] # Met dans une liste toutes les valeurs de la data
timestamps: list[datetime] = [datetime.combine(now, datetime.strptime(t, "%H:%M:%S").time()) for t in day_data_values["Timestamp"]] # Collectionne tout les timestamps
now += timedelta(days=1 if graph_type != "4H" else 0)
now_str = now.strftime("%Y/%m/%d-%H:%M:%S")
timestamps = pd.DatetimeIndex([t for t in timestamps if lower_hour   None:
self.lower_edge_combobox = ctk.CTkComboBox(
master=self,
width=60,
bg_color=(GRAYDB, GRAY2B),
command=lambda event: self.upper_edge.set(self.lower_edge.get() + 4),
values=self.lower_edge_range,
variable=self.lower_edge
)
self.upper_edge_combobox = ctk.CTkComboBox(
master=self,
width=60,
bg_color=(GRAYDB, GRAY2B),
command=lambda event: self.lower_edge.set(self.upper_edge.get() - 4),
values=self.upper_edge_range,
variable=self.upper_edge
)
def reset_values():
self.upper_edge.set(datetime.now().hour)
if self.upper_edge.get() < 4:
self.upper_edge.set(4)
self.lower_edge.set(self.upper_edge.get() - 4)
ctk.CTkLabel(master=self, text="Heure de début (de la journée) :").place(relx=0.05, rely=0.01)
ctk.CTkLabel(master=self, text="Heure de fin (de la journée) :").place(relx=0.4, rely=0.01)
self.lower_edge_combobox.place(relx=0.25, rely=0.01)
self.upper_edge_combobox.place(relx=0.575, rely=0.01)
def update_graphs(self):
running = True
while running:
self.create_graphs()
self.update()
if self.terminate_flag.is_set():
running = False
return
sleep(1)
self.update()
class GraphTotal(GraphMenu):
def __init__(self, master, title: str):
super().__init__(master=master, title=title, func=lambda: self.get_all_data(), _type="Total")
self.data = {"time": [], "values": {"DO": [], "pH": [], "Temperature": []}}
self.last_amount_of_records = 0
def get_estimated_time(self) -> float:
return len(get_data_filenames()) * 2.5
def get_all_data(self) -> dict[Literal['time', 'values'], dict[Literal["DO", "pH", "Temperature"], list[int]]]:
# Fonction pour obtenir les données pour la catégorie spécifiée (DO, pH, Température) sur les 4 dernières heures
self.date_range = get_data_filenames()
if self.last_amount_of_records == len(self.date_range):
return self.data # That to avoid reloading the data when the amount of record is still the same
# What is essentially called "cache"
self.last_amount_of_records = len(self.date_range)
for date in self.date_range:
self.data = self.get_today_data("Total", date, self.data)
return self.data
class Graph24H(GraphMenu):
def __init__(self, master, title: str):
super().__init__(
master=master,
title=title,
func=lambda: self.get_today_data("24H"),
_type="24H"
)
некоторые из них находятся в настройках:

Код: Выделить всё

# Fonctions pour le csv
def get_today_csv_filename():
return f"data/{datetime.now().strftime('%Y-%m-%d')}.csv"
def get_filenames_path(path: str, format: str):
return [os.path.join(path, filename) for filename in os.listdir(path) if filename.endswith(format)]
def get_data_filenames_path():
return get_filenames_path(r".\data", ".csv")
def get_data_filenames():
return [filename[:-4] for filename in os.listdir(r".\data") if filename.endswith(".csv")]
def get_category_boundaries(app, category: str) -> tuple[float, float]:
return {
"DO": (app.do_upper_boundary.get(), app.do_lower_boundary.get()),
"pH": (app.ph_upper_boundary.get(), app.ph_lower_boundary.get()),
"Temperature": (app.temp_upper_boundary.get(), app.temp_lower_boundary.get())
}[category]
def import_settings(app) ->  dict[str, Union[str, bool]]:
try:
with open(SETTINGS_FILENAME_PATH, "r") as f:
return json.load(f)
except Exception as e:
app.log_error(e, custom_error_message="Erreur lors de l'import des paramètres: ")
# Constants
TODAY_CSV_FILENAME = get_today_csv_filename()
SETTINGS_FILENAME_PATH = r".\settings.json"
called = "called"
if __name__ == "__main__":
# Get the list of data filenames
print(get_data_filenames())
меню_настроек:

Код: Выделить всё

class SettingsMenu(Menu):
def __init__(self, master, title: str):
super().__init__(master=master, title=title, fg_color=(GRAYCF, GRAY33))
self.relx = 0.7
self.relheight = 1
self.relwidth = 0.3
self.create_widgets()
def export_settings(self) ->  None:
try:
settings = {
"auto_saving": self.master.auto_saving.get(),
"port": self.port_cbb.get(),
"baudrate": self.baudrate_cbb.get(),
"appearance_value": self.appearance_value.get(),
"default_font_size": self.police_ecriture_cbb.get(),
"y_upper_view_limit":self.master.y_upper_view_limit.get(),
"y_lower_view_limit":self.master.y_lower_view_limit.get(),
"time_window_default_to": self.master.time_window_default_to.get(),
"graph_types_values": {
"4H": {
"xticks_interval": {
"value": self.master.graph_4h_xticks_interval_val.get(),
"unit": self.master.graph_4h_xticks_interval_unit.get()
},
"data_frequency": {
"value": self.master.graph_4h_data_frequency_val.get(),
"unit": self.master.graph_4h_data_frequency_unit.get()}},
"24H": {
"xticks_interval": {
"value": self.master.graph_24h_xticks_interval_val.get(),
"unit": self.master.graph_24h_xticks_interval_unit.get()
},
"data_frequency": {
"value": self.master.graph_24h_data_frequency_val.get(),
"unit": self.master.graph_24h_data_frequency_unit.get()
}},
"Total": {
"xticks_interval": {
"value": self.master.graph_total_xticks_interval_val.get(),
"unit": self.master.graph_total_xticks_interval_unit.get()
},
"data_frequency": {
"value": self.master.graph_total_data_frequency_val.get(),
"unit": self.master.graph_total_data_frequency_unit.get()
}}},
"graph_categories_values": {
"DO": {
"boundaries_values": {
"min": self.master.do_lower_boundary.get(),
"max": self.master.do_upper_boundary.get()
},
"yticks_ticks_skip": self.master.do_yticks_ticks_skip.get()
},
"pH": {
"boundaries_values": {
"min": self.master.ph_lower_boundary.get(),
"max": self.master.ph_upper_boundary.get()
},
"yticks_ticks_skip": self.master.ph_yticks_ticks_skip.get()
},
"Temperature": {
"boundaries_values": {
"min": self.master.temp_lower_boundary.get(),
"max": self.master.temp_upper_boundary.get()
},
"yticks_ticks_skip": self.master.temp_yticks_ticks_skip.get()
}}}
with open(SETTINGS_FILENAME_PATH, "w") as f:
json.dump(settings, f, indent=2)
except Exception as e:
self.master.log_error(e, custom_error_message="Erreur lors de l'export des paramètres: ")
raise e
Я знаю, что основная ошибка возникает из-за файлов графиков, но я не знаю, как ее исправить. Мне помог друг с кодированием файлаgraphs.py, но я вполне потерян таким, какой он есть. Я также чувствую, что, возможно, ошибка может возникнуть откуда-то еще в файлах, поэтому я помещаю части кода, связанные с ней. Если кто-нибудь подскажет, как это исправить, буду очень благодарен.

Подробнее здесь: https://stackoverflow.com/questions/784 ... number-but

Вернуться в «Python»