Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question re angle wrapping #261

Closed
ea42gh opened this issue Dec 8, 2018 · 15 comments
Closed

Question re angle wrapping #261

ea42gh opened this issue Dec 8, 2018 · 15 comments

Comments

@ea42gh
Copy link
Contributor

ea42gh commented Dec 8, 2018

Should gv.Path unwrap the angles internally,
or should it be up to the user calling gv.Path?
gvpath

@philippjfr
Copy link
Member

It should handle longitude wrapping but out-of-bounds latitudes are not valid. I also doubt it will handle wrapping from paths which span more than 360 degrees in longitude properly.

@jbednar
Copy link
Member

jbednar commented Dec 8, 2018

Not sure what you mean by out of bounds latitudes; those points all seem to be between +/- 60 in latitude.

@philippjfr
Copy link
Member

Yes, I was just very confused by the plot on the left, I see now what it represents.

@ea42gh
Copy link
Contributor Author

ea42gh commented Dec 8, 2018

When you say it should handle longitude wrapping, do you intend to
modify gv.Path to remove that horizontal line?
Or is it still up to the user of hv.Path?
(Note the path in the figure is a great circle)

@philippjfr
Copy link
Member

philippjfr commented Dec 8, 2018

When you say it should handle longitude wrapping, do you intend to modify gv.Path to remove that horizontal line?

The project operation (which is called automatically) should do that for you. Could you provide the code used to generate the example? Discussing things in the abstract is rarely helpful.

@ea42gh
Copy link
Contributor Author

ea42gh commented Dec 8, 2018

lon = np.linspace(90, 360+90, 100)%360.
lat = np.linspace(-60,60, 100)
gf.coastline*gv.Path([(lon,lat)])+hv.Curve(lon)*hv.Curve(lat)

and

lon = np.linspace(0, 360, 100)
lat = np.linspace(0,180+60, 100) % 180 - 90
gf.coastline*gv.Path([(lon,lat)])+hv.Curve(lon)*hv.Curve(lat)

The problem is the branch cut: gv.Path draws connections that should not be there.
A fix would be to break the path into pieces each time we cross the boundary,
with some care taken to draw the Path to the edge of the plotted geographical area.

Nasty piece of code that calls for a utility function...

@philippjfr
Copy link
Member

philippjfr commented Dec 8, 2018

I think the problem here is simply that you are wrapping the coordinates with the modulo, if you leave off the modulo it will wrap it correctly for you:

lon = np.linspace(90, 360+90, 100)
lat = np.linspace(-60,60, 100)
gf.coastline*gv.Path([(lon,lat)])+hv.Curve(lon)*hv.Curve(lat)

bokeh_plot

@ea42gh
Copy link
Contributor Author

ea42gh commented Dec 8, 2018

It misses half the path that way

@philippjfr
Copy link
Member

Okay, I see it now. I'll have to look into what cartopy is doing there.

@ea42gh
Copy link
Contributor Author

ea42gh commented Dec 10, 2018

continuity of paths (contd) Consider the following example

class PlaneWatcher(param.Parameterized):
    step = param.Integer(0, bounds=(0,None))
    
    def __init__(self, **params ):
        self.lonlat = (np.linspace(0, 40, 5), np.linspace(-90,10, 5))
        self.proj   = crs.LambertConformal()
        #self.proj = crs.PlateCarree()
        super(PlaneWatcher,self).__init__(**params)

    @param.depends("step")
    def view_plane(self):
        self.lonlat = ((self.lonlat[0]+1+180)%360-180, (self.lonlat[1]+1 + 90)%180-90)
        h = gf.coastline*gf.ocean *\
            gv.Points( self.lonlat ).options(size=5,color='darkblue', tools=['hover'])*\
            gv.Path( [self.lonlat] ).options(color='red', projection=self.proj)
        return h.relabel('step=%d'%self.step).options( global_extent=True, width=500, height=475, projection=self.proj )
       
    def view(self):
        return hv.DynamicMap( self.view_plane )

obj = PlaneWatcher()

player = Player(length=1000, interval=10)
player.width=400
player.loop_policy = 'loop'
player.link(obj, value='step')
pn.Column(obj.view(), pn.Row(pn.Spacer(width=200),player))

If you leave this running long enough, you will also see points coming in from the lower left
from outside the projected image

@ea42gh
Copy link
Contributor Author

ea42gh commented Dec 10, 2018

bokeh_plot

@ea42gh
Copy link
Contributor Author

ea42gh commented Dec 10, 2018

Don't know what happens to the coastline with proj LambertCylindrical()
Note quite a number of the projections also unnecessarily loose axes

@philippjfr
Copy link
Member

Should be fixed by #278

lon = np.linspace(90, 360+90, 100)
lat = np.linspace(-60,60, 100)
gf.coastline*gv.Path([(lon,lat)])+hv.Curve(lon)*hv.Curve(lat)

screen shot 2019-01-14 at 2 28 08 pm

@ea42gh
Copy link
Contributor Author

ea42gh commented Jan 14, 2019

Changed the lon/lat positioning logic:
I would like to keep the line connecting the points as the motion proceeds.

class PlaneWatcher(param.Parameterized):
    step = param.Integer(0, bounds=(0,None))
    
    def __init__(self, **params ):
        self.lon       = np.linspace(0, 40, 5)
        self.lat       = np.linspace(-90,10, 5)
        self.delta_lat = np.ones(5)

        #self.proj   = crs.LambertConformal()
        self.proj = crs.PlateCarree()
        super(PlaneWatcher,self).__init__(**params)

    @param.depends("step")
    def view_plane(self):
        self.lon += 1
        self.lat += self.delta_lat
        wrap = self.lat>90
        self.delta_lat[wrap]=-1
        self.lat[wrap] = 180-self.lat[wrap]

        wrap = self.lat<-90
        self.delta_lat[wrap]=1
        self.lat[wrap] =-180-self.lat[wrap]

        h = gf.coastline*gf.ocean *\
            gv.Points( (self.lon, self.lat) ).options(size=5,color='darkblue', tools=['hover'])*\
            gv.Path( [np.stack([self.lon,self.lat],axis=1)] ).options(color='red', projection=self.proj)
        return h.relabel('step=%d'%self.step).options( global_extent=True, width=500, height=475, projection=self.proj )
       
    def view(self):
        return hv.DynamicMap( self.view_plane )

obj = PlaneWatcher()

player = Player(length=1000, interval=10)
player.width=400
player.loop_policy = 'loop'
player.link(obj, value='step')
pn.Column(obj.view(), pn.Row(pn.Spacer(width=200),player))

@philippjfr
Copy link
Member

With the small patch in #279 I get this:

anim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants