def __init__(self, vel_dir, params): # Initialize the base class super(SimpleVelocityContainer, self).__init__(params) self.vel_dir = vel_dir # used by __str__ self.profiles = {} count = 0 for profile in fnmatch.filter(os.listdir(vel_dir), '*.txt'): count += 1 with open(os.path.join(vel_dir, profile), 'r') as f: # Read the location out of the file header = False loc = None while not header: l = f.readline().lstrip() if l.startswith('#'): header = True elif l.startswith('coordinates'): x, y = l.split(',')[1:] x = float(x) y = float(y) loc = Point((x, y)) header = True if not loc: # There were no coordinates. loc = Point((0, 0)) # Build up the time depth profile self.profiles[loc] = [] for line in f.readlines(): # Ignore comments if line.strip().startswith('#'): continue if len(line.strip().split(',')) == 2: time, depth = line.strip().split(',') elif len(line.strip().split()) == 2: time, depth = line.strip().split() else: Notice.warning("Could not read velocity file.") continue self.profiles[loc].append([float(time), float(depth)]) self.count = count
def plot_feature_well(tc, gs): """ Plotting function for the feature well. Args: tc (TransectContainer): The container for the main plot. log (axis): A matplotlib axis. gs (GridSpec): A matplotlib gridspec. """ fname = tc.settings['curve_display'] logs = tc.log.get(tc.feature_well) if not logs: # There was no data for this well, so there won't be a feature plot. Notice.fail("There's no well data for feature well " + tc.feature_well) return gs Z = logs.data['DEPT'] curves = ['GR', 'DT', 'DPHI_SAN', 'NPHI_SAN', 'DTS', 'RT_HRLT', 'RHOB', 'DRHO'] window = tc.settings.get('curve_smooth_window') or 51 ntracks = 5 lw = 1.0 smooth = True naxes = 0 ncurv_per_track = np.zeros(ntracks) if getattr(tc.log, 'striplog', None): ncurv_per_track[0] = 1 for curve in curves: naxes += 1 params = get_curve_params(curve, fname) ncurv_per_track[params['track']] += 1 axss = plt.subplot(gs[2:, -5]) axs0 = [axss, axss.twiny()] axs1 = [plt.subplot(gs[2:, -4])] axs2 = [plt.subplot(gs[2:, -3])] axs3 = [plt.subplot(gs[2:, -2])] axs4 = [plt.subplot(gs[2:, -1])] axs = [axs0, axs1, axs2, axs3, axs4] if getattr(tc.log, 'striplog', None): legend = Legend.default() try: logs.striplog[tc.log.striplog].plot_axis(axs0[0], legend=legend) except KeyError: # In fact, this striplog doesn't exist. Notice.fail("There is no such striplog" + tc.log.striplog) # And move on... axs0[0].set_ylim([Z[-1], 0]) label_shift = np.zeros(len(axs)) for curve in curves: try: values = logs.data[curve] except ValueError: Notice.warning("Curve not present: "+curve) values = np.empty_like(Z) values[:] = np.nan params = get_curve_params(curve, fname) i = params['track'] j = 0 label_shift[i] += 1 linOrlog = params['logarithmic'] sxticks = np.array(params['xticks']) xticks = np.array(sxticks, dtype=float) whichticks = 'major' if linOrlog == 'log': midline = np.log(np.mean(xticks)) xpos = midline whichticks = 'minor' else: midline = np.mean(xticks) xpos = midline if smooth: values = utils.rolling_median(values, window) if curve == 'GR': j = 1 # second axis in first track label_shift[i] = 1 if params['fill_left_cond']: # do the fill for the lithology track axs[i][j].fill_betweenx(Z, params['xleft'], values, facecolor=params['fill_left'], alpha=1.0, zorder=11) if (curve == 'DPHI_SAN') and params['fill_left_cond']: # do the fill for the neutron porosity track try: nphi = utils.rolling_median(logs.data['NPHI_SAN'], window) except ValueError: Notice.warning("No NPHI in this well") nphi = np.empty_like(Z) nphi[:] = np.nan axs[i][j].fill_betweenx(Z, nphi, values, where=nphi >= values, facecolor=params['fill_left'], alpha=1.0, zorder=11) axs[i][j].fill_betweenx(Z, nphi, values, where=nphi <= values, facecolor='#8C1717', alpha=0.5, zorder=12) if curve == 'DRHO': blk_drho = 3.2 values += blk_drho # this is a hack to get DRHO on RHOB scale axs[i][j].fill_betweenx(Z, blk_drho, values, where=nphi <= values, facecolor='#CCCCCC', alpha=0.5, zorder=12) # fill right if params['fill_right_cond']: axs[i][j].fill_betweenx(Z, values, params['xright'], facecolor=params['fill_right'], alpha=1.0, zorder=12) # plot curve axs[i][j].plot(values, Z, color=params['hexcolor'], lw=lw, zorder=13) # set scale of curve axs[i][j].set_xlim([params['xleft'], params['xright']]) # ------------------------------------------------- # # curve labels # ------------------------------------------------- # trans = transforms.blended_transform_factory(axs[i][j].transData, axs[i][j].transData) magic = -Z[-1] / 12. axs[i][j].text(xpos, magic - (magic/4)*(label_shift[i]-1), curve, horizontalalignment='center', verticalalignment='bottom', fontsize=12, color=params['hexcolor'], transform=trans) # curve units units = '${}$'.format(params['units']) if label_shift[i] <= 1: axs[i][j].text(xpos, magic*0.5, units, horizontalalignment='center', verticalalignment='top', fontsize=12, color='k', transform=trans) # ------------------------------------------------- # # scales and tickmarks # ------------------------------------------------- # axs[i][j].set_xscale(linOrlog) axs[i][j].set_ylim([Z[-1], 0]) axs[i][j].axes.xaxis.set_ticks(xticks) axs[i][j].axes.xaxis.set_ticklabels(sxticks, fontsize=8) for label in axs[i][j].axes.xaxis.get_ticklabels(): label.set_rotation(90) axs[i][j].tick_params(axis='x', direction='out') axs[i][j].xaxis.tick_top() axs[i][j].xaxis.set_label_position('top') axs[i][j].xaxis.grid(True, which=whichticks, linewidth=0.25, linestyle='-', color='0.75', zorder=100) axs[i][j].yaxis.grid(True, which=whichticks, linewidth=0.25, linestyle='-', color='0.75', zorder=100) axs[i][j].yaxis.set_ticks(np.arange(0, max(Z), 100)) if i != 0: axs[i][j].set_yticklabels("") # ------------------------------------------------- # # End of curve loop # ------------------------------------------------- # # Add Depth label axs[0][0].text(0, 1.05, 'MD\n$m$', fontsize='10', horizontalalignment='center', verticalalignment='center', transform=axs[0][0].transAxes) axs[0][0].axes.yaxis.get_ticklabels() axs[0][0].axes.xaxis.set_ticklabels('') for label in axs[0][0].axes.yaxis.get_ticklabels(): label.set_rotation(90) label.set_fontsize(10) for label in axs[1][0].axes.xaxis.get_ticklabels(): label.set_rotation(90) label.set_fontsize(10) # Add Tops try: if os.path.exists(tc.tops_file): tops = utils.get_tops(tc.tops_file) topx = get_curve_params('DT', fname) topmidpt = np.amax((topx)['xright']) # plot tops for i in range(ntracks): for mkr, depth in tops.iteritems(): # draw horizontal bars at the top position axs[i][-1].axhline(y=depth, xmin=0.01, xmax=.99, color='b', lw=2, alpha=0.5, zorder=100) # draw text box at the right edge of the last track axs[-1][-1].text(x=topmidpt, y=depth, s=mkr, alpha=0.5, color='k', fontsize='8', horizontalalignment='center', verticalalignment='center', zorder=10000, bbox=dict(facecolor='white', edgecolor='k', alpha=0.25, lw=0.25), weight='light') except AttributeError: Notice.warning("No tops for this well") except TypeError: # We didn't get a tops file so move along. print "No tops for this well" return gs
def plot_feature_well(tc, gs): """ Plotting function for the feature well. Args: tc (TransectContainer): The container for the main plot. log (axis): A matplotlib axis. gs (GridSpec): A matplotlib gridspec. """ fname = tc.settings['curve_display'] logs = tc.log.get(tc.feature_well) if not logs: # There was no data for this well, so there won't be a feature plot. Notice.fail("There's no well data for feature well " + tc.feature_well) return gs Z = logs.data['DEPT'] curves = [ 'GR', 'DT', 'DPHI_SAN', 'NPHI_SAN', 'DTS', 'RT_HRLT', 'RHOB', 'DRHO' ] window = tc.settings.get('curve_smooth_window') or 51 ntracks = 5 lw = 1.0 smooth = True naxes = 0 ncurv_per_track = np.zeros(ntracks) if getattr(tc.log, 'striplog', None): ncurv_per_track[0] = 1 for curve in curves: naxes += 1 params = get_curve_params(curve, fname) ncurv_per_track[params['track']] += 1 axss = plt.subplot(gs[2:, -5]) axs0 = [axss, axss.twiny()] axs1 = [plt.subplot(gs[2:, -4])] axs2 = [plt.subplot(gs[2:, -3])] axs3 = [plt.subplot(gs[2:, -2])] axs4 = [plt.subplot(gs[2:, -1])] axs = [axs0, axs1, axs2, axs3, axs4] if getattr(tc.log, 'striplog', None): legend = Legend.default() try: logs.striplog[tc.log.striplog].plot_axis(axs0[0], legend=legend) except KeyError: # In fact, this striplog doesn't exist. Notice.fail("There is no such striplog" + tc.log.striplog) # And move on... axs0[0].set_ylim([Z[-1], 0]) label_shift = np.zeros(len(axs)) for curve in curves: try: values = logs.data[curve] except ValueError: Notice.warning("Curve not present: " + curve) values = np.empty_like(Z) values[:] = np.nan params = get_curve_params(curve, fname) i = params['track'] j = 0 label_shift[i] += 1 linOrlog = params['logarithmic'] sxticks = np.array(params['xticks']) xticks = np.array(sxticks, dtype=float) whichticks = 'major' if linOrlog == 'log': midline = np.log(np.mean(xticks)) xpos = midline whichticks = 'minor' else: midline = np.mean(xticks) xpos = midline if smooth: values = utils.rolling_median(values, window) if curve == 'GR': j = 1 # second axis in first track label_shift[i] = 1 if params['fill_left_cond']: # do the fill for the lithology track axs[i][j].fill_betweenx(Z, params['xleft'], values, facecolor=params['fill_left'], alpha=1.0, zorder=11) if (curve == 'DPHI_SAN') and params['fill_left_cond']: # do the fill for the neutron porosity track try: nphi = utils.rolling_median(logs.data['NPHI_SAN'], window) except ValueError: Notice.warning("No NPHI in this well") nphi = np.empty_like(Z) nphi[:] = np.nan axs[i][j].fill_betweenx(Z, nphi, values, where=nphi >= values, facecolor=params['fill_left'], alpha=1.0, zorder=11) axs[i][j].fill_betweenx(Z, nphi, values, where=nphi <= values, facecolor='#8C1717', alpha=0.5, zorder=12) if curve == 'DRHO': blk_drho = 3.2 values += blk_drho # this is a hack to get DRHO on RHOB scale axs[i][j].fill_betweenx(Z, blk_drho, values, where=nphi <= values, facecolor='#CCCCCC', alpha=0.5, zorder=12) # fill right if params['fill_right_cond']: axs[i][j].fill_betweenx(Z, values, params['xright'], facecolor=params['fill_right'], alpha=1.0, zorder=12) # plot curve axs[i][j].plot(values, Z, color=params['hexcolor'], lw=lw, zorder=13) # set scale of curve axs[i][j].set_xlim([params['xleft'], params['xright']]) # ------------------------------------------------- # # curve labels # ------------------------------------------------- # trans = transforms.blended_transform_factory(axs[i][j].transData, axs[i][j].transData) magic = -Z[-1] / 12. axs[i][j].text(xpos, magic - (magic / 4) * (label_shift[i] - 1), curve, horizontalalignment='center', verticalalignment='bottom', fontsize=12, color=params['hexcolor'], transform=trans) # curve units units = '${}$'.format(params['units']) if label_shift[i] <= 1: axs[i][j].text(xpos, magic * 0.5, units, horizontalalignment='center', verticalalignment='top', fontsize=12, color='k', transform=trans) # ------------------------------------------------- # # scales and tickmarks # ------------------------------------------------- # axs[i][j].set_xscale(linOrlog) axs[i][j].set_ylim([Z[-1], 0]) axs[i][j].axes.xaxis.set_ticks(xticks) axs[i][j].axes.xaxis.set_ticklabels(sxticks, fontsize=8) for label in axs[i][j].axes.xaxis.get_ticklabels(): label.set_rotation(90) axs[i][j].tick_params(axis='x', direction='out') axs[i][j].xaxis.tick_top() axs[i][j].xaxis.set_label_position('top') axs[i][j].xaxis.grid(True, which=whichticks, linewidth=0.25, linestyle='-', color='0.75', zorder=100) axs[i][j].yaxis.grid(True, which=whichticks, linewidth=0.25, linestyle='-', color='0.75', zorder=100) axs[i][j].yaxis.set_ticks(np.arange(0, max(Z), 100)) if i != 0: axs[i][j].set_yticklabels("") # ------------------------------------------------- # # End of curve loop # ------------------------------------------------- # # Add Depth label axs[0][0].text(0, 1.05, 'MD\n$m$', fontsize='10', horizontalalignment='center', verticalalignment='center', transform=axs[0][0].transAxes) axs[0][0].axes.yaxis.get_ticklabels() axs[0][0].axes.xaxis.set_ticklabels('') for label in axs[0][0].axes.yaxis.get_ticklabels(): label.set_rotation(90) label.set_fontsize(10) for label in axs[1][0].axes.xaxis.get_ticklabels(): label.set_rotation(90) label.set_fontsize(10) # Add Tops try: if os.path.exists(tc.tops_file): tops = utils.get_tops(tc.tops_file) topx = get_curve_params('DT', fname) topmidpt = np.amax((topx)['xright']) # plot tops for i in range(ntracks): for mkr, depth in tops.iteritems(): # draw horizontal bars at the top position axs[i][-1].axhline(y=depth, xmin=0.01, xmax=.99, color='b', lw=2, alpha=0.5, zorder=100) # draw text box at the right edge of the last track axs[-1][-1].text(x=topmidpt, y=depth, s=mkr, alpha=0.5, color='k', fontsize='8', horizontalalignment='center', verticalalignment='center', zorder=10000, bbox=dict(facecolor='white', edgecolor='k', alpha=0.25, lw=0.25), weight='light') except AttributeError: Notice.warning("No tops for this well") except TypeError: # We didn't get a tops file so move along. print "No tops for this well" return gs
def plot(tc): """ Constructs a multi-subplot matplotlib figure. Args: transect (TransectContainer): A transect container. """ h = 15 mw = 16 # width of main section (inches) must be div by 4 fw = 5 # width of the feature plot (inches) must be div by 5 n_grids = len(tc.potfield.data) # We will save the same figure we make, to ensure the saved figure # has everything in the right places. For example, see this discussion: # http://stackoverflow.com/questions/7906365/ save_dpi = getattr(tc, 'save_dpi', tc.settings.get('default_dpi')) dpi = save_dpi or 80 fig = plt.figure(figsize=(mw + fw + 1, 15), facecolor='w', edgecolor='k', dpi=dpi, frameon=True) gs = gridspec.GridSpec(h, mw + fw + 1) # Left-hand column. header = fig.add_subplot(gs[0:1, 0:mw / 2]) description = fig.add_subplot(gs[1:3, 0:mw / 2]) locmap = fig.add_subplot(gs[0:3, mw / 2:mw]) # Aspect = 8:3 elevation = fig.add_subplot(gs[3, :mw]) xsection = fig.add_subplot(gs[4:h - n_grids, :mw]) xsec_logs = fig.add_subplot(gs[4:h - n_grids, :mw]) potfield = fig.add_subplot(gs[h - n_grids:, :mw]) # Right-hand column. log_header = fig.add_subplot(gs[0:1, -1 * fw:]) # log_plot is dealt with by passing gs to feature_plot.plot_feature_well() # Adjust white space between subplots # ------------------------------------------------------------ # left = 0.05 # left side of the subplots of the figure right = 0.95 # right side of the subplots of the figure bottom = 0.05 # bottom of the subplots of the figure top = 0.95 # top of the subplots of the figure wspace = 0.05 # blank w space between subplots hspace = 0.1 # blank h space between subplots fig.subplots_adjust(left, bottom, right, top, wspace, hspace) bbox = {'fc': 'w', 'pad': 0, 'ec': 'none', 'alpha': 0.5} props = {'ha': 'left', 'va': 'center', 'bbox': bbox} # Header # ---------------------------------------------------------# print "Header" header.axis("off") dy = 0.2 header.text(0.0, 0.5 + dy, tc.title, props, fontsize=30, horizontalalignment='left', verticalalignment='bottom') # horizontal line header.axhline(y=0.5, xmin=0, xmax=1.25, linewidth=1.5, color='k') # Subtitle header.text(1.0, 0.5 + dy, (tc.subtitle), fontsize=15, horizontalalignment='right', verticalalignment='bottom', weight='bold') descr = tc.description if tc.meta: description.text(0, 1.0, tc.domain.upper(), horizontalalignment='left', verticalalignment='bottom', fontsize=14) description.text(1.0, 1.0, tc.velocity, horizontalalignment='right', verticalalignment='bottom', fontsize=12) descr_pos = 0.8 # Where to position the rest. else: descr_pos = 1.0 # Paragraph description # -----------------------------------------------------# description.text(0, descr_pos, descr, horizontalalignment='left', verticalalignment='top', fontsize=12, family='serif') description.axis('off') # Wrap text fig.canvas.mpl_connect('draw_event', lambda event: on_draw(event, description)) # Map # ---------------------------------------------------------# print "Locmap" tx, ty = tc.data.coords.xy res = 'h' # c, l, i, h, f # Generate Basemap object. m = Basemap(projection='tmerc', lon_0=tc.locmap.mid.x, lat_0=tc.locmap.mid.y, resolution=res, llcrnrlon=tc.locmap.ll.x, llcrnrlat=tc.locmap.ll.y, urcrnrlon=tc.locmap.ur.x, urcrnrlat=tc.locmap.ur.y, ax=locmap) # Finish drawing the basemap. draw_basemap(m, tc) for layer, details in tc.locmap.layers.items(): data = getattr(tc.locmap, layer) for l in data: line_t = utils.utm2lola(l) params = details.get('params', None) if params: plot_line(m, line_t, **params) else: plot_line(m, line_t, colour='k', alpha=0.5) if layer == "wells": for p in data: point_t = utils.utm2lola(p) params = details.get('params', None) if params: plot_point(m, point_t, zorder=100, **params) else: plot_point(m, point_t, zorder=100, colour='k', alpha=0.5) lo, la = point_t.xy x, y = m(lo, la) # Plot the names of wells in the xsection # When we have names we can also plot special symbol # for the feature well. # Plot this transect line line_t = utils.utm2lola(tc.data) plot_line(m, line_t, colour='r', lw=3) # Adjust border thickness [i.set_linewidth(8) for i in locmap.spines.itervalues()] [i.set_color("white") for i in locmap.spines.itervalues()] # Elevation and bedrock plot # -----------------------------------------------------------# print "Elevation" for i, geo in enumerate(tc.bedrock.data[:-1]): lim1 = tc.bedrock.coords[i] lim2 = tc.bedrock.coords[i + 1] idx = np.where( np.logical_and(tc.elevation.coords >= lim1, tc.elevation.coords <= lim2))[0] if len(idx) > 1: if idx[-1] < tc.elevation.coords.size - 1: idx = np.append(idx, (idx[-1] + 1)) hsv = np.array([[geo["AV_HUE"], geo["AV_SAT"], geo["AV_VAL"]]]).reshape(1, 1, 3) color = hsv_to_rgb(hsv / 255.) elevation.bar(tc.elevation.coords[idx], tc.elevation.data[idx], width=1.0, linewidth=0, color=color.flatten()) elevation.plot(tc.elevation.coords[idx], tc.elevation.data[idx], lw=0.5, color='k') max_height = np.amax(tc.elevation.all_data) elevation.set_ylim((0, max_height)) elevation.set_xlim(tc.extents[:2]) elevation.set_yticks([0, int(max_height), int(np.amax(tc.elevation.data))]) elevation.set_xticklabels([]) elevation.tick_params(axis='y', which='major', labelsize=8) elevation.patch.set_alpha(0.1) elevation.set_ylabel("Elevation [m]", fontsize=8) elevation.grid(True) elevation.tick_params(axis='x', which='major', labelsize=0) elevation.xaxis.grid(True, which='major') elevation.text(0.01, 0.8, "Elevation", props, va='bottom', fontsize=11, weight='bold', transform=elevation.transAxes) elevation.text(0.01, 0.75, "Surface geology", props, va='top', fontsize=10, transform=elevation.transAxes) elevation.set_frame_on(False) for tick in elevation.get_xaxis().get_major_ticks(): tick.set_pad(-8.) tick.label1 = tick._get_text1() # Seismic cross section # ------------------------------------------------------------# print "Seismic" for coords, data in zip(tc.seismic.coords, tc.seismic.data): max_z = data["traces"].shape[0] * data["sample_interval"] im = xsection.imshow(data["traces"], extent=[ np.amin(coords) / 1000.0, np.amax(coords) / 1000.0, max_z, 0 ], aspect="auto", cmap=tc.seismic_cmap) # Horizons colours = ['b', 'g', 'orange', 'c', 'magenta', 'pink'] for i, (horizon, data) in enumerate(tc.horizons.data.items()): coords = tc.horizons.coords[horizon] xsection.scatter(coords / 1000, data, color=colours[i], marker='.') # labels xsection.text(0.01, 0.025 * (i + 1), horizon, transform=xsection.transAxes, ha='left', color=colours[i], va='center', fontsize=12) # Axes etc. plot_axis = [ tc.extents[0] / 1000., tc.extents[1] / 1000., tc.extents[2], tc.extents[3] ] xsection.axis(plot_axis) xsection.set_xticklabels([]) if tc.domain.lower() in ['depth', 'd', 'z']: xsection.set_ylabel("Depth [m]", fontsize=8) else: xsection.set_ylabel("TWTT [ms]", fontsize=8) xsection.tick_params(axis='y', which='major', labelsize=8) xsection.tick_params(axis='x', which='major', labelsize=0) xsection.yaxis.grid(True, which='major') xsection.xaxis.grid(True, which='major') xsection.set_frame_on(False) # Seismic colorbar colorbar_ax = add_subplot_axes(xsection, [0.975, 0.025, 0.01, 0.1]) fig.colorbar(im, cax=colorbar_ax) colorbar_ax.text(0.5, 0.9, "+", transform=colorbar_ax.transAxes, ha='center', color='white', va='center', fontsize=12) colorbar_ax.text(0.5, 0.15, "-", transform=colorbar_ax.transAxes, color='k', ha='center', va='center', fontsize=16) colorbar_ax.set_axis_off() # Title xsection.text(0.01, 0.99, "Seismic", color='k', ha='left', va='top', fontsize=12, weight='bold', transform=xsec_logs.transAxes) # Potential field data # -----------------------------------------------------------# print "Potfields" for i, (field, payload) in enumerate(tc.potfield.data.items()): bot = 1 - (i + 1.) / n_grids height = (1. / n_grids) - 0.05 rect = [0, bot, 1, height] this_ax = add_subplot_axes(potfield, rect) sc = this_ax.scatter(payload['coords'], payload['data'], c=payload['colour'], cmap=payload['cmap'], s=1, edgecolor='', vmin=-50, vmax=150) this_ax.set_xlim(tc.extents[:2]) this_ax.set_frame_on(False) this_ax.set_xticks([]) this_ax.tick_params(axis='y', which='major', labelsize=8) this_ax.grid(True) scale = payload['scale'] if scale: this_ax.set_ylim(float(scale[1]), float(scale[0])) if payload['colour_is_file']: tcol = '#555555' else: tcol = payload['colour'] this_ax.text(0.01, 0.01, field, ha='left', va='bottom', fontsize=10, color=tcol, transform=this_ax.transAxes) # potfield colorbar # TODO: This doesn't work. if payload.get('cmap'): # pf_cbar_ax = add_subplot_axes(this_ax, [0.975, 0.1, 0.01, 0.8]) # fig.colorbar(sc, cax=pf_cbar_ax) # pf_cbar_ax.set_axis_off() pass potfield.axis(plot_axis) potfield.set_frame_on(False) potfield.set_yticks([]) potfield.xaxis.grid(True, which='major') potfield.tick_params(axis='x', which='major', labelsize=10) potfield.set_xlabel("Transect range [km]", fontsize=10, ha='center') potfield.text(0.01, 1.0, "Potential fields", ha='left', va='top', fontsize=11, weight='bold', color='k', transform=potfield.transAxes) # Log overlays # --------------------------------------------------------# print "Logs" if tc.locmap.layers.get('wells'): if tc.locmap.layers['wells'].get('colour'): well_colour = tc.locmap.layers['wells']['colour'] else: well_colour = tc.settings.get('default_colour') if not well_colour: well_colour = 'k' c = tc.seismic_log_colour for name, las, pos in zip(tc.log.names, tc.log.data, tc.log.coords): if name == tc.feature_well: alpha, lw = 0.5, 1.5 weight = 'bold' else: alpha, lw = 0.25, 1.0 weight = 'normal' if las: data = np.nan_to_num(las.data[tc.seismic_log]) data /= np.amax(data) z = las.data['DEPT'] if tc.domain.lower() in ['time', 'twt', 'twtt', 't']: dt = 0.001 data = tc.seismic.velocity.depth2time(data, pos, dz=z, dt=dt) start = tc.seismic.velocity.depth2timept(las.start, pos) z = np.arange(0, len(data), 1) + 1000 * start # ms # Some post-processing for display lgsc = 0.015 # hack to compress the log width data *= lgsc * (tc.extents[1] - tc.extents[0]) if data.size > 0: data += pos - 0.5 * np.amax(data) xsec_logs.axvline(x=pos, color=well_colour, alpha=alpha, lw=lw, ymin=0, ymax=z[-1]) xsec_logs.plot(data, z, c, lw=0.5, alpha=0.75) else: # Need to get TD from SHP or well header sheet. z = [tc.extents[2] - 40] xsec_logs.axvline(x=pos, color=well_colour, alpha=0.25) elevation.axvline(x=pos, color=well_colour, alpha=alpha, lw=lw) potfield.axvline(x=pos / 1000, color=well_colour, alpha=alpha, lw=lw) # Well name annotation elevation.text(pos, max_height - 10, name, color=well_colour, va='top', ha='center', fontsize=10, weight=weight) xsec_logs.set_xlim((tc.extents[0], tc.extents[1])) xsec_logs.set_ylim((tc.extents[2], tc.extents[3])) xsec_logs.axis("off") # Log type annotation, top left xsec_logs.text(0.01, 0.965, tc.seismic_log + ' log', color=c, ha='left', va='top', fontsize=12, transform=xsec_logs.transAxes) # Feature plot # -----------------------------------------------------# if tc.feature_well: print "Feature well:", tc.feature_well log_header.text(0.0, 1.0, ("Well " + tc.feature_well), verticalalignment='top', horizontalalignment='left', fontsize=14, fontweight='bold') # horizontal line log_header.axhline(y=0.5, xmin=0, xmax=1.25, linewidth=1, color='k') plot_feature_well(tc, gs) else: Notice.warning("No feature well") log_header.axis("off") # Logo etc. # --------------------------------------------------------------# print "Logo" try: path = os.path.join(tc.data_dir, tc.settings['logo_file']) im = Image.open(path) im.thumbnail((fig.dpi, fig.dpi), Image.ANTIALIAS) except IOError: print "Image is missing", path im = np.zeros((1, 1, 3)) w, h = im.size # We need a float array between 0-1, rather than # a uint8 array between 0-255 im = np.array(im).astype(np.float) / 255 # With newer (1.0) versions of matplotlib, you can # use the "zorder" kwarg to make the image overlay # the plot, rather than hide behind it... (e.g. zorder=10) fig.figimage(im, (0.95 * fig.bbox.xmax) - w, (0.96 * fig.bbox.ymax) - h) # Annotate config file and creation date plt.figtext(0.950, 0.030, tc.time, ha="right", va="bottom", color="gray", size=8) plt.figtext(0.950, 0.04, tc.config_file, ha="right", va="bottom", color="gray", size=8) year = datetime.datetime.now().year text = "$\copyright$ {} Department of Energy".format(year) plt.figtext(0.750, 0.03, text, ha="left", va="bottom", color="gray", size=8) # Finish # --------------------------------------------------------------# save_file = getattr(tc, 'save_file', None) if save_file: if type(save_file) != 'str': # Then it's probably a bool from 'yes' or 'true' in the config save_file = tc.config_file.split('.')[0] + '.png' if save_file == 'config.png': save_file = 'temp.png' Notice.ok("Saving file " + save_file + "...", hold=True) plt.savefig(save_file, dpi=fig.dpi) Notice.ok("Done") Notice.warning("The displayed image is not identical to the saved one") plt.show() else: plt.show()
def plot(tc): """ Constructs a multi-subplot matplotlib figure. Args: transect (TransectContainer): A transect container. """ h = 15 mw = 16 # width of main section (inches) must be div by 4 fw = 5 # width of the feature plot (inches) must be div by 5 n_grids = len(tc.potfield.data) # We will save the same figure we make, to ensure the saved figure # has everything in the right places. For example, see this discussion: # http://stackoverflow.com/questions/7906365/ save_dpi = getattr(tc, 'save_dpi', tc.settings.get('default_dpi')) dpi = save_dpi or 80 fig = plt.figure(figsize=(mw + fw + 1, 15), facecolor='w', edgecolor='k', dpi=dpi, frameon=True) gs = gridspec.GridSpec(h, mw + fw + 1) # Left-hand column. header = fig.add_subplot(gs[0:1, 0:mw/2]) description = fig.add_subplot(gs[1:3, 0:mw/2]) locmap = fig.add_subplot(gs[0:3, mw/2:mw]) # Aspect = 8:3 elevation = fig.add_subplot(gs[3, :mw]) xsection = fig.add_subplot(gs[4:h-n_grids, :mw]) xsec_logs = fig.add_subplot(gs[4:h-n_grids, :mw]) potfield = fig.add_subplot(gs[h-n_grids:, :mw]) # Right-hand column. log_header = fig.add_subplot(gs[0:1, -1*fw:]) # log_plot is dealt with by passing gs to feature_plot.plot_feature_well() # Adjust white space between subplots # ------------------------------------------------------------ # left = 0.05 # left side of the subplots of the figure right = 0.95 # right side of the subplots of the figure bottom = 0.05 # bottom of the subplots of the figure top = 0.95 # top of the subplots of the figure wspace = 0.05 # blank w space between subplots hspace = 0.1 # blank h space between subplots fig.subplots_adjust(left, bottom, right, top, wspace, hspace) bbox = {'fc': 'w', 'pad': 0, 'ec': 'none', 'alpha': 0.5} props = {'ha': 'left', 'va': 'center', 'bbox': bbox} # Header # ---------------------------------------------------------# print "Header" header.axis("off") dy = 0.2 header.text(0.0, 0.5 + dy, tc.title, props, fontsize=30, horizontalalignment='left', verticalalignment='bottom' ) # horizontal line header.axhline(y=0.5, xmin=0, xmax=1.25, linewidth=1.5, color='k') # Subtitle header.text(1.0, 0.5 + dy, (tc.subtitle), fontsize=15, horizontalalignment='right', verticalalignment='bottom', weight='bold') descr = tc.description if tc.meta: description.text(0, 1.0, tc.domain.upper(), horizontalalignment='left', verticalalignment='bottom', fontsize=14 ) description.text(1.0, 1.0, tc.velocity, horizontalalignment='right', verticalalignment='bottom', fontsize=12 ) descr_pos = 0.8 # Where to position the rest. else: descr_pos = 1.0 # Paragraph description # -----------------------------------------------------# description.text(0, descr_pos, descr, horizontalalignment='left', verticalalignment='top', fontsize=12, family='serif' ) description.axis('off') # Wrap text fig.canvas.mpl_connect('draw_event', lambda event: on_draw(event, description)) # Map # ---------------------------------------------------------# print "Locmap" tx, ty = tc.data.coords.xy res = 'h' # c, l, i, h, f # Generate Basemap object. m = Basemap(projection='tmerc', lon_0=tc.locmap.mid.x, lat_0=tc.locmap.mid.y, resolution=res, llcrnrlon=tc.locmap.ll.x, llcrnrlat=tc.locmap.ll.y, urcrnrlon=tc.locmap.ur.x, urcrnrlat=tc.locmap.ur.y, ax=locmap) # Finish drawing the basemap. draw_basemap(m, tc) for layer, details in tc.locmap.layers.items(): data = getattr(tc.locmap, layer) for l in data: line_t = utils.utm2lola(l) params = details.get('params', None) if params: plot_line(m, line_t, **params) else: plot_line(m, line_t, colour='k', alpha=0.5) if layer == "wells": for p in data: point_t = utils.utm2lola(p) params = details.get('params', None) if params: plot_point(m, point_t, zorder=100, **params) else: plot_point(m, point_t, zorder=100, colour='k', alpha=0.5) lo, la = point_t.xy x, y = m(lo, la) # Plot the names of wells in the xsection # When we have names we can also plot special symbol # for the feature well. # Plot this transect line line_t = utils.utm2lola(tc.data) plot_line(m, line_t, colour='r', lw=3) # Adjust border thickness [i.set_linewidth(8) for i in locmap.spines.itervalues()] [i.set_color("white") for i in locmap.spines.itervalues()] # Elevation and bedrock plot # -----------------------------------------------------------# print "Elevation" for i, geo in enumerate(tc.bedrock.data[:-1]): lim1 = tc.bedrock.coords[i] lim2 = tc.bedrock.coords[i + 1] idx = np.where(np.logical_and(tc.elevation.coords >= lim1, tc.elevation.coords <= lim2))[0] if len(idx) > 1: if idx[-1] < tc.elevation.coords.size - 1: idx = np.append(idx, (idx[-1] + 1)) hsv = np.array([[geo["AV_HUE"], geo["AV_SAT"], geo["AV_VAL"]]]).reshape(1, 1, 3) color = hsv_to_rgb(hsv / 255.) elevation.bar(tc.elevation.coords[idx], tc.elevation.data[idx], width=1.0, linewidth=0, color=color.flatten()) elevation.plot(tc.elevation.coords[idx], tc.elevation.data[idx], lw=0.5, color='k') max_height = np.amax(tc.elevation.all_data) elevation.set_ylim((0, max_height)) elevation.set_xlim(tc.extents[:2]) elevation.set_yticks([0, int(max_height), int(np.amax(tc.elevation.data))]) elevation.set_xticklabels([]) elevation.tick_params(axis='y', which='major', labelsize=8) elevation.patch.set_alpha(0.1) elevation.set_ylabel("Elevation [m]", fontsize=8) elevation.grid(True) elevation.tick_params(axis='x', which='major', labelsize=0) elevation.xaxis.grid(True, which='major') elevation.text(0.01, 0.8, "Elevation", props, va='bottom', fontsize=11, weight='bold', transform=elevation.transAxes) elevation.text(0.01, 0.75, "Surface geology", props, va='top', fontsize=10, transform=elevation.transAxes) elevation.set_frame_on(False) for tick in elevation.get_xaxis().get_major_ticks(): tick.set_pad(-8.) tick.label1 = tick._get_text1() # Seismic cross section # ------------------------------------------------------------# print "Seismic" for coords, data in zip(tc.seismic.coords, tc.seismic.data): max_z = data["traces"].shape[0] * data["sample_interval"] im = xsection.imshow(data["traces"], extent=[np.amin(coords) / 1000.0, np.amax(coords) / 1000.0, max_z, 0], aspect="auto", cmap=tc.seismic_cmap) # Horizons colours = ['b', 'g', 'orange', 'c', 'magenta', 'pink'] for i, (horizon, data) in enumerate(tc.horizons.data.items()): coords = tc.horizons.coords[horizon] xsection.scatter(coords/1000, data, color=colours[i], marker='.') # labels xsection.text(0.01, 0.025*(i+1), horizon, transform=xsection.transAxes, ha='left', color=colours[i], va='center', fontsize=12) # Axes etc. plot_axis = [tc.extents[0] / 1000., tc.extents[1] / 1000., tc.extents[2], tc.extents[3]] xsection.axis(plot_axis) xsection.set_xticklabels([]) if tc.domain.lower() in ['depth', 'd', 'z']: xsection.set_ylabel("Depth [m]", fontsize=8) else: xsection.set_ylabel("TWTT [ms]", fontsize=8) xsection.tick_params(axis='y', which='major', labelsize=8) xsection.tick_params(axis='x', which='major', labelsize=0) xsection.yaxis.grid(True, which='major') xsection.xaxis.grid(True, which='major') xsection.set_frame_on(False) # Seismic colorbar colorbar_ax = add_subplot_axes(xsection, [0.975, 0.025, 0.01, 0.1]) fig.colorbar(im, cax=colorbar_ax) colorbar_ax.text(0.5, 0.9, "+", transform=colorbar_ax.transAxes, ha='center', color='white', va='center', fontsize=12) colorbar_ax.text(0.5, 0.15, "-", transform=colorbar_ax.transAxes, color='k', ha='center', va='center', fontsize=16) colorbar_ax.set_axis_off() # Title xsection.text(0.01, 0.99, "Seismic", color='k', ha='left', va='top', fontsize=12, weight='bold', transform=xsec_logs.transAxes) # Potential field data # -----------------------------------------------------------# print "Potfields" for i, (field, payload) in enumerate(tc.potfield.data.items()): bot = 1 - (i+1.)/n_grids height = (1./n_grids) - 0.05 rect = [0, bot, 1, height] this_ax = add_subplot_axes(potfield, rect) sc = this_ax.scatter(payload['coords'], payload['data'], c=payload['colour'], cmap=payload['cmap'], s=1, edgecolor='', vmin=-50, vmax=150) this_ax.set_xlim(tc.extents[:2]) this_ax.set_frame_on(False) this_ax.set_xticks([]) this_ax.tick_params(axis='y', which='major', labelsize=8) this_ax.grid(True) scale = payload['scale'] if scale: this_ax.set_ylim(float(scale[1]), float(scale[0])) if payload['colour_is_file']: tcol = '#555555' else: tcol = payload['colour'] this_ax.text(0.01, 0.01, field, ha='left', va='bottom', fontsize=10, color=tcol, transform=this_ax.transAxes) # potfield colorbar # TODO: This doesn't work. if payload.get('cmap'): # pf_cbar_ax = add_subplot_axes(this_ax, [0.975, 0.1, 0.01, 0.8]) # fig.colorbar(sc, cax=pf_cbar_ax) # pf_cbar_ax.set_axis_off() pass potfield.axis(plot_axis) potfield.set_frame_on(False) potfield.set_yticks([]) potfield.xaxis.grid(True, which='major') potfield.tick_params(axis='x', which='major', labelsize=10) potfield.set_xlabel("Transect range [km]", fontsize=10, ha='center') potfield.text(0.01, 1.0, "Potential fields", ha='left', va='top', fontsize=11, weight='bold', color='k', transform=potfield.transAxes) # Log overlays # --------------------------------------------------------# print "Logs" if tc.locmap.layers.get('wells'): if tc.locmap.layers['wells'].get('colour'): well_colour = tc.locmap.layers['wells']['colour'] else: well_colour = tc.settings.get('default_colour') if not well_colour: well_colour = 'k' c = tc.seismic_log_colour for name, las, pos in zip(tc.log.names, tc.log.data, tc.log.coords): if name == tc.feature_well: alpha, lw = 0.5, 1.5 weight = 'bold' else: alpha, lw = 0.25, 1.0 weight = 'normal' if las: data = np.nan_to_num(las.data[tc.seismic_log]) data /= np.amax(data) z = las.data['DEPT'] if tc.domain.lower() in ['time', 'twt', 'twtt', 't']: dt = 0.001 data = tc.seismic.velocity.depth2time(data, pos, dz=z, dt=dt) start = tc.seismic.velocity.depth2timept(las.start, pos) z = np.arange(0, len(data), 1) + 1000*start # ms # Some post-processing for display lgsc = 0.015 # hack to compress the log width data *= lgsc * (tc.extents[1] - tc.extents[0]) if data.size > 0: data += pos - 0.5 * np.amax(data) xsec_logs.axvline(x=pos, color=well_colour, alpha=alpha, lw=lw, ymin=0, ymax=z[-1]) xsec_logs.plot(data, z, c, lw=0.5, alpha=0.75) else: # Need to get TD from SHP or well header sheet. z = [tc.extents[2]-40] xsec_logs.axvline(x=pos, color=well_colour, alpha=0.25) elevation.axvline(x=pos, color=well_colour, alpha=alpha, lw=lw) potfield.axvline(x=pos/1000, color=well_colour, alpha=alpha, lw=lw) # Well name annotation elevation.text(pos, max_height-10, name, color=well_colour, va='top', ha='center', fontsize=10, weight=weight) xsec_logs.set_xlim((tc.extents[0], tc.extents[1])) xsec_logs.set_ylim((tc.extents[2], tc.extents[3])) xsec_logs.axis("off") # Log type annotation, top left xsec_logs.text(0.01, 0.965, tc.seismic_log+' log', color=c, ha='left', va='top', fontsize=12, transform=xsec_logs.transAxes) # Feature plot # -----------------------------------------------------# if tc.feature_well: print "Feature well:", tc.feature_well log_header.text(0.0, 1.0, ("Well " + tc.feature_well), verticalalignment='top', horizontalalignment='left', fontsize=14, fontweight='bold' ) # horizontal line log_header.axhline(y=0.5, xmin=0, xmax=1.25, linewidth=1, color='k') plot_feature_well(tc, gs) else: Notice.warning("No feature well") log_header.axis("off") # Logo etc. # --------------------------------------------------------------# print "Logo" try: path = os.path.join(tc.data_dir, tc.settings['logo_file']) im = Image.open(path) im.thumbnail((fig.dpi, fig.dpi), Image.ANTIALIAS) except IOError: print "Image is missing", path im = np.zeros((1, 1, 3)) w, h = im.size # We need a float array between 0-1, rather than # a uint8 array between 0-255 im = np.array(im).astype(np.float) / 255 # With newer (1.0) versions of matplotlib, you can # use the "zorder" kwarg to make the image overlay # the plot, rather than hide behind it... (e.g. zorder=10) fig.figimage(im, (0.95*fig.bbox.xmax) - w, (0.96*fig.bbox.ymax) - h) # Annotate config file and creation date plt.figtext(0.950, 0.030, tc.time, ha="right", va="bottom", color="gray", size=8) plt.figtext(0.950, 0.04, tc.config_file, ha="right", va="bottom", color="gray", size=8) year = datetime.datetime.now().year text = "$\copyright$ {} Department of Energy".format(year) plt.figtext(0.750, 0.03, text, ha="left", va="bottom", color="gray", size=8) # Finish # --------------------------------------------------------------# save_file = getattr(tc, 'save_file', None) if save_file: if type(save_file) != 'str': # Then it's probably a bool from 'yes' or 'true' in the config save_file = tc.config_file.split('.')[0] + '.png' if save_file == 'config.png': save_file = 'temp.png' Notice.ok("Saving file "+save_file+"...", hold=True) plt.savefig(save_file, dpi=fig.dpi) Notice.ok("Done") Notice.warning("The displayed image is not identical to the saved one") plt.show() else: plt.show()