示例#1
0
def nice_levels(data, approx_nlev=10, max_nlev=28):
    """Compute a vector of "levels" at "nice" increments.

    Returns a 1-D array of "levels" (e.g., contour levels) calculated
    to give an aesthetically pleasing and human-readable interval,
    if possible.  If not, returns levels for approx_nlev levels
    between the maximum and minimum of data.  In any event, the
    function will return no more than max_nlev levels.

    Keyword Input Parameter:
    * data:  Array of values to calculate levels for.  Can be of any 
      size and shape.

    Keyword Input Parameter:
    * approx_nlev:  Integer referring to approximately how many
      levels to return.  This is the way of adjusting how "coarse"
      or "fine" to make the vector of levels.

    * max_nlev:  The maximum number of levels the function will
      permit to be returned.  The interval of levels will be adjusted
      to keep the number of levels returned under this value.  If
      approx_nlev is chosen to be greater than or equal to max_nlev,
      an exception is raised.

    Output:
    * This function returns a 1-D array of contour levels.

    Function is adaptation of parts of IDL routine contour_plot.pro
    by Johnny Lin.  This is why the capitalization conventions of
    Python are not strictly followed in this function.

    Examples:
    >>> z = N.array([-24.5, 50.3, 183.1, 20.])
    >>> out = nice_levels(z)
    >>> ['%g' % out[i] for i in range(len(out))]
    ['-30', '0', '30', '60', '90', '120', '150', '180', '210']

    >>> z = N.array([-24.5, 50.3, 183.1, 20.])
    >>> out = nice_levels(z, approx_nlev=5)
    >>> ['%g' % out[i] for i in range(len(out))]
    ['-50', '0', '50', '100', '150', '200']

    >>> z = N.array([-24.5, 50.3, 183.1, 20.])
    >>> out = nice_levels(z, approx_nlev=10)
    >>> ['%g' % out[i] for i in range(len(out))]
    ['-30', '0', '30', '60', '90', '120', '150', '180', '210']
    """
    #- Default settings and error check:

    if approx_nlev >= max_nlev:
        raise ValueError, 'max_nlev is too small'

    MAX_zd_ok = N.max(data)
    MIN_zd_ok = N.min(data)

    nlevels = N.min([approx_nlev, max_nlev])
    tmpcmax = MAX_zd_ok
    tmpcmin = MIN_zd_ok
    tmpcint = N.abs((tmpcmax - tmpcmin) / float(nlevels))

    #- See if the cint can be "even".  If not, return alternative
    #  contour levels vector:

    #+ Guess a possible cint.  Look for an "even" value that is
    #  closest to that:

    guesscint = N.abs((MAX_zd_ok - MIN_zd_ok) / float(nlevels))

    if (guesscint > 1e-10) and (guesscint < 1e+10):
        possiblecint = [
            1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 0.0001, 0.0002, 0.0005, 0.001,
            0.002, 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1., 2., 5., 10.,
            20., 30., 45., 50., 100., 200., 500., 1000., 2000., 5000., 10000.,
            20000., 50000., 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10
        ]

        diffcint = N.abs(possiblecint - guesscint)
        tempcint = N.compress(diffcint == N.min(diffcint), possiblecint)[0]
        tcidx = N.compress(where_close(possiblecint, tempcint),
                           N.arange(N.size(possiblecint)))[0]

        #+ Look around at the "even" values nearby the possible option
        #  for cint.  Calculate how many contours each of those cints
        #  would give.  Dictionary ncon_count is the number of
        #  contours for a given test cint.  test_tcidxs are the indices
        #  in possiblecint to examine in detail; these index values
        #  will be the keys in ncon_count.

        if tcidx == 0: tcidx = 1
        if tcidx == N.size(possiblecint) - 1: tcidx = N.size(possiblecint) - 2

        ncon_count = {}
        test_tcidxs = [tcidx - 1, tcidx, tcidx + 1]
        for i in test_tcidxs:
            itcval = possiblecint[i]
            positivecon = N.arange(max_nlev + 2, dtype=float) * itcval
            negativecon = (N.arange(max_nlev + 2, dtype=float) +
                           1.0) * itcval * (-1.0)
            if (MAX_zd_ok + itcval >= 0) and (MIN_zd_ok - itcval >= 0):
                ncon_count[i] = N.sum( \
                    N.logical_and(positivecon <= MAX_zd_ok + itcval,
                                  positivecon >= MIN_zd_ok - itcval) )
            elif (MAX_zd_ok + itcval < 0) and (MIN_zd_ok - itcval < 0):
                ncon_count[i] = N.sum( \
                    N.logical_and(negativecon <= MAX_zd_ok + itcval,
                                  negativecon >= MIN_zd_ok - itcval) )
            else:
                ncon_count[i] = N.sum(positivecon <= MAX_zd_ok + itcval) \
                              + N.sum(negativecon >= MIN_zd_ok - itcval)

#+ Select the cint that has the fewest levels if it has at
#  least nlevels-1.  Otherwise, try to find the next cint with
#  the fewest levels that is below max_nlev.  tempcint is what
#  you get (changed, if warranted) leaving this section:

        min_ncon_count = N.min(ncon_count.values())
        current_best_count = max_nlev
        for i in test_tcidxs:
            if (ncon_count[i] == min_ncon_count) and \
               (ncon_count[i] >= nlevels-1):
                tempcint = possiblecint[i]
                current_best_count = ncon_count[i]
                break
            elif (ncon_count[i] == min_ncon_count) and \
               (ncon_count[i] < nlevels-1):
                continue
            elif ncon_count[i] > max_nlev:
                continue
            else:
                if N.abs(ncon_count[i]-nlevels) < \
                   N.abs(current_best_count-nlevels):
                    tempcint = possiblecint[i]
                    current_best_count = ncon_count[i]
                continue

#+ Create levels for case with neg. and pos. contours.  There
#  is the case of all pos., all neg., and mixed pos. and neg.
#  contours:

        positivecon = N.arange(max_nlev + 2, dtype=float) * tempcint
        negativecon = (N.arange(max_nlev + 2, dtype=float) +
                       1.0) * tempcint * (-1.0)

        if (MAX_zd_ok + tempcint >= 0) and (MIN_zd_ok - tempcint >= 0):
            tmpclevels = N.compress( \
                N.logical_and(positivecon <= MAX_zd_ok + tempcint,
                              positivecon >= MIN_zd_ok - tempcint),
                                     positivecon )
        elif (MAX_zd_ok + tempcint < 0) and (MIN_zd_ok - tempcint < 0):
            tmpclevels = N.compress( \
                N.logical_and(negativecon <= MAX_zd_ok + tempcint,
                              negativecon >= MIN_zd_ok - tempcint),
                                     negativecon )
        else:
            uppercon = N.compress(positivecon <= MAX_zd_ok + tempcint,
                                  positivecon)
            lowercon = N.compress(negativecon >= MIN_zd_ok - tempcint,
                                  negativecon)
            tmpclevels = N.concatenate([lowercon, uppercon])

#+ Sort clevels, reset number of levels, maximum, minimum,
#  and interval of contour based on the automatic setting:

        tmpclevels = N.sort(tmpclevels)
        if (N.size(tmpclevels) <= max_nlev) and (N.size(tmpclevels) > 0):
            nlevels = N.size(tmpclevels)
            tmpcmax = tmpclevels[-1]
            tmpcmin = tmpclevels[0]
            tmpcint = tempcint

    else:
        pass

    #- Return output:

    return N.arange(tmpcmin, tmpcmax + tmpcint, tmpcint)
示例#2
0
文件: plot.py 项目: jwblin/qtcm
def nice_levels(data, approx_nlev=10, max_nlev=28):
    """Compute a vector of "levels" at "nice" increments.

    Returns a 1-D array of "levels" (e.g., contour levels) calculated
    to give an aesthetically pleasing and human-readable interval,
    if possible.  If not, returns levels for approx_nlev levels
    between the maximum and minimum of data.  In any event, the
    function will return no more than max_nlev levels.

    Keyword Input Parameter:
    * data:  Array of values to calculate levels for.  Can be of any 
      size and shape.

    Keyword Input Parameter:
    * approx_nlev:  Integer referring to approximately how many
      levels to return.  This is the way of adjusting how "coarse"
      or "fine" to make the vector of levels.

    * max_nlev:  The maximum number of levels the function will
      permit to be returned.  The interval of levels will be adjusted
      to keep the number of levels returned under this value.  If
      approx_nlev is chosen to be greater than or equal to max_nlev,
      an exception is raised.

    Output:
    * This function returns a 1-D array of contour levels.

    Function is adaptation of parts of IDL routine contour_plot.pro
    by Johnny Lin.  This is why the capitalization conventions of
    Python are not strictly followed in this function.

    Examples:
    >>> z = N.array([-24.5, 50.3, 183.1, 20.])
    >>> out = nice_levels(z)
    >>> ['%g' % out[i] for i in range(len(out))]
    ['-30', '0', '30', '60', '90', '120', '150', '180', '210']

    >>> z = N.array([-24.5, 50.3, 183.1, 20.])
    >>> out = nice_levels(z, approx_nlev=5)
    >>> ['%g' % out[i] for i in range(len(out))]
    ['-50', '0', '50', '100', '150', '200']

    >>> z = N.array([-24.5, 50.3, 183.1, 20.])
    >>> out = nice_levels(z, approx_nlev=10)
    >>> ['%g' % out[i] for i in range(len(out))]
    ['-30', '0', '30', '60', '90', '120', '150', '180', '210']
    """
    #- Default settings and error check:

    if approx_nlev >= max_nlev:
        raise ValueError, 'max_nlev is too small'

    MAX_zd_ok = N.max(data)
    MIN_zd_ok = N.min(data)

    nlevels = N.min([approx_nlev, max_nlev])
    tmpcmax = MAX_zd_ok
    tmpcmin = MIN_zd_ok
    tmpcint = N.abs( (tmpcmax-tmpcmin)/float(nlevels) )


    #- See if the cint can be "even".  If not, return alternative
    #  contour levels vector:

    #+ Guess a possible cint.  Look for an "even" value that is
    #  closest to that:

    guesscint = N.abs( (MAX_zd_ok-MIN_zd_ok)/float(nlevels) )

    if (guesscint > 1e-10) and (guesscint < 1e+10):
        possiblecint = [1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5,
                            0.0001,  0.0002,            0.0005,
                            0.001,   0.002,             0.005,
                            0.01,    0.02,              0.05,
                            0.1,     0.2,               0.5,
                            1.,      2.,                5.,
                           10.,     20.,     30., 45., 50.,
                          100.,    200.,              500.,
                         1000.,   2000.,             5000.,
                        10000.,  20000.,            50000.,
                        1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10]

        diffcint = N.abs(possiblecint-guesscint)
        tempcint = N.compress( diffcint == N.min(diffcint), possiblecint )[0]
        tcidx = N.compress( where_close( possiblecint, tempcint ),
                            N.arange(N.size(possiblecint)) )[0]


        #+ Look around at the "even" values nearby the possible option
        #  for cint.  Calculate how many contours each of those cints
	#  would give.  Dictionary ncon_count is the number of
	#  contours for a given test cint.  test_tcidxs are the indices
	#  in possiblecint to examine in detail; these index values
	#  will be the keys in ncon_count.

        if tcidx == 0:  tcidx = 1
        if tcidx == N.size(possiblecint)-1:  tcidx = N.size(possiblecint)-2

        ncon_count = {}
        test_tcidxs = [tcidx-1, tcidx, tcidx+1]
        for i in test_tcidxs:
            itcval = possiblecint[i]
            positivecon = N.arange(max_nlev+2, dtype=float)*itcval
            negativecon = (N.arange(max_nlev+2, dtype=float)+1.0)*itcval*(-1.0)
            if (MAX_zd_ok + itcval >= 0) and (MIN_zd_ok - itcval >= 0):
                ncon_count[i] = N.sum( \
                    N.logical_and(positivecon <= MAX_zd_ok + itcval,
                                  positivecon >= MIN_zd_ok - itcval) )
            elif (MAX_zd_ok + itcval < 0) and (MIN_zd_ok - itcval < 0):
                ncon_count[i] = N.sum( \
                    N.logical_and(negativecon <= MAX_zd_ok + itcval,
                                  negativecon >= MIN_zd_ok - itcval) )
            else:
                ncon_count[i] = N.sum(positivecon <= MAX_zd_ok + itcval) \
                              + N.sum(negativecon >= MIN_zd_ok - itcval)


	#+ Select the cint that has the fewest levels if it has at
	#  least nlevels-1.  Otherwise, try to find the next cint with
	#  the fewest levels that is below max_nlev.  tempcint is what
	#  you get (changed, if warranted) leaving this section:

        min_ncon_count = N.min(ncon_count.values())
        current_best_count = max_nlev
        for i in test_tcidxs:
            if (ncon_count[i] == min_ncon_count) and \
               (ncon_count[i] >= nlevels-1):
                tempcint = possiblecint[i]
                current_best_count = ncon_count[i]
                break
            elif (ncon_count[i] == min_ncon_count) and \
               (ncon_count[i] < nlevels-1):
                continue
            elif ncon_count[i] > max_nlev:
                continue
            else:
                if N.abs(ncon_count[i]-nlevels) < \
                   N.abs(current_best_count-nlevels):
                    tempcint = possiblecint[i]
                    current_best_count = ncon_count[i]
                continue


	#+ Create levels for case with neg. and pos. contours.  There
	#  is the case of all pos., all neg., and mixed pos. and neg.
	#  contours:

        positivecon = N.arange(max_nlev+2, dtype=float)*tempcint
        negativecon = (N.arange(max_nlev+2, dtype=float)+1.0)*tempcint*(-1.0)

        if (MAX_zd_ok + tempcint >= 0) and (MIN_zd_ok - tempcint >= 0):
            tmpclevels = N.compress( \
                N.logical_and(positivecon <= MAX_zd_ok + tempcint, 
                              positivecon >= MIN_zd_ok - tempcint),
                                     positivecon )
        elif (MAX_zd_ok + tempcint < 0) and (MIN_zd_ok - tempcint < 0):
            tmpclevels = N.compress( \
                N.logical_and(negativecon <= MAX_zd_ok + tempcint, 
                              negativecon >= MIN_zd_ok - tempcint),
                                     negativecon )
        else:
            uppercon = N.compress( positivecon <= MAX_zd_ok + tempcint, 
                                   positivecon )
            lowercon = N.compress( negativecon >= MIN_zd_ok - tempcint, 
                                   negativecon )
            tmpclevels = N.concatenate([lowercon, uppercon])


	#+ Sort clevels, reset number of levels, maximum, minimum,
	#  and interval of contour based on the automatic setting:

        tmpclevels = N.sort(tmpclevels)
        if (N.size(tmpclevels) <= max_nlev ) and (N.size(tmpclevels) > 0):
            nlevels = N.size(tmpclevels)
            tmpcmax = tmpclevels[-1]
            tmpcmin = tmpclevels[0]
            tmpcint = tempcint

    else:
        pass


    #- Return output:

    return N.arange(tmpcmin, tmpcmax+tmpcint, tmpcint)