Home > database >  How to scale matplotlib meshridge for axes.pcolormesh to match plot data
How to scale matplotlib meshridge for axes.pcolormesh to match plot data

Time:02-23

I am trying to add a pcolormesh to a simple line plot in wxmplot and cannot get its scale to match the plot data axis.

The pcolormesh grid wants to conform to its own limits, and match those to the plot data.

In the test program (adopted from wxmplot example stripchart.py), the generated data is a sin wave with small random numbers added that has a range of about /- 1.5. Adding the pcolormesh to that and we see only the bottom few rows (i.e. one or two integer rows) and nothing below zero.

If I multiple the Y data by 10, then I start to be able to see a more complete pcolormesh.

I have tried various variations of different values for the meshgrid, norm and transfer parameters. This is the most stable version, but I can't find the right parameters to change to get the pcolormesh to conform to the plotted data's Y axis, and to use its full range of colours for the available Y axis, including negative values.

Suggestions would be very welcome! Thanks.

Sample plot with normal range. Plot Data multiple *1

Sample plot with y*10.

Plot Data multiple *10

#!/usr/bin/python
import time
import numpy as np
import sys
import wx
from wx.lib import masked
from floatcontrol import FloatCtrl
from wxmplot import PlotPanel

# Set the YMULTIPLER=1 to see the only the bottom two rows of the pcolormesh.
# Set the YMULTIPLER=10 to see the only the a more complete mesh.

# N.B. The pcolormesh does not get shown for any portion of the plot below zero.

#YMULTIPLIER=1
YMULTIPLIER=10

def next_data():
    "simulated data"
    t0 = time.time()
    lt = time.localtime(t0)
    tmin, tsec = lt[4],lt[5]
    u = np.random.random()
    v = np.random.random()
    x = np.sin( (u   tsec)/3.0)   tmin/30.   v/5.0
    return t0, x

class StripChartFrame(wx.Frame):
    def __init__(self, parent, ID, **kws):
        kws["style"] = wx.DEFAULT_FRAME_STYLE|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL

        wx.Frame.__init__(self, parent, ID, '',
                         wx.DefaultPosition, wx.Size(-1,-1), **kws)
        self.SetTitle("wxmplot StripChart Demo")

        self.tmin = 15.0

        self.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.BOLD,False))
        menu = wx.Menu()
        menu_exit = menu.Append(-1, "E&xit", "Terminate the program")

        menuBar = wx.MenuBar()
        menuBar.Append(menu, "&File");
        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU,  self.OnExit, menu_exit)
        self.Bind(wx.EVT_CLOSE, self.OnExit)

        sbar = self.CreateStatusBar(2,wx.CAPTION)
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(11)
        sbar.SetFont(sfont)
        self.SetStatusWidths([-3,-1])
        self.SetStatusText('',0)

        mainsizer = wx.BoxSizer(wx.VERTICAL)

        btnpanel = wx.Panel(self, -1)
        btnsizer = wx.BoxSizer(wx.HORIZONTAL)

        b_on  = wx.Button(btnpanel, -1, 'Start',   size=(-1,-1))
        b_off = wx.Button(btnpanel, -1, 'Stop',    size=(-1,-1))

        b_on.Bind(wx.EVT_BUTTON, self.onStartTimer)
        b_off.Bind(wx.EVT_BUTTON, self.onStopTimer)

        tlabel = wx.StaticText(btnpanel, -1, '  Time range:')
        self.time_range = FloatCtrl(btnpanel,  size=(100, -1), value=abs(self.tmin), precision=1)

        btnsizer.Add(b_on,   0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)
        btnsizer.Add(b_off,  0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)
        btnsizer.Add(tlabel, 1, wx.GROW|wx.ALL|wx.ALIGN_LEFT|wx.LEFT, 0)
        btnsizer.Add(self.time_range, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0)

        btnpanel.SetSizer(btnsizer)
        btnsizer.Fit(btnpanel)

        self.plotpanel = PlotPanel(self, messenger=self.write_message)
        self.plotpanel.BuildPanel()
        self.plotpanel.set_xlabel('Time from Present (s)')
        mainsizer.Add(btnpanel, 0,  wx.GROW|wx.ALIGN_LEFT|wx.LEFT, 0)
        mainsizer.Add(self.plotpanel, 1, wx.GROW|wx.ALL|wx.ALIGN_LEFT|wx.LEFT, 0)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer = wx.Timer(self)
        self.count = 0
        self.Refresh()
        self.SetSize(self.GetBestVirtualSize())

        axes = self.plotpanel.axes
        axis = axes.xaxis


        wx.CallAfter(self.onStartTimer)

    def write_message(self, msg, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(msg, panel)


   def onStartTimer(self,event=None):
        self.count    = 0
        t0,y0 = next_data()
        y0 *= YMULTIPLIER
        self.ylist = [y0]
        self.tlist = [t0]
        self.tmin_last = -10000
        self.time0    = time.time()
        self.timer.Start(50)

    def onStopTimer(self,event=None):
        self.timer.Stop()

    def onTimer(self, event):
        self.count  = 1
        etime = time.time() - self.time0
        self.tmin = float(self.time_range.GetValue())
        t1, y1 = next_data()
        y1 *= YMULTIPLIER
        self.tlist.append(t1)
        self.ylist.append(y1)
        if len(self.tlist) > 200:
                del self.tlist[0]
                del self.ylist[0]
        tdat = np.array(self.tlist) - self.time0
        mask = np.where(tdat > -abs(self.tmin))
        ydat = np.array(self.ylist)

        n = len(self.ylist)
        if n <= 2:
            self.plotpanel.plot(tdat, ydat)
        else:
            self.plotpanel.update_line(0, tdat, ydat, draw=False)
            self.write_message("update  %i points in %8.4f s" % (n,etime))

        lims = self.plotpanel.get_viewlimits()
        try:
            ymin, ymax = ydat[mask].min(), ydat[mask].max()
        except:
            ymin, ymax = ydat.min(), ydat.max()
        yrange = abs(ymax-ymin)
        ymin -= yrange*0.05
        ymax  = yrange*0.05
        if (ymin < lims[2] or ymax >  lims[3] ):
            self.plotpanel.set_xylims((-self.tmin, 0, ymin, ymax))
            self.plotpanel.plot(tdat, ydat)


        xmin, xmax = tdat.min(), tdat.max()
        X, Y = np.meshgrid(np.linspace(xmin, xmax, num=len(tdat)), np.linspace(ymin, ymax, num=int(ymax-ymin)))
        axes = self.plotpanel.axes
        axes.pcolormesh(Y, cmap="RdYlGn", alpha=0.2, edgecolors='gray')
        self.plotpanel.draw()

    def OnAbout(self, event):
        dlg = wx.MessageDialog(self, "wxmplot example: stripchart app",
                              "About WXMPlot test", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def OnExit(self, event):
        self.Destroy()

app = wx.App()
f = StripChartFrame(None,-1)
f.Show(True)
app.MainLoop()



CodePudding user response:

Additional screenshots for using pcolormesh with X,Y,Y

This changes the behaviour in two ways. First, it now does map to negative Y values. Second, the X bins are much smaller, i.e. less than one.

        xmin, xmax = tdat.min(), tdat.max()
        X, Y = np.meshgrid(np.linspace(xmin, xmax, num=len(tdat) 1), np.linspace(ymin, ymax, num=int(ymax-ymin) 1))
        axes = self.plotpanel.axes
        axes.pcolormesh(X, Y, Y, cmap="RdYlGn", alpha=0.2, edgecolors='gray')
        self.plotpanel.draw()

YMULTIPIER 1 enter image description here

YMULTIPLER 10 enter image description here

CodePudding user response:

Thanks, that does help with the X sizing.

But Y scaling still off.

        xmin, xmax = tdat.min(), tdat.max()
        #X, Y = np.meshgrid(np.linspace(xmin, xmax, num=len(tdat) 1), np.linspace(ymin, ymax, num=int(ymax-ymin) 1))
        X, Y = np.meshgrid(np.linspace(xmin, xmax, num=2), np.linspace(ymin, ymax, num=int(ymax-ymin) 1))
        axes = self.plotpanel.axes
        axes.pcolormesh(X, Y, Y, cmap="RdYlGn", alpha=0.2, edgecolors='gray')
        self.plotpanel.draw()

Y MULTIPLIER 1 enter image description here

Y MULTIPLIER 10 enter image description here

  • Related