Я пытаюсь встроить (полярную) радиолокационную карту в окно Tkinter
, но столкнулся с некоторыми проблемами при позиционировании некоторых элементов в matplotlib
figure
.
Вот мой код:
from math import pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as tk
from random import randint
def draw_diagram(categories, values, overlay, fig):
fig.clear()
length = len(values)
ax = setup_ax(fig, categories)
draw(values, ax, length, fill='red')
draw(overlay, ax, length, fill='orange', label='Potential')
l = ax.legend(bbox_to_anchor=(1.15, 1.15), loc="upper right")
def setup_ax(fig, categories):
ax = fig.add_subplot(111, polar=True)
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
ax.set_yticklabels([])
ax.set_xticklabels(categories)
ax.set_ylim(0, 100)
return ax
def draw(values, ax, length, fill, label='Current'):
x_as = [n / float(length) * 2 * pi for n in range(length)]
ax.plot(x_as, values, fill, linewidth=0.5, linestyle='solid', label=label, zorder=-1)
ax.fill(x_as, values, fill, alpha=0.3)
for lbl, i in zip(ax.get_xticklabels(), range(length)):
angle = i / float(length) * 2 * pi
if angle in (0, pi):
lbl.set_horizontalalignment('center')
elif 0 < angle < pi:
lbl.set_horizontalalignment('left')
else:
lbl.set_horizontalalignment('right')
win = tk.Tk()
win.rowconfigure(0, weight=1)
win.columnconfigure(0, weight=1)
win.geometry('300x300')
frame = tk.Frame(win)
frame.rowconfigure(0, weight=1)
frame.columnconfigure(0, weight=1)
frame.grid(sticky='nesw')
fig = Figure(dpi=100)
draw_diagram(['LONG HEADING HERE'] * 8, [65]*8, [90]*8, fig)
graph_canvas = FigureCanvasTkAgg(fig, master=frame)
graph_canvas.draw()
graph_canvas.get_tk_widget().grid(sticky='nesw')
win.mainloop()
Вывод:
![Matplotlib image produced](https://i.stack.imgur.com/q5fjT.png)
Мои основные проблемы:
-
xlabels
может быть длинным, и я не уверен, как заставить их автоматически помещаться в рамку, будь то путем уменьшения размера шрифта, их поворота или разделения текста на несколько строк. - Легенда должна быть в верхней - правый угол рамки (не диаграммы), как показано в примерах ниже.
- Не такая уж крупная сделка, но линия, проведенная вокруг каждого графика, не закрыта с одной стороны.
Мои другие попытки
# 1
Адаптируя код из этот ответ вместо этого, чтобы метод draw
был:
def draw(values, ax, length, fill, label='Current'):
x_as = [n / float(length) * 2 * pi for n in range(length)]
ax.plot(x_as, values, fill, linewidth=0.5, linestyle='solid', label=label,
zorder=-1)
ax.fill(x_as, values, fill, alpha=0.3)
for lbl, i in zip(ax.get_xticklabels(), range(length)):
angle = i / float(length) * 360
x,y = lbl.get_position()
lbl = ax.text(x,y+1, lbl.get_text(), transform=lbl.get_transform(),
ha=lbl.get_ha(), va=lbl.get_va())
lbl.set_rotation(angle)
ax.set_xticklabels([])
Дает :
![Output 2](https://i.stack.imgur.com/p2RoK.png)
Я не уверен, как правильно расположить метки x. Распечатка x, y
позиций каждой этикетки в for
-l oop все дает 0 0
.
# 2
Вращающиеся этикетки, угол которых не кратен 90 , с адаптированным кодом, поэтому функция draw
:
def draw(values, ax, length, fill, label='Current'):
x_as = [n / float(length) * 2 * pi for n in range(length)]
ax.plot(x_as, values, fill, linewidth=0.5, linestyle='solid', label=label,
zorder=-1)
ax.fill(x_as, values, fill, alpha=0.3)
for lbl, i in zip(ax.get_xticklabels(), range(length)):
angle = i / float(length) * 360
if angle % 90 == 0:
angle = 0
else:
angle = angle - 90
x,y = lbl.get_position()
lbl = ax.text(x,y+1, lbl.get_text(), transform=lbl.get_transform(),
ha=lbl.get_ha(), va=lbl.get_va())
lbl.set_rotation(angle)
Дает (с оригиналом для сравнения):
![Output 3](https://i.stack.imgur.com/Aba2C.png)
Помимо других вопросов, легенда теперь также неуместна, чего я хотел бы избежать.