(wxpython) делает статическую панель matplotlib NavigationToolbar для фигуры внутри прокручиваемой панели - PullRequest
1 голос
/ 06 апреля 2019

У меня есть фигура Matplotlib с большим количеством подзаговоров, которая нуждается в ScrolledPanel. Теперь я хочу navigation toolbar для фигуры, которая остается статичной, когда фигура panel прокручивается. Я попытался добавить его на другую панель, кроме родительского холста, но это не работает (панель инструментов навигации остается только внутри родительского холста).
Есть ли способ, чтобы панель навигации matplotlib оставалась статичной, но оставляла прокрутку остальной части холста?
Вот мой полный код:

import wx
import wx.lib.scrolledpanel

import matplotlib
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
from matplotlib.figure import Figure

import wx.lib.inspection

matplotlib.use('WXAgg')


class PlotDemoApp(object):
    def __init__(self, data):
        self.app = wx.App()
        self.frame = PlotCanvas(None, -1, "PlotCanvas", data)
        self.frame.Show(True)
        wx.lib.inspection.InspectionTool().Show()
        self.app.MainLoop()


class PlotCanvas(wx.Frame):
    def __init__(self, parent, wxid, title, data):
        wx.Frame.__init__(self, parent, wxid, title)

        self.box_main = wx.BoxSizer(wx.VERTICAL)

        panel_lower = wx.lib.scrolledpanel.ScrolledPanel(self, size=(2500,-1))
        panel_lower.SetupScrolling()
        panel_lower.SetBackgroundColour("White")
        self.box_lower = wx.BoxSizer(wx.HORIZONTAL)

        box_local = wx.BoxSizer(wx.VERTICAL)
        plt = Figure(figsize=(95,10))
        num_columns = len(data.columns)
        axes_1 = plt.add_subplot(1, num_columns, 1)
        data_numpy = data[data.columns[0]].to_numpy()
        depth = data.index.to_numpy()
        plt.gca().invert_yaxis()
        plt.subplots_adjust(left=0.01, right=1.00, top=0.95, bottom=0.05)
        axes_1.plot(data_numpy, depth)
        for i in range(1, num_columns):
            axes_tmp = plt.add_subplot(1, num_columns, i+1, sharey=axes_1)
            axes_tmp.set(xlabel=data.columns[i], ylabel='Depth', title='Depth vs ' + data.columns[i])

            data_numpy = data[data.columns[i]].to_numpy()

            plt.gca().invert_yaxis()
            axes_tmp.plot(data_numpy, depth)
        canvas = FigureCanvas(panel_lower, -1, plt)
        canvas.draw()
        box_local.Add(canvas, 1, wx.EXPAND)
        panel_nav = wx.Panel(self)
        box_nav = wx.BoxSizer(wx.HORIZONTAL)
        toolbar = NavigationToolbar(canvas)
        box_nav.Add(toolbar)
        panel_nav.SetSizer(box_nav)
        toolbar.Realize()
        self.box_main.Add(panel_nav, 0, wx.CENTER)
        self.box_lower.Add(box_local, 1, wx.EXPAND)

        self.box_main.Add(panel_lower, 1, wx.EXPAND)
        panel_lower.SetSizer(self.box_lower)
        self.SetSizer(self.box_main)
        self.box_main.Layout()

data вот кадр данных панд
Пример данных:

| index | BS   | CAL  |
|-------|------|------|
| 162   | 17.5 | 17.4 |
| 163   | 17.8 | 17.7 |
| 164   | 17.8 | 17.9 |

1 Ответ

2 голосов
/ 09 апреля 2019

Надеюсь, это то, что вы после или, по крайней мере, указывает вам в правильном направлении.

Панель инструментов навигации matplotlib, кажется, приварена к самому графику, но она может быть скрыта.

Пока он остается скрытым, его функции все еще доступны, поэтому мы можем создать собственный toolbar и назначить ему функции на скрытой панели инструментов.

Примерно так:

import wx
import wx.lib.scrolledpanel as scrolled
import pandas as pd
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
from matplotlib.figure import Figure

# images in /usr/share/matplotlib/mpl-data/images
# Your system may differ!

class PlotPanel(scrolled.ScrolledPanel):
    def __init__(self,parent):
        scrolled.ScrolledPanel.__init__(self, parent)
        self.SetupScrolling(scroll_x=True, scroll_y=True, scrollToTop=False, scrollIntoView=False)
        self.ShowScrollbars(True,True)
        self.plt = Figure(figsize=(95,10))
        self.canvas = FigureCanvas(self,-1, self.plt)
        self.toolbar = NavigationToolbar(self.canvas)

        #Hide the Matplotlib toolbar because we are going to create own own
        #but use the functions of this toolbar.
        self.toolbar.Hide()

    def plot(self):
        d = {'BS':[17.54,17.55,17.54,17.53,17.55,17.54],'CAL':[17.46,17.47,17.49,17.44,17.47,17.49]}
        data = pd.DataFrame(d, index=['1','2','3','4','5','6'])

        num_columns = len(data.columns)
        axes_1 = self.plt.add_subplot(1, num_columns, 1)
        #data_numpy = data[data.columns[0]].to_numpy()  # My version of pandas doesn't have .to_numpy()
        data_numpy = data[data.columns[0]]
        #depth = data.index.to_numpy()
        depth = data.index
        self.plt.gca().invert_yaxis()
        self.plt.subplots_adjust(left=0.01, right=0.50, top=0.95, bottom=0.05)
        axes_1.plot(data_numpy, depth)
        for i in range(0, num_columns):
            axes_tmp = self.plt.add_subplot(1, num_columns, i+1, sharey=axes_1)
            axes_tmp.set(xlabel=data.columns[i], ylabel='Depth', title='Depth vs ' + data.columns[i])

            #data_numpy = data[data.columns[i]].to_numpy()
            data_numpy = data[data.columns[i]]

            self.plt.gca().invert_yaxis()
            axes_tmp.plot(data_numpy, depth)
        self.canvas.draw()
        self.SetSize(self.canvas.GetSize())

class TestFrame(wx.Frame):
    def __init__(self,parent,title):
        wx.Frame.__init__(self,parent,title=title,size=(600,600))

        self.p1 = PlotPanel(self)

        #Create our own toolbar
        toolbar = self.CreateToolBar(style=wx.TB_HORIZONTAL|wx.TB_DOCKABLE|wx.TB_TEXT)
        hometool = toolbar.AddTool(wx.ID_ANY, 'Home', wx.Bitmap('/usr/share/matplotlib/mpl-data/images/home.png'))
        backtool = toolbar.AddTool(wx.ID_ANY, 'Back', wx.Bitmap('/usr/share/matplotlib/mpl-data/images/back.png'))
        fwdtool = toolbar.AddTool(wx.ID_ANY, 'Forward', wx.Bitmap('/usr/share/matplotlib/mpl-data/images/forward.png'))
        pantool = toolbar.AddTool(wx.ID_ANY, 'Pan', wx.Bitmap('/usr/share/matplotlib/mpl-data/images/move.png'))
        zoomtool = toolbar.AddTool(wx.ID_ANY, 'Zoom', wx.Bitmap('/usr/share/matplotlib/mpl-data/images/zoom_to_rect.png'))
        subtool = toolbar.AddTool(wx.ID_ANY, 'Subplots', wx.Bitmap('/usr/share/matplotlib/mpl-data/images/subplots.png'))
        savetool = toolbar.AddTool(wx.ID_ANY, 'Save', wx.Bitmap('/usr/share/matplotlib/mpl-data/images/filesave.png'))

        self.Bind(wx.EVT_TOOL, self.home, hometool)
        self.Bind(wx.EVT_TOOL, self.back, backtool)
        self.Bind(wx.EVT_TOOL, self.fwd, fwdtool)
        self.Bind(wx.EVT_TOOL, self.pan, pantool)
        self.Bind(wx.EVT_TOOL, self.zoom, zoomtool)
        self.Bind(wx.EVT_TOOL, self.sub, subtool)
        self.Bind(wx.EVT_TOOL, self.save, savetool)
        toolbar.Realize()

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.p1,1,wx.EXPAND,10)
        self.statusbar=self.CreateStatusBar()
        self.SetSizer(sizer)
        self.Show()
        self.plot()

    #Self defined Navigation Toolbar controls used to call hidden matplotlib Toolbar functions
    def home(self,event):
        self.statusbar.SetStatusText("Home")
        self.p1.toolbar.home()
        # Also scroll panel to start position
        self.p1.Scroll(0,0)

    def back(self,event):
        self.statusbar.SetStatusText("Back")
        self.p1.toolbar.back()

    def fwd(self,event):
        self.statusbar.SetStatusText("Fwd")
        self.p1.toolbar.forward()

    def pan(self,event):
        self.statusbar.SetStatusText("Pan")
        self.p1.toolbar.pan()

    def zoom(self,event):
        self.statusbar.SetStatusText("Zoom")
        self.p1.toolbar.zoom()

    def sub(self,event):
        self.statusbar.SetStatusText("Subplots")
        self.p1.toolbar.configure_subplots(event)

    def save(self,event):
        self.statusbar.SetStatusText("Save")
        self.p1.toolbar.save_figure()

    def plot(self):
        self.p1.plot()

app = wx.App(redirect=False)
frame = TestFrame(None,"Plot in Scrolled panel with replacement Navigation")
app.MainLoop()

enter image description here

Вы заметите, что я сделал замену toolbar Возможность стыковки, поэтому я могу двигатьсяtoolbar где угодно на экране.Он может быть присоединен.

enter image description here

Поскольку мы определяем нашу собственную панель инструментов, она может быть где угодно, просто посмотрите параметры wx.Toolbar.
Здесь я потерял текст и сделал его вертикальным.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...