Changeset 27198


Ignore:
Timestamp:
08/10/22 06:04:05 (3 years ago)
Author:
bdef
Message:

NEW: adding some plotting capacity

Location:
issm/trunk-jpl/src/m/plot
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/src/m/plot/applyoptions.py

    r27087 r27198  
    3434    fontsize = options.getfieldvalue('fontsize', 8)
    3535    fontweight = options.getfieldvalue('fontweight', 'normal')
    36     fontfamily = options.getfieldvalue('fontfamily', 'sans - serif')
     36    fontfamily = options.getfieldvalue('fontfamily', 'sans-serif')
    3737    font = {
    3838        'fontsize': fontsize,
     
    186186    if options.exist('cmap_set_under'):
    187187        cbar_extend += 2
    188     # }}}
    189     # {{{ contours
    190     if options.exist('contourlevels'):
    191         plot_contour(md, data, options, ax)
    192     # }}}
    193     # {{{ edgeoverlay
    194     if options.exist('edgeoverlay'):
    195         edgedata = options.getfieldvalue('edgeoverlay')
    196         plot_edgeoverlay(md, edgedata, options, ax)
    197     # }}}
    198     # {{{ wrapping TODO
    199     # }}}
    200     # {{{ colorbar
    201     if options.getfieldvalue('colorbar', 1) == 1:
     188
     189    # }}}
     190    # {{{ colorbar extension
     191    if options.exist('cbar_extend'):
     192        extend = options.getfieldvalue('cbar_extend', 'neither')
     193    else:
    202194        if cbar_extend == 0:
    203195            extend = 'neither'
     
    208200        elif cbar_extend == 3:
    209201            extend = 'both'
    210 
     202        options.addfielddefault('cbar_extend', extend)
     203    # }}}
     204    # {{{ contours
     205    if options.exist('contourlevels'):
     206        plot_contour(md, data, options, ax)
     207    # }}}
     208    # {{{ edgeoverlay
     209    if options.exist('edgeoverlay'):
     210        edgedata = options.getfieldvalue('edgeoverlay')
     211        plot_edgeoverlay(md, edgedata, options, ax)
     212    # }}}
     213    # {{{ wrapping TODO
     214    # }}}
     215    # {{{ colorbar
     216    if options.getfieldvalue('colorbar', 1) == 1:
    211217        cb = mpl.colorbar.ColorbarBase(ax.cax, cmap=cmap, norm=norm, extend=extend)
    212218        if options.exist('alpha'):
  • issm/trunk-jpl/src/m/plot/plot_edgeoverlay.py

    r27088 r27198  
    33import matplotlib.pyplot as plt
    44from processmesh import processmesh
     5from matplotlib import collections
     6from scipy.stats import percentileofscore
    57
    68
     
    1315    See also: PLOTMODEL'''
    1416
     17    # if md.mesh.numberofedges not in np.shape(datain):
     18    #     raise ValueError('Data must be defined on edges to be ploted as an edge overlay')
     19
    1520    x, y, z, elements, is2d, isplanet = processmesh(md, [], options)
     21    Edges = md.mesh.edges - 1
    1622
    17     flags = datain > 6.7e-5  # this is appropriate for channel Area (perhaps)
    18     hide = np.invert(flags)
     23    #First we mask values under a given value define by quantiles
     24    if options.exist('edgemin'):
     25        minval = options.getfieldvalue('edgemin', 0)
     26        minquant = percentileofscore(datain, minval, kind='weak')
     27        minquant = minquant / 100
     28    else:
     29        minquant = 0.7
     30        minval = np.quantile(datain, minquant)
     31    print("For the overlay we plot values above {:.4g} wich corresponds to the {}% percentile".format(minval, minquant * 100))
    1932
    20     NodeMask = np.zeros(np.shape(md.mesh.x), dtype=bool)
    21     HideElt = md.mesh.edges[np.where(hide), 0] - 1
    22     NodeMask[HideElt] = True
    23     MaskX = np.ma.array(x, mask=NodeMask)
    24     MaskY = np.ma.array(y, mask=NodeMask)
     33    flags = datain > minval  #6.7e-5  # this is appropriate for channel Area (perhaps)
    2534
    26     EdgeEnd = md.mesh.edges[:, 1] - 1
    27     EdgeStart = md.mesh.edges[:, 0] - 1
    28     quiverU = MaskX[EdgeEnd] - MaskX[EdgeStart]
    29     quiverV = MaskY[EdgeEnd] - MaskY[EdgeStart]
     35    edgetype = options.getfieldvalue('edgetype', 'thickness')
    3036
    31     Masked = np.ma.masked_array(datain, mask=hide)
    32     if options.exist('cedgelim'):
    33         lims = options.getfieldvalue('cedgelim', [Masked.min(), Masked.max()])
    34         edgenorm = mpl.colors.Normalize(vmin=lims[0], vmax=lims[1])
     37    if edgetype == "color":
     38        #create an nodewise dataset from edges
     39        NodeMask = np.ones(np.shape(md.mesh.x), dtype=bool)
     40        #We grab all the starts from the unmasked edges
     41        Starters = Edges[np.where(flags), 0]
     42        NodeMask[Starters] = False
     43        Xstart = np.ma.array(x, mask=NodeMask)
     44        Ystart = np.ma.array(y, mask=NodeMask)
     45
     46        NodeMask = np.ones(np.shape(md.mesh.x), dtype=bool)
     47        Enders = Edges[np.where(flags), 1]
     48        NodeMask[Enders] = False
     49        Xend = np.ma.array(x, mask=NodeMask)
     50        Yend = np.ma.array(y, mask=NodeMask)
     51
     52        #define vectors from the start and end point of the unmasked edges
     53        EdgeEnd = Edges[:, 1]
     54        EdgeStart = Edges[:, 0]
     55        quiverU = np.ma.array(Xend[EdgeEnd] - Xstart[EdgeStart], mask=np.invert(flags))
     56        quiverV = np.ma.array(Yend[EdgeEnd] - Ystart[EdgeStart], mask=np.invert(flags))
     57
     58        #mask out the values from the data and create colorscale
     59        Masked = np.ma.masked_array(datain, mask=np.invert(flags))
     60        cbar_extend = 0
     61        edgemap = plt.cm.get_cmap('inferno')
     62        if options.exist('cedgeaxis'):
     63            lims = options.getfieldvalue('cedgeaxis', [Masked.min(), Masked.max()])
     64            edgenorm = mpl.colors.Normalize(vmin=lims[0], vmax=lims[1])
     65            if lims[0] > Masked.min():
     66                edgemap.set_under('r')
     67                cbar_extend += 2
     68            if lims[1] < Masked.max():
     69                edgemap.set_over('k')
     70                cbar_extend += 1
     71        else:
     72            edgenorm = mpl.colors.Normalize(vmin=Masked.min(), vmax=Masked.max())
     73
     74        if cbar_extend == 0:
     75            extend = 'neither'
     76        elif cbar_extend == 1:
     77            extend = 'max'
     78        elif cbar_extend == 2:
     79            extend = 'min'
     80        elif cbar_extend == 3:
     81            extend = 'both'
     82
     83        ax.quiver(Xstart[EdgeStart], Ystart[EdgeStart], quiverU, quiverV, datain,
     84                  units="xy", angles="xy", scale_units="xy", scale=1,
     85                  headwidth=0, headlength=0, width=100, headaxislength=0,
     86                  norm=edgenorm, cmap=edgemap)
     87
     88        #plt.colorbar(plt.cm.ScalarMappable(norm=edgenorm, cmap=edgemap), ax=ax, extend=extend, orientation='horizontal', anchor=(1, 0))
     89        cbarax = ax.inset_axes([0.02, 0.02, 0.96, 0.05])
     90        #inset_axes(ax, width="100%", height="5%", loc='lower center', borderpad=-5)
     91        mpl.colorbar.ColorbarBase(cbarax, norm=edgenorm, cmap=edgemap, extend=extend, orientation='horizontal', ticklocation='top')
     92
     93    elif edgetype == 'thickness':
     94        #First we classify a range
     95        if options.exist('edgeranges'):
     96            edgeranges = options.getfieldvalue('edgeranges', 2)
     97        else:
     98            edgeranges = 2
     99
     100        quantrange = np.linspace(minquant, 1, edgeranges + 1)[:-1]
     101        flags = []
     102        legtext = []
     103        for Qindex, quantile in enumerate(quantrange):
     104            if quantile < quantrange[-1]:
     105                lowquant = np.quantile(datain, quantile)
     106                highquant = np.quantile(datain, quantrange[Qindex + 1])
     107                flags.append(np.logical_and(datain >= lowquant, datain <= highquant))
     108                legtext.append('From  {:.2g} to {:.2g}'. format(lowquant, highquant))
     109            else:
     110                lowquant = np.quantile(datain, quantile)
     111                flags.append((datain > lowquant))
     112                legtext.append('More than {:.2g}'.format(lowquant))
     113
     114        flags = np.asarray(np.squeeze(flags))
     115        EdgeEnd = Edges[:, 1]
     116        EdgeStart = Edges[:, 0]
     117
     118        for index in range(edgeranges):
     119            linecol = []
     120            #We loop on the result and aonly add to a linecollection the flaged edges.
     121            for datindex, datval in enumerate(datain):
     122                if flags[index, datindex]:
     123                    linecol.append([(x[EdgeStart[datindex]], y[EdgeStart[datindex]]),
     124                                    (x[EdgeEnd[datindex]], y[EdgeEnd[datindex]])])
     125
     126            lc = collections.LineCollection(linecol, color='k', linewidth=0.5 + index,
     127                                            label=legtext[index])
     128            ax.add_collection(lc)
     129
     130        ax.legend(title='Overlay')
     131
    35132    else:
    36         edgenorm = mpl.colors.Normalize(vmin=Masked.min(), vmax=Masked.max())
    37     edgemap = plt.cm.get_cmap('inferno')
    38 
    39     ax.quiver(MaskX[EdgeStart], MaskY[EdgeStart], quiverU, quiverV, datain,
    40               units="xy", angles="xy", scale_units="xy", scale=1,
    41               headwidth=0, headlength=0, width=100, headaxislength=0,
    42               norm=edgenorm, cmap=edgemap)
    43 
    44     plt.colorbar(plt.cm.ScalarMappable(norm=edgenorm, cmap=edgemap), ax=ax)
     133        print("Only 'color', and 'thickness' are accepted as edgeoverlay types")
  • issm/trunk-jpl/src/m/plot/plot_manager.py

    r26353 r27198  
    2727    currently generated using matplotlib's AxesGrid toolkit.
    2828
    29     'gridindex' is passed through to specialized plot* functions and 
     29    'gridindex' is passed through to specialized plot* functions and
    3030    applyoptions.
    3131
     
    8989    # }}}
    9090
    91     #process data and model
    9291    x, y, z, elements, is2d, isplanet = processmesh(md, data, options)
    9392    data2, datatype = processdata(md, data, options)
  • issm/trunk-jpl/src/m/plot/plot_unit.py

    r27087 r27198  
    3333
    3434    # colormap
    35     # {{{ give number of colorlevels and transparency
     35    # give number of colorlevels and transparency {{{
    3636    colorlevels = options.getfieldvalue('colorlevels', 128)
    3737    alpha = options.getfieldvalue('alpha', 1)
    38     if alpha < 1:
    39         antialiased = True
    40     else:
    41         antialiased = False
    42     # }}}
    43     # {{{ define wich colormap to use
     38    # }}}
     39    # define wich colormap to use {{{
    4440    try:
    4541        defaultmap = plt.cm.get_cmap('viridis', colorlevels)
     
    5147    else:
    5248        cmap = getcolormap(options)
    53     if options.exist('cmap_set_over'):
    54         over = options.getfieldvalue('cmap_set_over', 'k')
    55         cmap.set_over(over)
    56     if options.exist('cmap_set_under'):
    57         under = options.getfieldvalue('cmap_set_under', 'k')
    58         cmap.set_under(under)
    5949    options.addfield('colormap', cmap)
    6050    # }}}
    61     # {{{ if plotting only one of several layers reduce dataset, same for surface
     51    # if plotting only one of several layers reduce dataset, same for surface {{{
    6252    if options.getfieldvalue('layer', 0) >= 1:
    6353        plotlayer = options.getfieldvalue('layer', 0)
     
    6858        data = data[(plotlayer - 1) * slicesize:plotlayer * slicesize]
    6959    # }}}
    70     # {{{ Get the colormap limits
     60    # Get the colormap limits {{{
    7161    dataspread = np.nanmax(data) - np.nanmin(data)
    7262    if dataspread != 0.:
     
    7767    if options.exist('caxis'):
    7868        lims = options.getfieldvalue('caxis', [np.nanmin(data), np.nanmax(data)])
     69        if lims[0] > np.nanmin(data):
     70            options.addfielddefault('cmap_set_under', 'r')
     71        if lims[1] < np.nanmax(data):
     72            options.addfielddefault('cmap_set_over', 'k')
    7973    else:
    8074        if limextent == 0.:
     
    8579        else:
    8680            lims = [np.nanmin(data), np.nanmax(data)]
    87     # }}}
    88     # {{{ Set the spread of the colormap (default is normal
     81
     82    cbar_extend = 0
     83    if options.exist('cmap_set_over'):
     84        over = options.getfieldvalue('cmap_set_over', 'k')
     85        cmap.set_over(over)
     86        cbar_extend += 1
     87    if options.exist('cmap_set_under'):
     88        under = options.getfieldvalue('cmap_set_under', 'r')
     89        cmap.set_under(under)
     90        cbar_extend += 2
     91    # }}}
     92
     93    # colorbar extension {{{
     94    if cbar_extend == 0:
     95        extend = 'neither'
     96    elif cbar_extend == 1:
     97        extend = 'max'
     98    elif cbar_extend == 2:
     99        extend = 'min'
     100    elif cbar_extend == 3:
     101        extend = 'both'
     102    options.addfielddefault('cbar_extend', extend)
     103    # }}}
     104    # Set the spread of the colormap (default is normal) {{{
    89105    if options.exist('log'):
    90106        norm = mpl.colors.LogNorm(vmin=lims[0], vmax=lims[1])
     
    95111
    96112    # Plot depending on the datatype
    97     # {{{ data are on elements
     113    # data are on elements {{{
    98114    if datatype == 1:
    99115        if is2d:
     
    102118            else:
    103119                triangles = mpl.tri.Triangulation(x, y, elements)
     120
    104121            tri = ax.tripcolor(triangles, data, colorlevels, cmap=cmap, norm=norm, alpha=alpha, edgecolors=edgecolor)
    105122        else:
     
    153170
    154171    # }}}
    155     # {{{ data are on nodes
    156 
     172    # data are on nodes {{{
    157173    elif datatype == 2:
    158174        if is2d:
     
    162178            else:
    163179                triangles = mpl.tri.Triangulation(x, y, elements)
    164     #tri = ax.tricontourf(triangles, data, colorlevels, cmap = cmap, norm=norm, alpha = alpha)
    165             if options.exist('log'):
    166                 if alpha < 1:  #help with antialiasing
    167                     tri = ax.tricontour(triangles, data, colorlevels, cmap=cmap, norm=norm, alpha=0.1, antialiased=antialiased)
    168                 tri = ax.tricontourf(triangles, data, colorlevels, cmap=cmap, norm=norm, alpha=alpha, antialiased=antialiased)
     180            if edgecolor == 'None':
     181                tri = ax.tripcolor(triangles, data, cmap=cmap, norm=norm, alpha=alpha, shading='gouraud')
    169182            else:
    170                 if alpha < 1:  #help with antialiasing
    171                     tri = ax.tricontour(triangles, data, colorlevels, cmap=cmap, norm=norm, alpha=0.1, antialiased=antialiased)
    172                 tri = ax.tricontourf(triangles, data, colorlevels, cmap=cmap, norm=norm, alpha=alpha, extend='both', antialiased=antialiased)
    173             if edgecolor != 'None':
    174                 ax.triplot(x, y, elements, color=edgecolor)
     183                tri = ax.tripcolor(triangles, data, cmap=cmap, norm=norm, alpha=alpha, edgecolors=edgecolor)
    175184        else:
    176185            #first deal with the colormap
     
    178187            loccmap.set_array(lims)
    179188            loccmap.set_clim(vmin=lims[0], vmax=lims[1])
    180 
    181189    #deal with prism sides
    182190            recface = np.vstack((elements[:, 0], elements[:, 1], elements[:, 4], elements[:, 3])).T
     
    215223
    216224    # }}}
    217     # {{{ plotting quiver
     225    # plotting quiver {{{
    218226    elif datatype == 3:
    219227        if is2d:
     
    223231        return
    224232    # }}}
    225     # {{{ plotting P1 Patch (TODO)
     233    # plotting P1 Patch (TODO) {{{
    226234    elif datatype == 4:
    227235        print('plot_unit message: P1 patch plot not implemented yet')
    228236        return
    229237    # }}}
    230     # {{{ plotting P0 Patch (TODO)
     238    # plotting P0 Patch (TODO) {{{
    231239    elif datatype == 5:
    232240        print('plot_unit message: P0 patch plot not implemented yet')
    233241        return
    234242    # }}}
     243    # plotting edges  {{{
     244    elif datatype == 6:
     245        if is2d:
     246            triangles = mpl.tri.Triangulation(x, y, elements)
     247            tri = ax.tripcolor(triangles, data, cmap=cmap, norm=norm, alpha=alpha, edgecolors=edgecolor)
     248
     249        else:
     250            print("edge plotting is not implemented for 3D")
     251        return
     252    # }}}
    235253    else:
    236254        raise ValueError('datatype = %d not supported' % datatype)
  • issm/trunk-jpl/src/m/plot/plotmodel.py

    r27087 r27198  
    2828    numberofplots = options.numberofplots
    2929
    30     #get number of subplots
    31     subplotwidth = ceil(sqrt(numberofplots))
     30    #get the "optimal" number of subfigures in a row/col
     31    if (np.nanmax(md.mesh.x) - np.nanmin(md.mesh.x)) > (np.nanmax(md.mesh.y) - np.nanmin(md.mesh.y)):
     32        maxrow = ceil(sqrt(numberofplots))
     33        maxcol = ceil(numberofplots / maxrow)
     34    else:
     35        maxcol = ceil(sqrt(numberofplots))
     36        maxrow = ceil(numberofplots / maxcol)
    3237
    33     # TODO: Check that commenting this out is correct; we do not need a hold
    34     # under matplotlib, right?
    35     #
    36     # #get hold
    37     # hold = options.list[0].getfieldvalue('hold', False)
    38 
    39     #if nrows and ncols specified, then bypass
     38    #If any  of nrows or ncols are given we use that
    4039    if options.list[0].exist('nrows'):
    4140        nrows = options.list[0].getfieldvalue('nrows')
    42         nr = True
     41        if options.list[0].exist('ncols'):
     42            ncols = options.list[0].getfieldvalue('ncols')
     43        else:
     44            ncols = ceil(numberofplots / nrows)
     45    elif options.list[0].exist('ncols'):
     46        ncols = options.list[0].getfieldvalue('ncols')
     47        nrows = ceil(numberofplots / ncols)
    4348    else:
    44         nrows = np.ceil(numberofplots / subplotwidth)
    45         nr = False
    46 
    47     if options.list[0].exist('ncols'):
    48         ncols = options.list[0].getfieldvalue('ncols')
    49         nc = True
    50     else:
    51         ncols = int(subplotwidth)
    52         nc = False
     49        nrows = maxrow
     50        ncols = maxcol
    5351    ncols = int(ncols)
    5452    nrows = int(nrows)
    55 
    56     #check that nrows and ncols were given at the same time!
    57     if nr != nc:
    58         raise Exception('plotmodel error message: nrows and ncols need to be specified together, or not at all')
    5953
    6054    # Go through plots
  • issm/trunk-jpl/src/m/plot/processdata.py

    r27087 r27198  
    88    datatype = 2 -> nodes
    99    datatype = 3 -> node quivers
    10     datatype = 4 -> patch
     10    datatype = 4 -> P1 patch
     11    datatype = 5 -> P0 patch
     12    datatype = 6 -> edges
    1113
    1214    Usage:
     
    2426    else:
    2527        numberofvertices2d = np.nan
     28
     29    try:
     30        numberofedges = md.mesh.numberofedges
     31    except AttributeError:
     32        numberofedges = np.nan
    2633
    2734    if options.exist('amr'):
     
    5259    # }}}
    5360
    54     #  log {{{
     61    # log {{{
    5562    if options.exist('log'):
    5663        cutoff = options.getfieldvalue('log', 1)
     
    5865    # }}}
    5966
    60     #  quiver plot {{{
     67    # quiver plot {{{
    6168    if datasize[1] > 1 and datasize[0] != numberofvertices + 1:
    6269        if datasize[0] == numberofvertices and datasize[1] in [2, 3]:
     
    8087    # }}}
    8188
    82     #  element data{{{
     89    # element data{{{
    8390    if datasize[0] == numberofelements and datasize[1] == 1:
    8491        #initialize datatype if non patch
     
    107114    # }}}
    108115
    109     #  node data {{{
    110     if datasize[0] in [numberofvertices, numberofvertices2d] and datasize[1] == 1:
     116    # node data {{{
     117    elif datasize[0] in [numberofvertices, numberofvertices2d] and datasize[1] == 1:
    111118        datatype = 2
    112119        # AMR {{{
     
    115122            procdata = procdata[nonan]
    116123        # }}}
    117         #  Mask {{{
     124        # Mask {{{
    118125        if options.exist('mask'):
    119126            flags = options.getfieldvalue('mask')
     
    133140    # }}}
    134141
    135     #  spc time series {{{
    136     if datasize[0] == numberofvertices + 1:
     142    # edge data {{{
     143    elif datasize[0] in [numberofedges] and datasize[1] == 1:
     144        datatype = 6
     145        procdata = np.zeros((md.mesh.numberofelements))
     146        repeat = np.zeros((md.mesh.numberofelements))
     147        for index, edge in enumerate(md.mesh.edges[:, -2:]):
     148            procdata[edge - 1] += data[index] * np.asarray(edge - 1 > -1, dtype=int)
     149            repeat[edge - 1] += np.asarray(edge - 1 > -1, dtype=int)
     150        procdata = procdata / repeat
     151
     152        # }}}
     153    # }}}
     154
     155    # spc time series {{{
     156    elif datasize[0] == numberofvertices + 1:
    137157        datatype = 2
    138158        spccol = options.getfieldvalue('spccol', 0)
     
    141161        procdata = procdata[0:-1, spccol]
    142162
    143         #mask?
    144 
    145         #layer projection?
    146 
    147         #control arrow density if quiver plot
    148163    # }}}
    149164
    150     # convert rank - 2 array to rank - 1 {{{
     165    # convert rank -2 array to rank -1 {{{
    151166    if np.ndim(procdata) == 2 and np.shape(procdata)[1] == 1:
    152167        procdata = procdata.reshape(-1, )
     
    169184        procdata[np.isnan(procdata)] = nanfill
    170185        procdata = np.ma.array(procdata, mask=np.isnan(procdata))
    171         print('from nan processing {} and {}'.format(lb, ub))
    172186        if nanfill < lb:
    173             options.addfielddefault('cmap_set_under', 'k')
     187            options.addfielddefault('cmap_set_under', 'r')
    174188        elif nanfill > ub:
    175189            options.addfielddefault('cmap_set_over', 'k')
Note: See TracChangeset for help on using the changeset viewer.