Das Problem:
Egal welchen Datumsbereich ich auswähle, das px.timeline-Diagramm stellt seine X-Achse immer ab dem 1. Januar 1970 dar.
Das Geheimnis:
Das sollte nicht passieren. Ich habe direkt vor dem Erstellen der Figur print(data.dtypes) und print(data.head()) in meine @render_plotly-Funktion eingefügt. Die Konsole bestätigt, dass der Daten-DataFrame nicht leer ist und dass meine Spalten fecha_inicio und fecha_fin vom Typ datetime64[ns] sind und die korrekten Daten enthalten (z. B. von 2025).
Plotly scheint die korrekten datetime-Objekte für 2025 zu empfangen, ignoriert sie jedoch und verwendet standardmäßig der Unix-Epoche (1970).
Hier finden Sie den gesamten Code und die Daten, die zum Reproduzieren dieses Fehlers erforderlich sind.
1. app.py
(Sie müssen Shiny, Pandas, Plotly, Shinywidgets, Shinyswatch installieren)
Code: Select all
from shiny.express import render, ui, input
import pandas as pd
from shiny import reactive
from pathlib import Path
import plotly.express as px
from shinywidgets import render_plotly
from shinyswatch import theme
try:
df_calderas = pd.read_csv('calderas.csv')
# Convert to datetime on load
df_calderas['fecha_inicio'] = pd.to_datetime(df_calderas['fecha_inicio'])
df_calderas['fecha_fin'] = pd.to_datetime(df_calderas['fecha_fin'])
df_calderas['caldera'] = df_calderas['caldera'].str.capitalize()
except FileNotFoundError:
print("ERROR: calderas.csv not found.")
df_calderas = pd.DataFrame(columns=["caldera", "fecha_inicio", "fecha_fin"])
ui.page_opts(theme=theme.united)
ui.h1("Dashboard Bug", style="text-align: center;")
# --- 2. UI DATE INPUTS (FLATPICKR) ---
with ui.card(style="margin-bottom: 20px;"):
ui.h5("Select Date Range", style="text-align: center;")
with ui.tags.div(class_="input-container"):
with ui.tags.div(class_="input-group"):
ui.tags.label("From:", _for="inicio")
ui.tags.input(id="inicio", type="text", class_="flatpickr")
with ui.tags.div(class_="input-group"):
ui.tags.label("To:", _for="fin")
ui.tags.input(id="fin", type="text", class_="flatpickr")
# --- 3. REACTIVE FILTER ---
@reactive.calc
def filtered_calderas():
start_date_str = input.inicio()
end_date_str = input.fin()
# Wait for inputs
if not start_date_str or not end_date_str:
return pd.DataFrame(columns=df_calderas.columns)
# Parse dates from flatpickr
formato_fecha = "%d-%m-%Y %H:%M"
start_date = pd.to_datetime(start_date_str, format=formato_fecha)
end_date = pd.to_datetime(end_date_str, format=formato_fecha)
# Filter logic
condicion1 = df_calderas['fecha_inicio'] = start_date
return df_calderas[condicion1 & condicion2]
# --- 4. THE PROBLEMATIC PLOTLY CHART ---
with ui.card(style="margin-top: 20px;"):
ui.tags.h4("Boiler On-Time Chart (The Problem)")
@render_plotly
def show_calderas():
data = filtered_calderas()
# If data is empty, plot an empty chart
if data.empty:
print("--- Filtered data is EMPTY. Plotting empty chart. ---")
return px.timeline(title="No data for selected dates")
# --- THIS IS THE MYSTERY ---
# My console prints prove the data is correct!
print("\n--- DATA BEING SENT TO PLOTLY ---")
print(data.dtypes)
print(data.head())
print("---------------------------------\n")
orden_eje_y = sorted(data['caldera'].unique())
fig = px.timeline(
data_frame=data,
x_start="fecha_inicio", # Passing the correct datetime col
x_end="fecha_fin", # Passing the correct datetime col
template="simple_white",
y="caldera",
color="caldera",
title="Boiler On-Time",
category_orders={"caldera": orden_eje_y}
)
fig.update_layout(
xaxis_title="Date and Time",
yaxis_title="Boilers",
xaxis=dict(tickformat="%d-%m-%Y %H:%M") # Set date format
)
fig.update_xaxes(
tickangle=60,
nticks=20,
)
return fig
# --- 5. JAVASCRIPT FOR FLATPICKR ---
ui.tags.link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css")
ui.tags.script(src="https://cdn.jsdelivr.net/npm/flatpickr")
ui.tags.script(src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/es.js") # Spanish locale
ui.tags.script("""
$(document).ready(function() {
const config = {
enableTime: true,
enableSeconds: false,
dateFormat: "d-m-Y H:i",
time_24hr: true,
locale: "es"
};
// Initialize inputs
const fp_inicio = flatpickr("#inicio", {
...config,
defaultDate: "20-10-2025 06:00", // Set default for testing
onChange: function(selectedDates, dateStr) {
if (dateStr) { Shiny.setInputValue("inicio", dateStr, {priority: "event"}); }
}
});
const fp_fin = flatpickr("#fin", {
...config,
defaultDate: "21-10-2025 18:00", // Set default for testing
onChange: function(selectedDates, dateStr) {
if (dateStr) { Shiny.setInputValue("fin", dateStr, {priority: "event"}); }
}
});
// Trigger the inputs on app load so it filters immediately
Shiny.setInputValue("inicio", "20-10-2025 06:00", {priority: "event"});
Shiny.setInputValue("fin", "21-10-2025 18:00", {priority: "event"});
});
""")
(Platzieren Sie diese Datei im selben Verzeichnis wie app.py)
Code: Select all
caldera,fecha_inicio,fecha_fin
Caldera1,2025-10-20 08:00:00,2025-10-20 10:30:00
Caldera2,2025-10-20 09:15:00,2025-10-20 11:00:00
Caldera3,2025-10-20 10:00:00,2025-10-20 14:45:00
Caldera1,2025-10-21 14:00:00,2025-10-21 15:10:00
Caldera2,2025-10-21 07:00:00,2025-10-21 12:30:00
Caldera3,2025-10-21 11:30:00,2025-10-21 16:00:00
Wenn ich die App ausführe, gibt die Konsole dies aus, was beweist, dass meine Funktion filtered_calderas() funktioniert und korrekte Daten an Plotly sendet:
Code: Select all
--- DATA BEING SENT TO PLOTLY ---
caldera object
fecha_inicio datetime64[ns]
fecha_fin datetime64[ns]
dtype: object
caldera fecha_inicio fecha_fin
2 Caldera3 2025-10-20 10:00:00 2025-10-20 14:45:00
3 Caldera1 2025-10-20 14:00:00 2025-10-20 15:10:00
4 Caldera2 2025-10-21 07:00:00 2025-10-21 12:30:00
5 Caldera1 2025-10-21 11:00:00 2025-10-21 16:00:00
---------------------------------
- Zeitzonen: Ich vermutete einen Zeitzonenkonflikt (naiv vs. bewusst). Ich habe versucht, .dt.tz_localize(None) sowohl für die CSV-Daten als auch für die Eingabedaten zu verwenden, aber der Fehler von 1970 besteht weiterhin.
- Manuelle Zeichenfolgen: Ich habe versucht, die Datums- und Uhrzeitangaben manuell mit strftime in Zeichenfolgen umzuwandeln, bevor ich sie an Plotly übergeben habe. Dies ergibt auch 1970.
- Neustart: Ich habe den Kernel und die App viele Male neu gestartet.

Mobile version