Search code examples
python-3.xwxpython

Showing value of pixel from NetCDF in another panel using matplotlib and wxpython?


I have questions about code when I plot figure with imshow matplotlib I have a plot with x y and z= value of pixel like picture :

code :

import netCDF4
    import numpy as np
    import matplotlib
    import matplotlib.pyplot as plt


    path = 'D/data/'

    fic = 'air.departure.sig995.2012.nc'

    nc = netCDF4.Dataset(path+fic,'r')
    var = nc.variables.keys()

    lats = nc.variables['lat'][:]  # extract/copy the data
    lons = nc.variables['lon'][:]
    air_dep = nc.variables['air_dep'][:,:,:]
    air_dep = air_dep[0,:,:]  


    plt.imshow(air_dep)
    plt.show()

I have an app with wxpython I can show in other panel the cordinates cursor x y but I need to show the value of pixel z how can I do that?

This is the code for application:

import wx
import numpy as np
import netCDF4
from netCDF4 import Dataset
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.patches as patches
import matplotlib

class Window(wx.Frame):
    """ Fenêtre principale de l'application """

    def __init__(self, **kwargs):
        super().__init__(None, **kwargs)
        RootPanel(self)

class RootPanel(wx.Panel):
    """ Panel contenant tous les autres widgets de l'application """

    def __init__(self, parent):
        super().__init__(parent)

        panel_buttons = wx.Panel(self)
        panel_buttons_sizer = wx.GridSizer(1, 2, 0, 0)

        self.canvas_panel = CanvasPanel(self)
        self.panel_two = PanelTwo(parent=self)

        select_button = PickButton(
            panel_buttons,
            "netCDF4 files (nc)|*.nc",
            self.canvas_panel.load_from_file,
            label="Show on this window (nc)",
        )
        toplevel_select_button = TopLevelPickButton(
            panel_buttons,
            "Text files (txt)|*.txt|All files|*.*",
            label="Show on separate window (txt)",
        )
        panel_buttons_sizer.Add(select_button)
        panel_buttons_sizer.Add(toplevel_select_button)
        panel_buttons.SetSizer(panel_buttons_sizer)

        canvas_sizer = wx.BoxSizer(wx.HORIZONTAL)
        canvas_sizer.Add(self.canvas_panel,1,wx.EXPAND)
        canvas_sizer.Add(self.panel_two,1,wx.EXPAND)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(panel_buttons)
        sizer.Add(canvas_sizer)
        self.SetSizerAndFit(sizer)
        self.Show()

class PickButton(wx.Button):
    """ Bouton permettant de choisir un fichier """

    def __init__(self, parent, wildcard, func, **kwargs):
        # func est la méthode à laquelle devra être foruni le fichier sélectionné
        super().__init__(parent, **kwargs)
        self.wildcard = wildcard
        self.func = func
        self.Bind(wx.EVT_BUTTON, self.pick_file)

    def pick_file(self, evt):
        style = style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE
        with wx.FileDialog(
            self, "Pick files", wildcard=self.wildcard, style=style
        ) as fileDialog:
            if fileDialog.ShowModal() != wx.ID_CANCEL:
                chosen_file = fileDialog.GetPath()
                self.func(chosen_file)

class TopLevelPickButton(PickButton):
    """ Permet de choisir un fichier et d'ouvrir une toplevel """

    def __init__(self, parent, wildcard, **kwargs):
        super().__init__(parent, wildcard, self.create_toplevel, **kwargs)

    def create_toplevel(self, file_name):
        """ Ouvre une toplevel et affiche le graphique """
        self.win = TopLevelCanvas(self.Parent)
        self.win.canvas_panel.load_from_file(file_name)
        self.win.Show()

class CanvasPanel(wx.Panel):
    """ Panel du graphique matplotlib """
    def __init__(self, parent , size=(200,250)):
        super().__init__(parent)
        self.figure = Figure(figsize =(5,5))
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.Size = self.canvas.Size
        self.parent = parent

    def load_from_file(self, file_name):
        """
        Méthode effectuant l'intermédiaire pour charger le fichier selon
        son type
        """
        self.axes = self.figure.add_subplot(111)
        if file_name.endswith(".nc"):
            self._load_nc(file_name)
        else:
            self._load_txt(file_name)
        self.canvas.draw()

    def _load_txt(self, file_name):
        self._load_nc(file_name)

    def _load_nc(self, file_name):
        """ Simule le chargement et affichage à partir d'un fichier nc """
        fic='air.departure.sig995.2012.nc'

        path='D:/data/'


        nc = netCDF4.Dataset(path+fic,'r')
        lons = nc.variables['lon'][:]
        lats = nc.variables['lat'][:]
        air_dep = nc.variables['air_dep'][:,:,:]
        air_dep = air_dep[0,:,:]


        self.axes.imshow(air_dep)

        self.canvas.mpl_connect('button_press_event', self.on_press)
        x = y = 1
        self.rect = patches.Rectangle((x, y), 5,5,edgecolor='r', alpha=1, fill=None, label='Label')
        self.axes.add_patch(self.rect)
        self.axes.plot()
        self.Show()

    def on_press(self, click):
        x1, y1 = click.xdata, click.ydata
        self.parent.panel_two.Update(x1,y1)
        zx1 = x1 - 2.5
        zy1 = y1 - 2.5
        zx2 = x1 + 2.5
        zy2 = y1 + 2.5
        self.rect.set_x(x1 - 2.5) #Move the rectangle and centre it on the X click point
        self.rect.set_y(y1 - 2.5) #Move the rectangle and centre it on the Y click point


        self.axes.plot()
        self.canvas.draw()



class PanelTwo(wx.Panel): #here when i need to visualize pixel and coordinator cursor
    def __init__(self,parent):
        wx.Panel.__init__(self,parent,size=(300,250))

        self.text_ctrl = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.BORDER_SUNKEN|wx.TE_READONLY|wx.TE_RICH2, size=(200,170))

        lbl = wx.StaticText(self,label="Coordinato cursor & Pixel ")
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(lbl,0, wx.ALIGN_CENTRE,10)
        sizer.Add(self.text_ctrl,0, wx.ALIGN_CENTRE,10)
        self.SetSizer(sizer)

    def Update(self,x1,y1):
        self.text_ctrl.SetValue("Mouse click at;\nX "+str(x1)+"\nY "+str(y1))



class TopLevelCanvas(wx.Frame):
    """ Fenêtre affichant uniquement un graph matplotlib """

    def __init__(self, parent, **kwargs):
        super().__init__(parent, **kwargs)
        self.canvas_panel = CanvasPanel(self)
        self.zoom_panel = Zoom(parent=self)
        self.Size = self.canvas_panel.Size
        canvas_sizer = wx.BoxSizer(wx.HORIZONTAL)
        canvas_sizer.Add(self.canvas_panel,1,wx.EXPAND)
        canvas_sizer.Add(self.zoom_panel,1,wx.EXPAND)
        self.SetSizerAndFit(canvas_sizer)
        self.Show()

class App(wx.App):
    def OnInit(self):
        win = Window(title="A test dialog", size=(1000, 800))
        win.Show()
        return True

if __name__ == "__main__":
    app = App()
    app.MainLoop()

How can I show the value of pixel in the paneltwo like x y coordinates? AND ALL VALUES OF AIR_DEP IN WINDOWS 5X5 like this example : IR_108 is other variables value

enter image description here

thank you


Solution

  • When you say "pixel z" do you mean the air_dep value?

    import wx
    import numpy as np
    import netCDF4
    from netCDF4 import Dataset
    from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
    from matplotlib.figure import Figure
    import matplotlib.patches as patches
    import matplotlib
    
    class Window(wx.Frame):
        """ Fenêtre principale de l'application """
    
        def __init__(self, **kwargs):
            super().__init__(None, **kwargs)
            RootPanel(self)
    
    class RootPanel(wx.Panel):
        """ Panel contenant tous les autres widgets de l'application """
    
        def __init__(self, parent):
            super().__init__(parent)
    
            panel_buttons = wx.Panel(self)
            panel_buttons_sizer = wx.GridSizer(1, 2, 0, 0)
    
            self.canvas_panel = CanvasPanel(self)
            self.panel_two = PanelTwo(parent=self)
    
            select_button = PickButton(
                panel_buttons,
                "netCDF4 files (nc)|*.nc",
                self.canvas_panel.load_from_file,
                label="Show on this window (nc)",
            )
            toplevel_select_button = TopLevelPickButton(
                panel_buttons,
                "Text files (txt)|*.txt|All files|*.*",
                label="Show on separate window (txt)",
            )
            panel_buttons_sizer.Add(select_button)
            panel_buttons_sizer.Add(toplevel_select_button)
            panel_buttons.SetSizer(panel_buttons_sizer)
    
            canvas_sizer = wx.BoxSizer(wx.HORIZONTAL)
            canvas_sizer.Add(self.canvas_panel,1,wx.EXPAND)
            canvas_sizer.Add(self.panel_two,1,wx.EXPAND)
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(panel_buttons)
            sizer.Add(canvas_sizer)
            self.SetSizerAndFit(sizer)
            self.Show()
    
    class PickButton(wx.Button):
        """ Bouton permettant de choisir un fichier """
    
        def __init__(self, parent, wildcard, func, **kwargs):
            # func est la méthode à laquelle devra être foruni le fichier sélectionné
            super().__init__(parent, **kwargs)
            self.wildcard = wildcard
            self.func = func
            self.Bind(wx.EVT_BUTTON, self.pick_file)
    
        def pick_file(self, evt):
            style = style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE
            with wx.FileDialog(
                self, "Pick files", wildcard=self.wildcard, style=style
            ) as fileDialog:
                if fileDialog.ShowModal() != wx.ID_CANCEL:
                    chosen_file = fileDialog.GetPath()
                    self.func(chosen_file)
    
    class TopLevelPickButton(PickButton):
        """ Permet de choisir un fichier et d'ouvrir une toplevel """
    
        def __init__(self, parent, wildcard, **kwargs):
            super().__init__(parent, wildcard, self.create_toplevel, **kwargs)
    
        def create_toplevel(self, file_name):
            """ Ouvre une toplevel et affiche le graphique """
            self.win = TopLevelCanvas(self.Parent)
            self.win.canvas_panel.load_from_file(file_name)
            self.win.Show()
    
    class CanvasPanel(wx.Panel):
        """ Panel du graphique matplotlib """
        def __init__(self, parent , size=(200,250)):
            super().__init__(parent)
            self.figure = Figure(figsize =(5,3))
            self.canvas = FigureCanvas(self, -1, self.figure)
            self.Size = self.canvas.Size
            self.parent = parent
    
        def load_from_file(self, file_name):
            """
            Méthode effectuant l'intermédiaire pour charger le fichier selon
            son type
            """
            self.axes = self.figure.add_subplot(111)
            if file_name.endswith(".nc"):
                self._load_nc(file_name)
            else:
                self._load_txt(file_name)
            self.canvas.draw()
    
        def _load_txt(self, file_name):
            self._load_nc(file_name)
    
        def _load_nc(self, file_name):
            """ Simule le chargement et affichage à partir d'un fichier nc """
            fic='air.departure.sig995.2012.nc'
    
            #path='/home/data/'
            path=''
    
    
            nc = netCDF4.Dataset(path+fic,'r')
            self.lons = nc.variables['lon'][:]
            self.lats = nc.variables['lat'][:]
            air_dep = nc.variables['air_dep'][:,:,:]
            self.air_dep = air_dep[0,:,:]
    
            self.axes.imshow(self.air_dep)
    
            self.canvas.mpl_connect('button_press_event', self.on_press)
            x = y = 1
            self.rect = patches.Rectangle((x, y), 5,5,edgecolor='r', alpha=1, fill=None, label='Label')
            self.axes.add_patch(self.rect)
            self.axes.plot()
    
        def float_to_dms(self,f):
            # convert to seconds
            f = f * 3600
            if f < 0:
                div1 = -3600
                div2 = -1
            else:
                div1 = 3600
                div2 = 1
            #Degrees,minutes,seconds
            d,m = divmod(f,div1)
            m,s = divmod(m*60,div1)
            s, x = divmod(s*60,div1)
    
            d,x = divmod(d,div2)
            m,x = divmod(m,1)
            s,x = divmod(s,1)
    
            return ("\n\t"+str(int(d))+"° "+str(int(m)).zfill(2)+"' "+str(int(s)).zfill(2)+'"\n')
    
        def on_press(self, click):
            x1, y1 = click.xdata, click.ydata
            #Longititude values are 2.5 degrees apart for this data
            lon = x1*2.5
            #Latitude values from 90 to -90 2.5 degrees apart
            #split the y value
            i,f = divmod(y1,1)
            lat = self.lats[int(i)]
            #calculate the fraction of degrees
            if lat > 0 and lat < 87.5:
                lat = lat+(f*2.5)
            elif lat < 0 and lat > -87.5:
                lat = lat-(f*2.5)
            #Convert to ° ' "
            lon_dms = self.float_to_dms(lon)
            lat_dms = self.float_to_dms(lat)
    
            #air_dep seems the wrong way round but what do I know
            #The way below gives values that seem correct
            air = self.air_dep[int(y1),int(x1)]
            self.parent.panel_two.Update(x1,y1,lon,lat,air,lon_dms,lat_dms)
            zx1 = x1 - 2.5
            zy1 = y1 - 2.5
            zx2 = x1 + 2.5
            zy2 = y1 + 2.5
            self.rect.set_x(x1 - 2.5) #Move the rectangle and centre it on the X click point
            self.rect.set_y(y1 - 2.5) #Move the rectangle and centre it on the Y click point
    
    
            self.axes.plot()
            self.canvas.draw()
    
    
    
    class PanelTwo(wx.Panel): #here when i need to visualize pixel and coordinator cursor
        def __init__(self,parent):
            wx.Panel.__init__(self,parent,size=(300,250))
    
            self.text_ctrl = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.BORDER_SUNKEN|wx.TE_READONLY|wx.TE_RICH2, size=(200,200))
    
            lbl = wx.StaticText(self,label="Coordinato cursor & Pixel ")
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(lbl,0, wx.ALIGN_CENTRE,10)
            sizer.Add(self.text_ctrl,0, wx.ALIGN_CENTRE,10)
            self.SetSizer(sizer)
    
        def Update(self,x1,y1,lon,lat,air,lon_dms,lat_dms):
            update_str = "Mouse click at;\nX "+str(x1)+"\nLon "+str(lon)+"\n"+lon_dms+"\nY "+str(y1)+"\nLat "+str(lat)+"\n"+lat_dms+"\nAir Value "+str(air)
            self.text_ctrl.SetValue(update_str)
    
    
    
    class TopLevelCanvas(wx.Frame):
        """ Fenêtre affichant uniquement un graph matplotlib """
    
        def __init__(self, parent, **kwargs):
            super().__init__(parent, **kwargs)
            self.canvas_panel = CanvasPanel(self)
            self.zoom_panel = Zoom(parent=self)
            self.Size = self.canvas_panel.Size
            canvas_sizer = wx.BoxSizer(wx.HORIZONTAL)
            canvas_sizer.Add(self.canvas_panel,1,wx.EXPAND)
            canvas_sizer.Add(self.zoom_panel,1,wx.EXPAND)
            self.SetSizerAndFit(canvas_sizer)
            self.Show()
    
    class App(wx.App):
        def OnInit(self):
            win = Window(title="A test dialog", size=(1000, 800))
            win.Show()
            return True
    
    if __name__ == "__main__":
        app = App()
        app.MainLoop()
    

    enter image description here