Segment anchoring problem
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 15/100
- Tipo de issue
- Error
- Claridad
- Necesita aclaración
- Estado de actividad
- Estancado
- Stack tecnológico
- matplotlib, pandas, python
- Área
- data-visualization
Línea de trabajo
Comience por los puntos de entrada add_lines y update_chart del script proporcionado y, después, inspeccione cómo se reconstruyen los ejes del gráfico durante el zoom y la navegación. Reproduzca el movimiento de la línea con el CSV adjunto y determine el comportamiento de anclaje esperado; en el issue no se identifica ningún archivo del repositorio ni ninguna prueba.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Hello,
FX_NAS100, 5.csv
I hope I'm not out of line with the problem I can't solve.
I would like to draw a red line and a green line representing the amplitude of the US trading session on the NASDAQ100.
The history is in candlestick units of 5 minutes.
The two lines (for the historical period) should be drawn from the 15:30 candle to the 21:55 candle.
Tracing is correct at first, but the lines move as soon as you use the program's zoom or advance functions.
Perhaps tracing with “axhline” isn't the right solution; I've tried using the xplot method to exploit the position of the reference candle index, but I can't get anywhere.
Do you have any ideas for solving this problem?
Later, I want to draw other lines with different levels, but until I solve this problem, I'm stuck.
Thanks
import` pandas as pd
import mplfinance as mpf
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
from tkinter import ttk
import os
import matplotlib.pyplot as plt
df_bourse = pd.DataFrame([
{'Année': 2022, 'Période': 'Été US', 'Début': '2022-03-14', 'Fin': '2022-03-28', 'Modedate': 1},
{'Année': 2022, 'Période': 'Hiver US', 'Début': '2022-10-31', 'Fin': '2022-11-04', 'Modedate': 1},
{'Année': 2023, 'Période': 'Été US', 'Début': '2023-03-13', 'Fin': '2023-03-24', 'Modedate': 1},
{'Année': 2023, 'Période': 'Hiver US', 'Début': '2023-10-30', 'Fin': '2023-11-03', 'Modedate': 1},
{'Année': 2024, 'Période': 'Été US', 'Début': '2024-03-11', 'Fin': '2024-03-28', 'Modedate': 1},
{'Année': 2024, 'Période': 'Hiver US', 'Début': '2024-10-28', 'Fin': '2024-11-01', 'Modedate': 1}
])
df_bourse['Début'] = pd.to_datetime(df_bourse['Début'])
df_bourse['Fin'] = pd.to_datetime(df_bourse['Fin'])
csv_path = r"C:\Formation Python\FX_NAS100, 5.csv"
df = pd.read_csv(csv_path)
csv_filename = os.path.basename(csv_path)
df["time"] = pd.to_datetime(df["time"], unit='s')
df['date'] = df['time'].dt.date
def determine_modedate(date):
for _, row in df_bourse.iterrows():
if row['Début'].date() <= date <= row['Fin'].date():
return row['Modedate']
return 2
df['Modedate'] = df['date'].apply(determine_modedate)
df['amp_journée'] = 0.0
for day in df['date'].unique():
day_data = df[df['date'] == day]
if not day_data.empty:
modedate = day_data['Modedate'].iloc[0]
if modedate == 1:
start_time = pd.to_datetime("14:30").time()
end_time = pd.to_datetime("21:00").time()
else:
start_time = pd.to_datetime("15:30").time()
end_time = pd.to_datetime("22:00").time()
filtered_data = day_data[(day_data['time'].dt.time >= start_time) & (day_data['time'].dt.time <= end_time)]
if not filtered_data.empty:
high_max = filtered_data['high'].max()
low_min = filtered_data['low'].min()
amplitude = high_max - low_min
df.loc[df['date'] == day, 'amp_journée'] = amplitude
percentages = [25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275]
for p in percentages:
df[f'{p}%'] = df['amp_journée'] * (p / 100)
df[f'-{p}%'] = df['amp_journée'] * (-p / 100)
cols = ['date', 'time', 'open', 'high', 'low', 'close', 'Modedate', 'amp_journée']
percentage_cols = [f'{p}%' for p in percentages] + [f'-{p}%' for p in percentages]
df = df[cols + percentage_cols]
# Interface graphique principale
root = tk.Tk()
root.title("Graphique en chandelier japonais")
root.state('zoomed')
frame = ttk.Frame(root)
frame.pack(fill=tk.BOTH, expand=True)
start_index = 0
num_candles = 100
# Champs pour les pas
step_frame = ttk.Frame(root)
step_frame.pack(side=tk.TOP, fill=tk.X)
tk.Label(step_frame, text="Pas graphique:").pack(side=tk.LEFT, padx=5)
graph_step_entry = ttk.Entry(step_frame, width=5)
graph_step_entry.insert(0, "30")
graph_step_entry.pack(side=tk.LEFT, padx=5)
tk.Label(step_frame, text="Pas zoom:").pack(side=tk.LEFT, padx=5)
zoom_step_entry = ttk.Entry(step_frame, width=5)
zoom_step_entry.insert(0, "30")
zoom_step_entry.pack(side=tk.LEFT, padx=5)
# Fenêtre pour afficher le DataFrame
def show_dataframe():
df_window = tk.Toplevel(root)
df_window.title("Tableau des données")
df_window.state('zoomed')
tree_frame = ttk.Frame(df_window)
tree_frame.pack(fill=tk.BOTH, expand=True)
tree_scroll_y = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL)
tree_scroll_x = ttk.Scrollbar(tree_frame, orient=tk.HORIZONTAL)
tree = ttk.Treeview(tree_frame, yscrollcommand=tree_scroll_y.set, xscrollcommand=tree_scroll_x.set)
tree_scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
tree_scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
tree_scroll_y.config(command=tree.yview)
tree_scroll_x.config(command=tree.xview)
tree.pack(fill=tk.BOTH, expand=True)
df_display = df.copy().reset_index()
numeric_columns = ['amp_journée'] + [col for col in df_display.columns if '%' in col] + ['open', 'high', 'low', 'close']
for column in numeric_columns:
if column in df_display.columns:
df_display[column] = df_display[column].round(2)
tree["columns"] = ["index"] + list(df_display.columns)[1:]
tree["show"] = "headings"
tree.heading("index", text="Index")
tree.column("index", width=50, anchor='center')
for column in df_display.columns[1:]:
tree.heading(column, text=column)
if column == 'time':
tree.column(column, width=200, anchor='center')
else:
tree.column(column, width=100, anchor='center')
for _, row in df_display.iterrows():
tree.insert("", "end", values=[row['index']] + list(row)[1:])
# Champ de saisie pour l'index
index_frame = ttk.Frame(df_window)
index_frame.pack(side=tk.TOP, fill=tk.X)
tk.Label(index_frame, text="Index:").pack(side=tk.LEFT, padx=5)
index_entry = ttk.Entry(index_frame, width=10)
index_entry.pack(side=tk.LEFT, padx=5)
def select_by_index(event=None):
index = index_entry.get()
if index.isdigit():
index = int(index)
for item in tree.get_children():
if int(tree.item(item)['values'][0]) == index:
tree.selection_set(item)
tree.see(item)
break
index_entry.bind('<Return>', select_by_index)
df_window.mainloop()
btn_show_df = ttk.Button(root, text="Afficher le tableau", command=show_dataframe)
btn_show_df.pack(side=tk.TOP, pady=5)
# Ajouter une ligne rouge et verte
def add_lines(ax, df_slice):
try:
unique_dates = df_slice['date'].unique()
for date in unique_dates:
daily_data = df_slice[df_slice['date'] == date]
if daily_data.empty:
continue
modedate = daily_data['Modedate'].iloc[0]
if modedate == 1:
start_time = pd.to_datetime("14:30").time()
end_time = pd.to_datetime("21:00").time()
else:
start_time = pd.to_datetime("15:30").time()
end_time = pd.to_datetime("21:55").time()
filtered_data = daily_data[
(daily_data['time'].dt.time >= start_time) &
(daily_data['time'].dt.time <= end_time)
]
if filtered_data.empty:
continue
max_high = filtered_data['high'].max()
min_low = filtered_data['low'].min()
time_range = df_slice['time']
xmin = (pd.Timestamp.combine(date, start_time) - time_range.min()).total_seconds() / (time_range.max() - time_range.min()).total_seconds()
xmax = (pd.Timestamp.combine(date, end_time) - time_range.min()).total_seconds() / (time_range.max() - time_range.min()).total_seconds()
ax.axhline(y=max_high, color='red', linestyle='--', xmin=xmin, xmax=xmax)
ax.axhline(y=min_low, color='green', linestyle='--', xmin=xmin, xmax=xmax)
except Exception as e:
pass
# fonction pour gérer le mouvement de la souris
def on_mouse_move(event):
if event.inaxes:
x, y = event.xdata, event.ydata
ax = event.inaxes
# Effacer les lignes précédentes
for line in ax.lines:
if line.get_label() in ['crosshair_h', 'crosshair_v']:
line.remove()
# Dessiner les nouvelles lignes
ax.axhline(y=y, color='black', linewidth=0.5, label='crosshair_h')
ax.axvline(x=x, color='black', linewidth=0.5, label='crosshair_v')
# Mettre à jour les données dans la fenêtre
if df_slice is not None and len(df_slice) > 0:
index = max(0, min(int(x), len(df_slice) - 1))
data = df_slice.iloc[index]
info_text = f"Index: {start_index + index}\nOpen: {data['open']:.2f}\nHigh: {data['high']:.2f}\nLow: {data['low']:.2f}\nClose: {data['close']:.2f}\nTime: {data['time']}"
info_window.set(info_text)
# Mise à jour des valeurs X et Y
x_value.set(f"X: {data['time']}")
y_value.set(f"Y: {y:.2f}")
# Redessiner le graphique
fig.canvas.draw_idle()
# Evènement molette de la sourie
def on_scroll(event):
global num_candles
if event.button == 'up':
num_candles = max(num_candles - int(zoom_step_entry.get()), 10)
elif event.button == 'down':
num_candles += int(zoom_step_entry.get())
update_chart()
# Fonctions pour le graphique
def update_chart():
global start_index, num_candles, df_slice, fig
plt.close('all') # Ferme toutes les figures existantes
df_slice = df.iloc[start_index:start_index + num_candles]
if df_slice.empty:
return
df_ohlc = df_slice[['time', 'open', 'high', 'low', 'close']].copy()
df_ohlc.set_index('time', inplace=True)
fig, axlist = mpf.plot(df_ohlc, type='candle', style='charles', title=csv_filename,
ylabel='Prix', volume=False, returnfig=True)
ax = axlist[0]
add_lines(ax, df_slice)
if hasattr(frame, "canvas"):
frame.canvas.get_tk_widget().destroy()
canvas = FigureCanvasTkAgg(fig, master=frame)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
frame.canvas = canvas
fig.canvas.mpl_connect('motion_notify_event', on_mouse_move)
fig.canvas.mpl_connect('scroll_event', on_scroll)
def increase_candles():
global num_candles
num_candles += int(zoom_step_entry.get())
update_chart()
def decrease_candles():
global num_candles
num_candles = max(num_candles - int(zoom_step_entry.get()), 10) # Minimum de 10 chandeliers
update_chart()
def move_right():
global start_index
start_index += int(graph_step_entry.get())
update_chart()
def move_left():
global start_index
start_index = max(start_index - int(graph_step_entry.get()), 0)
update_chart()
# Boutons
button_frame = ttk.Frame(root)
button_frame.pack(side=tk.BOTTOM, fill=tk.X)
plus_button = ttk.Button(button_frame, text="+", command=decrease_candles)
plus_button.pack(side=tk.LEFT, padx=5, pady=5)
minus_button = ttk.Button(button_frame, text="-", command=increase_candles)
minus_button.pack(side=tk.LEFT, padx=5, pady=5)
left_button = ttk.Button(button_frame, text="←", command=move_left)
left_button.pack(side=tk.LEFT, padx=5, pady=5)
right_button = ttk.Button(button_frame, text="→", command=move_right)
right_button.pack(side=tk.LEFT, padx=5, pady=5)
# Fenêtre d'information
info_frame = ttk.Frame(root)
info_frame.pack(side=tk.BOTTOM, fill=tk.X)
# Sous-frame pour les informations centrées
center_info_frame = ttk.Frame(info_frame)
center_info_frame.pack(side=tk.LEFT, expand=True)
info_window = tk.StringVar()
info_label = ttk.Label(center_info_frame, textvariable=info_window, justify=tk.LEFT)
info_label.pack(pady=10)
# Sous-frame pour les valeurs X et Y à droite
xy_info_frame = ttk.Frame(info_frame)
xy_info_frame.pack(side=tk.RIGHT)
x_value = tk.StringVar()
y_value = tk.StringVar()
x_label = ttk.Label(xy_info_frame, textvariable=x_value, justify=tk.LEFT)
y_label = ttk.Label(xy_info_frame, textvariable=y_value, justify=tk.LEFT)
x_label.pack(padx=10, anchor='w')
y_label.pack(padx=10, anchor='w')
update_chart()
root.mainloop()
- Lenguaje dominante
- Python
- Estrellas
- 4.4k
- Forks
- 678
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de matplotlib/mplfinance
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
matplotlib/mplfinance#672 ·
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 10/100
matplotlib/mplfinance#700 ·
-
enhancement
Dificultad 5/5 Más de una semana Aptitud para principiantes 30/100
matplotlib/mplfinance#695 ·
-
question
Dificultad 3/5 1-2 días Aptitud para principiantes 25/100
matplotlib/mplfinance#691 · 1 comentario ·
-
question
Dificultad 4/5 3-5 días Aptitud para principiantes 52/100
matplotlib/mplfinance#690 · 5 comentarios ·
Todos los issues de matplotlib/mplfinance
Issues similares
-
[Bug] reef-hermes tells me to resume with hermes --resume, which does not work from my shell Abiertoarea: harness bug status: needs-triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Human-Agent-Society/reef#625 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 80/100
learningequality/kolibri#15351 · 2 comentarios ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
-
Name consistency Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
eellak/triplestore#65 · 1 comentario ·