Exemple #1
0
nomposstr = '05h34m31.94s 22d00m52.2s'
header = fits.getheader(filename)
proj = wcs.Projection(header)
xc, yc = float(header['NAXIS1']) / 2., float(header['NAXIS2']) / 2.
ui.load_image(filename)
ui.notice2d('circle({0}, {1}, {2})'.format(xc, yc,
                                           float(header['NAXIS2']) / 4.))
ui.set_source(ui.gauss2d.g1 + ui.gauss2d.g2)
g1.xpos = xc
g1.ypos = yc
g2.fwhm = g1.fwhm = 3.
ui.link(g2.xpos, g1.xpos)
ui.link(g2.ypos, g1.ypos)
g2.ampl = 50.
g1.ampl = 50.
ui.guess()
ui.fit()
ui.image_fit()
ui.covar()
conf = ui.get_covar_results()
conf_dict = dict([(n, (v, l, h)) for n, v, l, h in zip(
    conf.parnames, conf.parvals, conf.parmins, conf.parmaxes)])
x, y = proj.toworld((conf_dict['g1.xpos'][0], conf_dict['g1.ypos'][0]))
xmin, ymin = proj.toworld((conf_dict['g1.xpos'][0] + conf_dict['g1.xpos'][1],
                           conf_dict['g1.ypos'][0] + conf_dict['g1.ypos'][1]))
xmax, ymax = proj.toworld((conf_dict['g1.xpos'][0] + conf_dict['g1.xpos'][2],
                           conf_dict['g1.ypos'][0] + conf_dict['g1.ypos'][2]))
nompos = positions.str2pos(nomposstr, proj)
print('{0} ({1}-{2}) vs {3}'.format(x, xmin, xmax, nompos[0][0][0]))
print('{0} ({1}-{2}) vs {3}'.format(y, ymin, ymax, nompos[0][0][1]))
Exemple #2
0
filename = 'skymap_ex.fits'
nomposstr = '05h34m31.94s 22d00m52.2s'
header = fits.getheader(filename)
proj = wcs.Projection(header)
xc, yc = float(header['NAXIS1']) / 2., float(header['NAXIS2']) / 2.
ui.load_image(filename)
ui.notice2d('circle({0}, {1}, {2})'.format(xc, yc, float(header['NAXIS2']) / 4.))
ui.set_source(ui.gauss2d.g1 + ui.gauss2d.g2)
g1.xpos = xc
g1.ypos = yc
g2.fwhm = g1.fwhm = 3.
ui.link(g2.xpos, g1.xpos)
ui.link(g2.ypos, g1.ypos)
g2.ampl = 50.
g1.ampl = 50.
ui.guess()
ui.fit()
ui.image_fit()
ui.covar()
conf = ui.get_covar_results()
conf_dict = dict([(n,(v, l, h)) for n,v,l,h in
                   zip(conf.parnames, conf.parvals, conf.parmins, conf.parmaxes)])
x, y = proj.toworld((conf_dict['g1.xpos'][0], conf_dict['g1.ypos'][0]))
xmin, ymin = proj.toworld((conf_dict['g1.xpos'][0] + conf_dict['g1.xpos'][1],
                           conf_dict['g1.ypos'][0] + conf_dict['g1.ypos'][1]))
xmax, ymax = proj.toworld((conf_dict['g1.xpos'][0] + conf_dict['g1.xpos'][2],
                           conf_dict['g1.ypos'][0] + conf_dict['g1.ypos'][2]))
nompos = positions.str2pos(nomposstr, proj)    
print('{0} ({1}-{2}) vs {3}'.format(x, xmin, xmax, nompos[0][0][0]))
print('{0} ({1}-{2}) vs {3}'.format(y, ymin, ymax, nompos[0][0][1]))
Exemple #3
0
   def __init__(self, projection, mixpix, pxlim, pylim, aspectratio=1.0,
                pos1=None, pos2=None, rulersize=None, rulerangle=None,
                x1=None, y1=None, x2=None, y2=None, lambda0=0.5, step=None,
                world=False, angle=None, addangle=0.0,
                fmt=None, fun=None, units=None, fliplabelside=False, mscale=None,
                labelsintex=True, gridmode=False, **kwargs):
      self.ptype = "Ruler"
      self.x1 = None
      self.y1 = None
      self.x2 = None
      self.y2 = None
      self.x = []
      self.y = []
      self.xw = []
      self.yw = []
      self.stepsizeW = None
      self.label = []
      self.offsets = []      # Store the offsets in degrees
      self.angle = None
      self.kwargs = {'clip_on' : True}   # clip_on is buggy for plot() in MPL versions <= 0.98.3 change later
      self.tickdx = None
      self.tickdy = None
      self.mscale = None
      self.fun = None
      self.fmt = None
      self.linekwargs = {'color' : 'k'}
      self.kwargs.update(kwargs)    # These are the kwargs for the labels
      self.aspectratio = aspectratio
      self.rulertitle = None
      self.gridmode = gridmode
      
      # Recipe:
      # Are the start and endpoint in world coordinates or pixels?
      # Convert to pixels.
      # Calculate the central position in pixels
      # Calculate the central position in world coordinates (Xw,Yw)
      # Find a lambda in (x,y) = (x1,y1) + lambda*(x2-x1,y2-x1)
      # so that, if (x,y) <-> (xw,yw), the distance D((Xw,Yw), (xw,yw))
      # is the step size on the ruler.
      def bisect(offset, lambda_s, Xw, Yw, x1, y1, x2, y2):
         """
         We are looking for a value mu so that mu+lambda_s sets a
         pixel which corresponds to world coordinates that are
         'offset' away from the start point set by lambda_s
         If lambda_s == 0 then we are in x1, x2. If lambda_s == 1
         we are in x2, y2
         """
         mes = ''
         if offset >= 0.0:
            a = 0.0; b = 1.1
         else:
            a = -1.1; b = 0.0
   
         f1 = getdistance(a, lambda_s, Xw, Yw, x1, y1, x2, y2) - abs(offset)
         f2 = getdistance(b, lambda_s, Xw, Yw, x1, y1, x2, y2) - abs(offset)
         validconditions = f1*f2 < 0.0
         if not validconditions:
            mes = "Found interval without a root for this step size"
            return  None, mes
   
         tol = 1e-12   # Tolerance. Stop iteration if (b-a)/2 < tol
         N0  = 50      # Stop output with error message if number of iterations
                        # exceeds this number
         # Initialize
         i = 0
         fa = getdistance(a, lambda_s, Xw, Yw, x1, y1, x2, y2) - abs(offset)
         # The iteration itself
         while i <= N0:
            # The bisection
            p = a + (b-a)/2.0
            fp = getdistance(p, lambda_s, Xw, Yw, x1, y1, x2, y2) - abs(offset)
            # Did we find a root?
            i += 1
            if fp == 0.0 or (b-a)/2.0 < tol:
               # print 'Root is: ', p, fp          # We found a root
               # print "Iterations: ", i
               break                         # Success..., leave the while loop
            if fa*fp > 0:
               a = p
               fa = fp
            else:
               b = p
         else:
            mes = 'Ruler bisection failed after %d iterations!' % N0
            p = None
         return p, mes
   
   
      def DV(l1, b1, l2, b2):
         # Vincenty, Thaddeus, 1975, formula for distance on sphere accurate over entire sphere
         fac = numpy.pi / 180.0
         l1 *= fac; b1 *= fac; l2 *= fac; b2 *= fac
         dlon = l2 - l1
         a1 = numpy.cos(b2)*numpy.sin(dlon)
         a2 = numpy.cos(b1)*numpy.sin(b2) - numpy.sin(b1)*numpy.cos(b2)*numpy.cos(dlon)
         a = numpy.sqrt(a1*a1+a2*a2)
         b = numpy.sin(b1)*numpy.sin(b2) + numpy.cos(b1)*numpy.cos(b2)*numpy.cos(dlon)
         d = numpy.arctan2(a,b)
         return d*180.0/numpy.pi
   
   
      def tolonlat(x, y):
         # This function also sorts the spatial values in order
         # longitude, latitude
         if mixpix == None:
            xw, yw = projection.toworld((x,y))
            xwo = xw     # Store originals
            ywo = yw
         else:
            W = projection.toworld((x, y, mixpix))
            xw = W[projection.lonaxnum-1]
            yw = W[projection.lataxnum-1]
            xwo = xw; ywo = yw
            if projection.lonaxnum > projection.lataxnum:
               xwo, ywo = ywo, xwo    # Swap
         return xw, yw, xwo, ywo
   
   
      def topixel2(xw, yw):
         # Note that this conversion is only used to convert
         # start and end position, given in world coordinates,
         # to pixels.
         if mixpix == None:
            x, y = projection.topixel((xw,yw))
         else:
            unknown = numpy.nan
            wt = (xw, yw, unknown)
            pixel = (unknown, unknown, mixpix)
            (wt, pixel) = projection.mixed(wt, pixel)
            x = pixel[0]; y = pixel[1]
         return x, y
   
   
      def getdistance(mu, lambda_s, Xw, Yw, x1, y1, x2, y2):
         lam = lambda_s + mu
         x = x1 + lam*(x2-x1)
         y = y1 + lam*(y2-y1)
         xw, yw, xw1, yw1 = tolonlat(x,y)
         return DV(Xw, Yw, xw, yw)
   
   
      def nicestep(x1, y1, x2, y2):
         # Assume positions in pixels
         xw1, yw1, dummyx, dummyy = tolonlat(x1,y1)
         xw2, yw2, dummyx, dummyy = tolonlat(x2,y2)
         step = None
         length = DV(xw1, yw1, xw2, yw2)
         # Nice numbers for dms should also be nice numbers for hms
         sec = numpy.array([30, 20, 15, 10, 5, 2, 1])
         minut = sec
         deg = numpy.array([60, 30, 20, 15, 10, 5, 2, 1])
         nicenumber = numpy.concatenate((deg*3600.0, minut*60.0, sec))
         fact = 3600.0
   
         d = length * fact
         step2 = 0.9*d/3.0          # We want at least four offsets on our ruler
         for p in nicenumber:
            k = int(step2/p)
            if k >= 1.0:
               step2 = k * p
               step = step2
               break           # Stop if we have a candidate
   
         # d = x2 - x1
         # If nothing suitable then try something else
         if step == None:
            f = int(numpy.log10(d))
            if d < 1.0:
               f -= 1
            D3 = numpy.round(d/(10.0**f),0)
            if D3 == 3.0:
               D3 = 2.0
            elif D3 == 6:
               D3 = 5.0
            elif D3 == 7:
               D3 = 8
            elif D3 == 9:
               D3 = 10
            if D3 in [2,4,8]:
               k = 4
            else:
               k = 5
            step = (D3*10.0**f)/k
         return step/fact

      spatial = projection.types[0] in ['longitude', 'latitude'] or projection.types[1] in ['longitude', 'latitude']
      if not spatial:
         raise Exception("Rulers only suitable for maps with at least one spatial axis!")

      # User entered units, then check conversion
      uf = None
      if not units is None:
         uf, errmes = unitfactor('degree', units)
         if uf is None:
            raise ValueError(errmes)
         
   
      if not pos1 is None:
         poswp = str2pos(pos1, projection, mixpix=mixpix, gridmode=self.gridmode)
         if poswp[3] != "":
            raise Exception(poswp[3])
         # The result of the position parsing of str2pos is stored in 'poswp'
         # Its second element are the returned pixel coordinates.
         # (poswp[1]).
         # Note we required 1 position. Then the pixel coordinate we want is
         # poswp[1][0]. If we omit the last index then we end up with a sequence (of 1)
         # which cannot be processed further. Finally the pixel coordinate represents a
         # position in 2-dim. So the first element represents x (poswp[1][0][0]).
         pix =  poswp[1][0]
         x1 = pix[0]
         y1 = pix[1]
      else:
         if x1 is None: x1 = pxlim[0]; world = False
         if y1 is None: y1 = pylim[0]; world = False
         if world:
            x1, y1 = topixel2(x1, y1)
   
      if not pos2 is None:
         poswp = str2pos(pos2, projection, mixpix=mixpix, gridmode=self.gridmode)
         if poswp[3] != "":
            raise Exception(poswp[3])
         pix =  poswp[1][0]
         x2 = pix[0]
         y2 = pix[1]
      else:
         if not rulersize is None:
            # We have two pixels to start with. Convert to long, lat
            # which serves as a starting point for the ruler.
            lon1, lat1, xwo1, ywo1 = tolonlat(x1, y1)
            swapped = lon1 != xwo1
            # Find second point in world coordinates
            if rulerangle is None:
               rulerangle = 270.0
            if not uf is None:
               rulersize /= uf
            # Find end point. Assume cdelt of long. is negative
            lon2, lat2 = dispcoord(lon1, lat1, rulersize, -1, rulerangle)
            if swapped:
               x2 = lat2
               y2 = lon2  # Swap back
            else:
               x2 = lon2
               y2 = lat2
            x2, y2 = topixel2(x2, y2)            
         else:
            if x2 is None: x2 = pxlim[1]; world = False
            if y2 is None: y2 = pylim[1]; world = False
            if world:
               x2, y2 = topixel2(x2, y2)
      
      #print "DV", DV(23*15,15, 22*15, 30)*60.0
   
      # Get a step size for nice offsets
      if step is None:
         stepsizeW = nicestep(x1, y1, x2, y2)
      else:
         stepsizeW = step
      if step == 0.0:
         raise Exception("Cannot make ruler with step size equal to zero!")
   
   
      # Look for suitable units (degrees, arcmin, arcsec) if nothing is
      # specified in the call. Note that 'stepsizeW' is in degrees.
      uf = None

      if units != None:
         uf, errmes = unitfactor('degree', units)
         if uf is None:
            raise ValueError(errmes)
         if uf != 1.0:
            fun = lambda x: x*uf
            # Input in 'units' but must be degrees for further processing
            if not step is None:   
               stepsizeW /= uf  # because step was in units of 'units'. Must be deg.
         if fmt is None:
            if uf == 1.0:
               if labelsintex:
                  fmt = r"%4.0f^{\circ}"
               else:
                  fmt = "%4.0f\u00B0"
            elif uf == 60.0:
               # Write labels in arcmin
               if labelsintex:
                  fmt = r"%4.0f^{\prime}"
               else:
                  fmt = r"%4.0f'"
            elif uf == 3600.0:
               # Write labels in arcsec
               if labelsintex:
                  fmt = r"%4.0f^{\prime\prime}"
               else:
                  fmt = r"%4.0f''"
            else:
               raise ValueError("Only degree, arcmin and arcsec allowed")

      if fun is None and fmt is None:
            if labelsintex:
               fmt = r"%4.0f^{\circ}"
            else:
               fmt = "%4.0f\u00B0"
            if abs(stepsizeW) < 1.0:
               # Write labels in arcmin
               fun = lambda x: x*60.0
               if labelsintex:
                  fmt = r"%4.0f^{\prime}"
               else:
                  fmt = r"%4.0f'"
            if abs(stepsizeW) < 1.0/60.0:
               # Write labels in arcsec
               fun = lambda x: x*3600.0
               if labelsintex:
                  fmt = r"%4.0f^{\prime\prime}"
               else:
                  fmt = r"%4.0f''"
      elif fmt is None:          # A function but not a format. Then a default format
         fmt = '%g'
      # Check whether the start- and end point of the ruler are inside the frame
      start_in = isinside(x1, y1, pxlim, pylim)
      #start_in = (pxlim[0]-0.5 <= x1 <= pxlim[1]+0.5) and (pylim[0]-0.5 <= y1 <= pylim[1]+0.5)
      if not start_in:
         raise Exception("Start point of ruler not in pixel limits!")

      end_in = isinside(x2, y2, pxlim, pylim)
      #end_in = (pxlim[0]-0.5 <= x2 <= pxlim[1]+0.5) and (pylim[0]-0.5 <= y2 <= pylim[1]+0.5)
      if not end_in:
         raise Exception("End point of ruler not in pixel limits!")
   
      # Ticks perpendicular to ruler line. Prependicular is with respect to
      # square pixels, so correct these first for their aspect ratio to find
      # the right angle.
      defangle = 180.0 * numpy.arctan2(y2-y1, (x2-x1)/aspectratio) / numpy.pi - 90.0
   
      l1 = pxlim[1] - pxlim[0] + 1.0; l1 /= 100.0
      l2 = pylim[1] - pylim[0] + 1.0; l2 /= 100.0
      ll = max(l1,l2)
      dx = ll*numpy.cos(defangle*numpy.pi/180.0)*aspectratio
      dy = ll*numpy.sin(defangle*numpy.pi/180.0)
      if fliplabelside:
         dx = -dx
         dy = -dy
   
      if angle == None:
         phi = defangle
      else:
         phi = angle
      phi += addangle
      defkwargs = {'fontsize':10, 'rotation':phi}
      if defangle+90.0 in [270.0, 90.0, -90.0, -270.0]:
         if fliplabelside:
            defkwargs.update({'va':'center', 'ha':'right'})
         else:
            defkwargs.update({'va':'center', 'ha':'left'})
         if mscale == None:
            mscale = 1.5
      elif defangle+90.0 in [0.0, 180.0, -180.0]:
         if fliplabelside:
            defkwargs.update({'va':'bottom', 'ha':'center'})
         else:
            defkwargs.update({'va':'top', 'ha':'center'})
         mscale = 1.5
      else:
         defkwargs.update({'va':'center', 'ha':'center'})
         if mscale == None:
            mscale = 2.5
      defkwargs.update(kwargs)
      #ruler = Rulerstick(x1, y1, x2, y2, defangle, dx, dy, mscale, **defkwargs)
      self.x1 = x1; self.x2 = x2; self.y1 = y1; self.y2 = y2
      self.angle = defangle
      self.tickdx = dx; self.tickdy = dy
      self.mscale = mscale
      self.kwargs.update(defkwargs) 
      self.fmt = fmt
      self.fun = fun
      self.flip = fliplabelside
   
      lambda_s = lambda0
      x0 = x1 + lambda_s*(x2-x1)
      y0 = y1 + lambda_s*(y2-y1)
      Xw, Yw, xw1, yw1 = tolonlat(x0, y0)
      self.append(x0, y0, 0.0, fmt%0.0)
      self.appendW(xw1, yw1)         # Store in original order i.e. not sorted
      self.stepsizeW = stepsizeW     # Needed elsewhere so store as an attribute

      
      # Find the mu on the straight ruler line for which the distance between
      # the position defined by mu and the center point (lambda0) is 'offset'
      # Note that these distances are calculated on a sphere
      for sign in [+1.0, -1.0]:
         mu = 0.0
         offset = 0.0
         lamplusmu = lambda_s + mu
         while mu != None and (0.0 <= lamplusmu <= 1.0):
            offset += sign*stepsizeW
            mu, mes = bisect(offset, lambda_s, Xw, Yw, x1, y1, x2, y2)
            if mu != None:
               lamplusmu = lambda_s + mu
               if 0.0 <= lamplusmu <= 1.0:
                  x = x1 + (lamplusmu)*(x2-x1)
                  y = y1 + (lamplusmu)*(y2-y1)
                  if fun != None:                     
                     off = fun(offset)
                  else:
                     off = abs(offset)
                  self.append(x, y, offset, fmt%off, labelsintex)
                  xw, yw, xw1, yw1 = tolonlat(x, y)
                  self.appendW(xw1, yw1)
            elif sign == -1.0:
               break
               # raise Exception, mes
      self.pxlim = pxlim
      self.pylim = pylim