Example #1
0
    def update(self, transect):
        """
        Gather the data near the transect. Depth convert if necessary.

        Returns nothing. Side effect: sets attributes.

        Args:
            transect (LineString): A shapely LineString object.
        """
        Notice.info("Updating " + self.__class__.__name__)

        b = self.settings.get('fine_buffer') or self.settings['buffer']
        prepared = prep(transect.buffer(b))

        for horizon, points in self.lookup.items():
            l = len(points)
            points = filter(prepared.contains, points)
            print horizon, len(points), "of", l, "points"
            data, coords = [], []
            for p in points:
                coords.append(transect.project(p))
                if self.domain.lower() in ['depth', 'd', 'z']:
                    "Depth converting horizon"
                    zpt = self.velocity.time2depthpt(p.z/1000, coords[-1])
                    data.append(zpt)
                else:
                    data.append(p.z)

            self.data[horizon] = np.array(data)
            self.coords[horizon] = np.array(coords)
Example #2
0
    def update(self, transect):
        """
        Updates the container data to a profile that intersect the
        transect line.

        Returns nothing. Sets attributes as a side effect.

        Args:
            transect (LineString): A transect line.
        """
        Notice.info("Updating " + self.__class__.__name__)

        pad = self.settings['map_padding']
        aspect = 12/3.  # I was expecting it to be 8:3.

        # Calculate the map bounds and centre.
        bounds = transect.bounds
        llx, lly, urx, ury = bounds
        w, h = urx - llx, ury - lly

        x_adj, y_adj = 0, 0
        if h > (w/aspect):
            x_adj = ((aspect*h) - w) / 2.  # Aspect is hard-coded in uberplot
        else:
            y_adj = ((w/aspect) - h) / 2.

        utm_nad83 = pp.Proj("+init=EPSG:26920")
        ll_nad83 = pp.Proj("+proj=longlat +ellps=GRS80 +datum=NAD83 +no_defs")
        utm2lola = partial(pp.transform, utm_nad83, ll_nad83)

        ll = transform(utm2lola, Point(llx-pad-x_adj, lly-pad-y_adj))
        ur = transform(utm2lola, Point(urx+pad+x_adj, ury+pad+y_adj))
        self.ll, self.ur = ll, ur
        self.mid = Point(ll.x + 0.5*(ur.x-ll.x), ll.y + 0.5*(ur.y - ll.y))

        # Go over the layers and collect data.
        for layer, details in self.layers.items():
            path = details['file']
            print layer, path

            # Set up convenient params dictionary for plotting function.
            params = {k: v for k, v in details.items() if k != 'file'}
            self.layers[layer]['params'] = params

            # Get a list of shapes from the file.
            shapes = []
            fname, ext = os.path.splitext(os.path.basename(path))
            if ext.strip('.').lower() in self.settings['raster_extensions']:
                # TODO: Deal with rasters.
                pass
            elif ext.strip('.').lower() == 'shp':
                with fiona.open(path) as c:
                    for s in c:
                        shapes.append(shape(s['geometry']))
                        # name = s.get('name') or s.get('id') or None
                        # data = {name: shape(s['geometry'])}
                        # setattr(self, 'data', data)
                setattr(self, layer, shapes)
            else:
                pass
def insert(root = None):
	logging.debug("called : %s", __name__)
	logging.debug("argument root : %s", root)

	if root is None:
		logging.debug("empty root is received")
		root = os.path.abspath(os.path.dirname(__file__)) + "/gen/json"
	if not os.path.isdir(root):
		logging.debug("making directory : %s", root)
		os.makedirs(root)

	notices = extract.get_notice_list(False)
	if notices is None:
		logging.error("error getting notice list")
		return None
	count = 0
	for notice in notices:
		timestamp = str(notice['timestamp'])
		path = root + '/' + timestamp + '.json'
		if os.path.isfile(path):
			continue;
		else:
			count += 1
			print "Saved notice dated '{}' titled '{}'.".format(notice['time'], notice['title'])
			logging.info("Saved notice dated %s titled %s",
					notice['time'], notice['title'])

			n = Notice(timestamp)
			n.save_json(notice)

	logging.info("%d notices inserted", count)
	return count
Example #4
0
    def update(self, transect):
        """
        Updates the container data to a profile that intersect the
        transect line.

        Returns nothing. Sets attributes as a side effect.

        Args:
            transect (LineString): A transect line.
        """
        Notice.info("Updating " + self.__class__.__name__)

        for name, payload in self.data.items():
            print name
            payload['coords'] = self.linspace
            payload['data'] = np.zeros_like(self.linspace)
            if payload['colour_is_file']:
                payload['colour'] = np.zeros_like(self.linspace)
            else:
                payload['colour'] = payload['all_colour']

            for i in self.linspace:
                i = int(i)
                x, y = transect.interpolate(i).xy
                xi = np.abs(payload['all_coords'][0][0, :] - x).argmin()
                yi = np.abs(payload['all_coords'][1][:, 0] - y).argmin()

                payload['data'][i] = payload['all_data'][yi, xi]
                if payload['colour_is_file']:
                    try:
                        payload['colour'][i] = payload['all_colour'][yi, xi]
                    except IndexError:
                        payload['colour'][i] = 0

            self.data[name] = payload
def send_name(filename):
	'''Send the notification for the notice of given json filename'''
	logging.debug("called : %s", __name__)
	logging.debug("argument filename : %s", filename)

	if filename is None:
		logging.error("empty filename received")
		return

	n = Notice(filename)
	notice = n.get_json()

	# If the notice is not updated, update it.
	logging.debug("checking if notice is updated")
	if not notice['updated']:
		update.update_json(filename)
		notice = n.get_json()

	# If the notice is not sent, send it.
	logging.debug("checking if notice is sent")
	if not notice['sent']:
		if send_json(notice):
			# If notice is sent, save it locally. So that it is not
			# sent again.
			logging.debug("notice is sent - saving it locally")
			notice['sent'] = True
			n.save_json(notice)
			return True
		else:
			logging.error("failed sending notice")
			return False
	else:
		logging.debug("notice is already sent")
		return False
Example #6
0
    def update(self, transect):
        """
        Updates the container data to a profile that intersect the
        transect line.

        Returns nothing. Sets attributes as a side effect.

        Args:
            transect (LineString): A transect line.
        """
        Notice.info("Updating " + self.__class__.__name__)

        self.reset_data()

        points = [Point(xy) for xy in transect.coords]
        for polygon, properties in self.lookup.items():
            for p in filter(polygon.contains, points):
                self.data.append(properties)
                self.coords.append(transect.project(p))

        # Sort the data to be in order
        idx = sorted(range(len(self.coords)),
                     key=lambda k: self.coords[k])

        self.data = [self.data[i] for i in idx]
        self.coords = np.array([self.coords[i] for i in idx])
def get_text_path(path):
	"""
	Given path to json file, return a formatted body string with all the details
	"""
	logging.debug("called : %s", __name__)
	logging.debug("argument path : ", path)
	n = Notice(path)
	notice = n.get_json()
	return get_text_dict(notice)
Example #8
0
    def update(self, transect):
        """
        Updates the container data to a profile that intersect the
        transect line.

        Returns nothing. Sets attributes as a side effect.

        Args:
            transect (LineString): A transect line.
        """
        Notice.info("Updating " + self.__class__.__name__)

        # Preprocess
        prepared = prep(transect.buffer(self.settings['buffer']))

        # Get the intersecting points
        points = filter(prepared.contains, self.lookup.keys())

        self.reset_data()
        self.names = []

        for point in points:
            name = self.lookup[point]
            self.names.append(name)
            print name,

            pattern = "^" + name + "_out.las"
            for fname in utils.walk(self.well_dir, pattern):
                # This is a loop but there should only be one matching file.
                well = Well(fname, null_subs=np.nan)
                print well.curves.names
                self.data.append(well)
                self.log_lookup[name] = self.data[-1]

            if not self.log_lookup.get(name):
                print
                self.data.append(None)

            sl_name = getattr(self, 'striplog', None)
            sl = None
            if sl_name and (name == self.feature_well):
                lexicon = Lexicon.default()
                pattern = "^" + name + ".*striplog.las"
                for fname in utils.walk(self.well_dir, pattern):
                    # Load the striplog.
                    sl = Well(fname, lexicon=lexicon, null_subs=np.nan)

                    # Add it to the well
                    self.log_lookup[name].add_striplog(sl.striplog[sl_name],
                                                       sl_name)

            self.coords.append(transect.project(point))
def sent_false():
	logging.debug('called : sent_false')
	root = os.path.abspath(os.path.dirname(__file__))
	path = root + '/gen/json/'
	listfile = os.listdir(path)
	if 'old' in listfile:
		listfile.remove('old')
	for fl in listfile:
		n = Notice(fl)
		notice = n.get_json()
		if not notice['sent']:
			notice['sent'] = True
			n.save_json(notice)
Example #10
0
    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 update_json(name):
    logging.debug("called : %s", __name__)
    logging.debug("argument name : %s", name)

    path = jsondir + name
    if not os.path.isfile(path):
        logging.error("json file '%s' is not present.", path)
        return

    n = Notice(name)
    notice = n.get_json()

    # If the json is erroneous, i.e, has empty fields like topic etc, start
    # fresh by removing the json file. This way the json will be reloaded at
    # next cron update.
    if erroneous_json(notice):
        logging.error("Encountered errnoneous json %s. Deleting.", str(path))
        os.remove(path)
        return False

        # If notice is updated, do not update it once more.
    if notice["updated"]:
        logging.info("notice %s is already updated", name)
        return False

    details = get_details_url(notice["url"], notice["num_attachments"] == 1)

    logging.debug("Notice has been updated with information from the notice	page")
    notice["updated"] = True
    notice["text"] = details["text"]
    if notice["num_attachments"] == 1:
        notice["attachments"] = details["attachments"]
        notice["num_attachments"] = len(details["attachments"])

    logging.debug("Saving the updated notice")
    n.save_json(notice)

    return True
Example #12
0
    def plot(self):
        """
        Generates plot for the transect.
        """

        # Set the extent to the length? Or keep them all the same?
        self.extents[0] = 0
        self.extents[1] = self.data.length

        Notice.hr_header("Updating")
        # update the containers
        self.velocity.update(self.data)
        self.log.update(self.data)
        self.seismic.update(self.data)
        self.horizons.update(self.data)
        self.elevation.update(self.data)
        self.bedrock.update(self.data)
        self.potfield.update(self.data)
        self.locmap.update(self.data)

        Notice.hr_header("Plotting")
        plot(self)
        plt.show()
Example #13
0
    def update(self, transect):
        """
        Updates the container data to a profile that intersect the
        transect line.

        Returns nothing. Sets attributes as a side effect.

        Args:
            transect (LineString): A transect line.
        """
        Notice.info("Updating " + self.__class__.__name__)

        # space = np.linspace(0, transect.length, self.nsamples)
        for i, n in enumerate(self.linspace):

            # interpolate along the transect
            x, y = transect.interpolate(n).xy

            # Get the closest elevation points
            xi = np.abs(self.all_coords[0][0, :] - x).argmin()
            yi = np.abs(self.all_coords[1][:, 0] - y).argmin()

            self.data[i] = self.all_data[yi, xi]
Example #14
0
    def __init__(self, **kwargs):

        Notice.title()
        Notice.hr_header("Initializing")

        params = kwargs.get('params')
        layers = kwargs.get('layers')
        potfields = kwargs.get('potfields')
        data = kwargs.get('data')
        velocity = kwargs.get('velocity')

        super(TransectContainer, self).__init__(params)

        print "Starting {}, id {}, file {}".format(self.title,
                                                   self.id,
                                                   self.config_file)

        # Set up 'data' — the transect line — from shapefile.
        self.data = None
        with fiona.open(data['transect_file']) as c:
            for line in c:
                if line['properties']['id'] == self.id:
                    self.data = shape(line['geometry'])
        if not self.data:
            Notice.fail("No transect with ID "+self.id)

        # self.data.length holds the length of the transect in metres
        # But often we want ints, and sometimes the number of samples.
        # This will give us a nice linspace. Put them in params.
        params['length'] = self.length = int(np.floor(self.data.length))
        params['nsamples'] = self.nsamples = self.length + 1
        params['linspace'] = self.linspace = np.linspace(0, self.length,
                                                         self.nsamples)

        self.time = time.strftime("%Y/%m/%d %H:%M", time.localtime())
        self.tops_file = data['tops_file']
        self.log = LogContainer(data['well_dir'], params)
        self.velocity = self.__velocity_factory(velocity, params)
        self.seismic = SeismicContainer(data['seismic_dir'],
                                        self.velocity,
                                        params)
        self.horizons = HorizonContainer(data['horizon_dir'],
                                         self.velocity,
                                         params)
        self.elevation = ElevationContainer(data['elevation_file'], params)
        self.bedrock = BedrockContainer(data['bedrock_dir'], params)
        self.potfield = PotfieldContainer(potfields, params)
        self.locmap = LocmapContainer(layers, params)
Example #15
0
def main(target, cfg):
    """
    Puts everything together.
    """
    t0 = time.time()

    # Read the file.
    section = readSEGY(target, unpack_headers=True)

    # Calculate some things.
    # NB Getting nsamples and dt from the first trace assumes that all
    # traces are the same length, which is not a safe assumption in SEGY v2.
    ninlines = section.traces[-1].header.trace_sequence_number_within_line
    last_tr = section.traces[-1].header.trace_sequence_number_within_segy_file
    nxlines = last_tr / ninlines

    nsamples = section.traces[0].header.number_of_samples_in_this_trace
    dt = section.traces[0].header.sample_interval_in_ms_for_this_trace
    ntraces = len(section.traces)
    tbase = 0.001 * np.arange(0, nsamples * dt, dt)
    tstart = 0
    tend = np.amax(tbase)

    # Make the data array.
    data = np.vstack([t.data for t in section.traces]).T

    threed = False
    if nxlines > 1:  # Then it's a 3D and `data` is an ensemble.
        threed = True
        cube = np.reshape(data.T, (ninlines, nxlines, nsamples))
        l = cfg['number']
        if cfg['direction'].lower()[0] == 'i':
            direction = 'inline'
            ntraces = nxlines
            l *= ninlines if (l < 1) else 1
            data = cube[l, :, :].T
        else:
            direction = 'xline'
            ntraces = ninlines
            l *= nxlines if (l < 1) else 1
            data = cube[:, l, :].T

    # Collect some other data. Use a for loop because there are several.
    elev, esp, ens, tsq = [], [], [], []
    for i, trace in enumerate(section.traces):
        elev.append(trace.header.receiver_group_elevation)
        esp.append(trace.header.energy_source_point_number)
        tsq.append(trace.header.trace_sequence_number_within_line)

        if threed:
            trs = []
            if direction == 'inline':
                cdp_label_text = 'Crossline number'
                trace_label_text = 'Trace number'
                ens.append(trace.header.for_3d_poststack_data_this_field_is_for_cross_line_number)
                trs.append(trace.header.for_3d_poststack_data_this_field_is_for_in_line_number)
            else:
                cdp_label_text = 'Inline number'
                trace_label_text = 'Trace number'
                ens.append(trace.header.for_3d_poststack_data_this_field_is_for_in_line_number)
                trs.append(trace.header.for_3d_poststack_data_this_field_is_for_cross_line_number)
            line_no = min(trs)
        else:
            cdp_label_text = 'CDP number'
            trace_label_text = 'Trace number'
            ens.append(trace.header.ensemble_number)
        min_tr, max_tr = 0, ntraces

    traces = (min_tr, max_tr)

    clip_val = np.percentile(data, cfg['percentile'])

    # Notify user of parameters
    Notice.info("n_traces   {}".format(ntraces))
    Notice.info("n_samples  {}".format(nsamples))
    Notice.info("dt         {}".format(dt))
    Notice.info("t_start    {}".format(tstart))
    Notice.info("t_end      {}".format(tend))
    Notice.info("max_val    {}".format(np.amax(data)))
    Notice.info("min_val    {}".format(np.amin(data)))
    Notice.info("clip_val   {}".format(clip_val))

    t1 = time.time()
    Notice.ok("Read data in {:.1f} s".format(t1-t0))

    #####################################################################
    #
    # MAKE PLOT
    #
    #####################################################################
    Notice.hr_header("Plotting")

    ##################################
    # Plot size parameters
    # Some constants
    fs = cfg['fontsize']
    wsl = 6  # Width of sidelabel, inches
    mih = 12  # Minimum plot height, inches
    fhh = 5  # File header box height, inches
    m = 0.5  # basic unit of margins, inches

    # Margins, CSS like: top, right, bottom, left.
    mt, mr, mb, ml = m,  2 * m, m, 2 * m
    mm = m  # padded margin between seismic and label

    # Width is determined by seismic width, plus sidelabel, plus margins.
    seismic_width = ntraces / cfg['tpi']
    w = ml + seismic_width + mm + wsl + mr  # inches

    # Height is given by ips, but with a minimum of mih inches
    seismic_height = cfg['ips'] * (tbase[-1] - tbase[0]) / 1000
    h_reqd = mb + seismic_height + mt  # inches
    h = max(mih, h_reqd)

    # Calculate where to start sidelabel and seismic data.
    # Depends on whether sidelabel is on the left or right.
    if cfg['sidelabel'] == 'right':
        ssl = (ml + seismic_width + mm) / w  # Start of side label (ratio)
        seismic_left = ml / w
    else:
        ssl = ml / w
        seismic_left = (ml + wsl + mm) / w

    adj = max(0, h - h_reqd) / 2
    seismic_bottom = (mb / h) + adj / h
    seismic_width_fraction = seismic_width / w
    seismic_height_fraction = seismic_height / h

    # Publish some notices so user knows plot size.
    Notice.info("Width of plot   {} in".format(w))
    Notice.info("Height of plot  {} in".format(h))

    ##################################
    # Make the figure.
    fig = plt.figure(figsize=(w, h), facecolor='w')

    # Add the main seismic axis.
    ax = fig.add_axes([seismic_left,
                       seismic_bottom,
                       seismic_width_fraction,
                       seismic_height_fraction
                       ])

    # make parasitic axes for labeling CDP number
    par1 = ax.twiny()
    par1.spines["top"].set_position(("axes", 1.0))
    tickfmt = mtick.FormatStrFormatter('%.0f')
    par1.plot(ens, np.zeros_like(ens))
    par1.set_xlabel(cdp_label_text, fontsize=fs-2)
    par1.set_xticklabels(par1.get_xticks(), fontsize=fs-2)
    par1.xaxis.set_major_formatter(tickfmt)

    # Plot title
    title_ax = fig.add_axes([ssl, 1-mt/h, wsl/w, mt/(h)])
    title_ax = plotter.plot_title(title_ax, target, fs=1.5*fs, cfg=cfg)
    if threed:
        title_ax.text(0.0, 0.0, '{} {}'.format(direction.title(), line_no))

    # Plot text header.
    s = section.textual_file_header.decode()
    start = (h - 1.5*mt - fhh) / h
    head_ax = fig.add_axes([ssl, start, wsl/w, fhh/h])
    head_ax = plotter.plot_header(head_ax, s, fs=fs-1, cfg=cfg)

    # Plot histogram.
    # Params for histogram plot
    pady = 0.75 / h  # 0.75 inch
    padx = 0.75 / w   # 0.75 inch
    cstrip = 0.3/h   # color_strip height = 0.3 in
    charth = 1.5/h   # height of charts = 1.5 in
    chartw = wsl/w - mr/w - padx  # or ml/w for left-hand sidelabel; same thing
    chartx = (ssl + padx)
    histy = 1.5 * mb/h + charth + pady
    # Plot colourbar under histogram
    clrbar_ax = fig.add_axes([chartx, histy - cstrip, chartw, cstrip])
    clrbar_ax = plotter.plot_colourbar(clrbar_ax, cmap=cfg['cmap'])
    # Plot histogram itself
    hist_ax = fig.add_axes([chartx, histy, chartw, charth])
    hist_ax = plotter.plot_histogram(hist_ax,
                                     data,
                                     tickfmt,
                                     percentile=cfg['percentile'],
                                     fs=fs)

    # Plot spectrum.
    specy = 1.5 * mb/h
    spec_ax = fig.add_axes([chartx, specy, chartw, charth])

    try:
        spec_ax = plotter.plot_spectrum(spec_ax,
                                        data,
                                        dt,
                                        tickfmt,
                                        ntraces=20,
                                        fontsize=fs)
    except:
        pass

    # Plot seismic data.
    if cfg['display'].lower() in ['vd', 'varden', 'variable']:
        _ = ax.imshow(data,
                      cmap=cfg['cmap'],
                      clim=[-clip_val, clip_val],
                      extent=[0, ntraces, tbase[-1], tbase[0]],
                      aspect='auto'
                      )

    elif cfg['display'].lower() == 'wiggle':
        ax = plotter.wiggle_plot(ax,
                                 data,
                                 tbase,
                                 ntraces,
                                 skip=cfg['skip'],
                                 gain=cfg['gain'],
                                 rgb=cfg['colour'],
                                 alpha=cfg['opacity'],
                                 lw=cfg['lineweight']
                                 )
        ax.set_ylim(ax.get_ylim()[::-1])

    elif cfg['display'].lower() == 'both':
        # variable density goes on first
        _ = ax.imshow(data,
                      cmap=cfg['cmap'],
                      clim=[-clip_val, clip_val],
                      extent=[0, ntraces, tbase[-1], tbase[0]],
                      aspect='auto'
                      )

        # wiggle plots go on top
        ax = plotter.wiggle_plot(ax,
                                 data,
                                 tbase,
                                 ntraces,
                                 skip=cfg['skip'],
                                 gain=cfg['gain'],
                                 rgb=cfg['colour'],
                                 alpha=cfg['opacity'],
                                 lw=cfg['lineweight']
                                 )
        # ax.set_ylim(ax.get_ylim()[::-1])

    else:
        Notice.fail("You need to specify the type of display: wiggle or vd")

    # Seismic axis annotations.
    ax = plotter.decorate_seismic(ax, traces, trace_label_text, tickfmt, cfg)

    # Watermark.
    if cfg['watermark_text']:
        Notice.info("Adding watermark")
        ax = plotter.watermark_seismic(ax, cfg)

    t2 = time.time()
    Notice.ok("Built plot in {:.1f} s".format(t2-t1))

    #####################################################################
    #
    # SAVE FILE
    #
    #####################################################################
    Notice.hr_header("Saving")

    if cfg['stain_paper'] or cfg['coffee_rings'] or cfg['distort'] or cfg['scribble']:
        stupid = True
    else:
        stupid = False

    s = "Saved image file {} in {:.1f} s"
    if cfg['outfile']:

        if os.path.isfile(cfg['outfile']):
            outfile = cfg['outfile']
        else:  # is directory
            stem, ext = os.path.splitext(os.path.split(target)[1])
            outfile = os.path.join(cfg['outfile'], stem + '.png')

        stem, _ = os.path.splitext(outfile)  # Needed for stupidity.
        fig.savefig(outfile)
        t3 = time.time()
        Notice.ok(s.format(outfile, t3-t2))
    else:  # Do the default: save a PNG in the same dir as the target.
        stem, _ = os.path.splitext(target)
        fig.savefig(stem)
        t3 = time.time()
        Notice.ok(s.format(stem+'.png', t3-t2))

    if stupid:
        fig.savefig(stem + ".stupid.png")
    else:
        return

    #####################################################################
    #
    # SAVE STUPID FILE
    #
    #####################################################################
    Notice.hr_header("Applying the stupidity")

    stupid_image = Image.open(stem + ".stupid.png")
    if cfg['stain_paper']:
        utils.stain_paper(stupid_image)
    utils.add_rings(stupid_image, cfg['coffee_rings'])
    if cfg['scribble']:
        utils.add_scribble(stupid_image)
    stupid_image.save(stem + ".stupid.png")

    s = "Saved stupid file stupid.png in {:.1f} s"
    t4 = time.time()
    Notice.ok(s.format(t4-t3))

    return
Example #16
0
        utils.stain_paper(stupid_image)
    utils.add_rings(stupid_image, cfg['coffee_rings'])
    if cfg['scribble']:
        utils.add_scribble(stupid_image)
    stupid_image.save(stem + ".stupid.png")

    s = "Saved stupid file stupid.png in {:.1f} s"
    t4 = time.time()
    Notice.ok(s.format(t4-t3))

    return


if __name__ == "__main__":

    Notice.title()
    parser = argparse.ArgumentParser(description='Plot a SEGY file.')
    parser.add_argument("-c", "--config",
                        metavar="config file",
                        type=argparse.FileType('r'),
                        default="config.yaml",
                        nargs="?",
                        help="The name of a YAML config file.")
    parser.add_argument('filename',
                        metavar='SEGY file',
                        type=str,
                        nargs='?',
                        help='The path to a SEGY file.')
    parser.add_argument('-o', '--out',
                        metavar='Output file',
                        type=str,
Example #17
0
    stupid_image = Image.open(fname)
    if cfg['stain_paper']: utils.stain_paper(stupid_image)
    utils.add_rings(stupid_image, cfg['coffee_rings'])
    if cfg['scribble']: utils.add_scribble(stupid_image)
    stupid_image.save(fname)

    t4 = time.time()
    Notice.ok("Saved stupid file {} in {:.1f} s".format(fname, t4-t3))

    return


if __name__ == "__main__":

    Notice.title()
    parser = argparse.ArgumentParser(description='Plot a SEGY file.')
    parser.add_argument("-c", "--config",
                        metavar="config file",
                        type=argparse.FileType('r'),
                        default="config.yaml",
                        nargs="?",
                        help="The name of a YAML config file. Default: config.yaml.")
    parser.add_argument('filename',
                        metavar='SEGY file',
                        type=str,
                        nargs='?',
                        help='The path to one or more SEGY files. Uses Unix-style pathname expansion.')
    parser.add_argument('-o', '--out',
                        metavar='output file',
                        type=str,
Example #18
0
def main(target, cfg):
    """
    Puts everything together.
    """
    t0 = time.time()

    # Read the file.
    section = readSEGY(target, unpack_headers=True)

    # Calculate some things
    nsamples = section.traces[0].header.number_of_samples_in_this_trace
    dt = section.traces[0].header.sample_interval_in_ms_for_this_trace
    ntraces = len(section.traces)
    tbase = 0.001 * np.arange(0, nsamples * dt, dt)
    tstart = 0
    tend = np.amax(tbase)
    wsd = ntraces / cfg['tpi']

    # Build the data container
    elev, esp, ens, tsq = [], [], [], []  # energy source point number
    data = np.zeros((nsamples, ntraces))
    for i, trace in enumerate(section.traces):
        data[:, i] = trace.data
        elev.append(trace.header.receiver_group_elevation)
        esp.append(trace.header.energy_source_point_number)
        ens.append(trace.header.ensemble_number)
        tsq.append(trace.header.trace_sequence_number_within_line)

    clip_val = np.percentile(data, 99.0)

    # Notify user of parameters
    Notice.info("n_traces   {}".format(ntraces))
    Notice.info("n_samples  {}".format(nsamples))
    Notice.info("dt         {}".format(dt))
    Notice.info("t_start    {}".format(tstart))
    Notice.info("t_end      {}".format(tend))
    Notice.info("max_val    {}".format(np.amax(data)))
    Notice.info("min_val    {}".format(np.amin(data)))
    Notice.info("clip_val   {}".format(clip_val))

    t1 = time.time()
    Notice.ok("Read data successfully in {:.1f} s".format(t1-t0))

    #####################################################################
    #
    # MAKE PLOT
    #
    #####################################################################
    Notice.hr_header("Plotting")

    ##################################
    # Plot size parameters
    # Some constants
    wsl = 6  # Width of sidelabel
    mih = 10  # Minimum plot height
    fhh = 5  # File header height
    m = 0.5  # margin in inches

    # Margins, CSS like
    mt, mb, ml, mr = m, m, 2 * m, 2 * m
    mm = mr / 2  # padded margin between seismic and label

    # Width is determined by tpi, plus a constant for the sidelabel, plus 1 in
    w = ml + wsd + wsl + mr + mm

    # Height is given by ips, but with a minimum of 8 inches, plus 1 in
    h = max(mih, cfg['ips'] * (np.amax(tbase) - np.amin(tbase)) / 1000 + mt + mb)

    # More settings
    ssl = (ml + wsd + mm) / w  # Start of side label (ratio)
    fs = cfg['fontsize']

    Notice.info("Width of plot   {} in".format(w))
    Notice.info("Height of plot  {} in".format(h))

    ##################################
    # Make the figure.
    fig = plt.figure(figsize=(w, h), facecolor='w')
    ax = fig.add_axes([ml / w, mb / h, wsd / w, (h - mb - mt) / h])

    # make parasitic axes for labeling CDP number
    par1 = ax.twiny()
    par1.spines["top"].set_position(("axes", 1.0))
    tickfmt = mtick.FormatStrFormatter('%.0f')
    par1.plot(ens, np.zeros_like(ens))
    par1.set_xlabel("CDP number", fontsize=fs-2)
    par1.set_xticklabels(par1.get_xticks(), fontsize=fs-2)
    par1.xaxis.set_major_formatter(tickfmt)

    ax = wiggle_plot(ax,
                     data,
                     tbase,
                     ntraces,
                     skip=cfg['skip'],
                     gain=cfg['gain'],
                     rgb=cfg['colour'],
                     alpha=cfg['opacity'],
                     lw=cfg['lineweight']
                     )

    ax = decorate_seismic(ax, ntraces, tickfmt, fs)

    # Plot title
    title_ax = fig.add_axes([ssl, 1-mt/h, wsl/w, mt/(2*h)])
    title_ax = plot_title(title_ax, target, fs=fs)

    # Plot text header.
    s = str(section.textual_file_header)[2:-1]
    start = (h - mt - fhh) / h
    head_ax = fig.add_axes([ssl, start, wsl/w, fhh/h])
    head_ax = plot_header(head_ax, s, fs)

    # Plot histogram.
    pad = 0.05
    charty = 0.125  # height of chart
    xhist = (ssl + pad)
    whist = (1 - ssl - (ml/w)) - 2 * pad
    hist_ax = fig.add_axes([xhist, 1.5 * mb/h + charty + pad, whist, charty])
    hist_ax = plot_histogram(hist_ax, data, fs)

    # Plot spectrum.
    spec_ax = fig.add_axes([xhist, 1.5 * mb/h, whist, charty])
    spec_ax = plot_spectrum(spec_ax, data, dt, fs)

    t2 = time.time()
    Notice.ok("Built plot in {:.1f} s".format(t2-t1))

    #####################################################################
    #
    # SAVE FILE
    #
    #####################################################################
    Notice.hr_header("Saving")
    s = "Saved image file {} in {:.1f} s"
    if cfg['outfile']:
        fig.savefig(cfg['outfile'])
        t3 = time.time()
        Notice.ok(s.format(cfg['outfile'], t3-t2))
    else:
        stem, _ = os.path.splitext(target)
        fig.savefig(stem)
        t3 = time.time()
        Notice.ok(s.format(stem+'.png', t3-t2))

    return
Example #19
0
    if cfg['outfile']:
        fig.savefig(cfg['outfile'])
        t3 = time.time()
        Notice.ok(s.format(cfg['outfile'], t3-t2))
    else:
        stem, _ = os.path.splitext(target)
        fig.savefig(stem)
        t3 = time.time()
        Notice.ok(s.format(stem+'.png', t3-t2))

    return


if __name__ == "__main__":

    Notice.title()
    parser = argparse.ArgumentParser(description='Plot a SEGY file.')
    parser.add_argument("-c", "--config",
                        metavar="config file",
                        type=argparse.FileType('r'),
                        default="config.yaml",
                        nargs="?",
                        help="The name of a YAML config file.")
    parser.add_argument('filename',
                        metavar='SEGY file',
                        type=str,
                        nargs='?',
                        help='The path to a SEGY file.')
    parser.add_argument('-o', '--out',
                        metavar='Output file',
                        type=str,
Example #20
0
def main(target, cfg):
    """
    Puts everything together.
    """
    t0 = time.time()

    #####################################################################
    #
    # READ SEGY
    #
    #####################################################################
    s = Seismic.from_segy(target, params={'ndim': cfg['ndim']})

    # Set the line and/or xline number.
    try:
        n, xl = cfg['number']
    except:
        n, xl = cfg['number'], 0.5

    # Set the direction.
    if (s.ndim) == 2:
        direction = ['inline']
    elif cfg['direction'].lower()[0] == 'i':
        direction = ['inline']
    elif cfg['direction'].lower()[0] == 'x':
        direction = ['xline']
    elif cfg['direction'].lower()[0] == 't':
        direction = ['tslice']
    else:
        direction = ['inline', 'xline']

    # Get the data.
    ss = [Seismic.from_seismic(s, n=n, direction=d) for n, d in zip((n, xl), direction)]
    data = [s.data for s in ss]

    clip_val = np.percentile(s.data, cfg['percentile'])

    # Notify user of parameters.
    Notice.info("n_traces   {}".format(s.ntraces))
    Notice.info("n_samples  {}".format(s.nsamples))
    Notice.info("dt         {}".format(s.dt))
    Notice.info("t_start    {}".format(s.tstart))
    Notice.info("t_end      {}".format(s.tend))
    Notice.info("max_val    {:.3f}".format(np.amax(s.data)))
    Notice.info("min_val    {:.3f}".format(np.amin(s.data)))
    Notice.info("clip_val   {:.3f}".format(clip_val))

    t1 = time.time()
    Notice.ok("Read data in {:.1f} s".format(t1-t0))

    #####################################################################
    #
    # MAKE PLOT
    #
    #####################################################################
    Notice.hr_header("Plotting")

    # Plot size parameters.
    fs = cfg['fontsize']
    wsl = 6  # Width of sidelabel, inches
    mih = 12  # Minimum plot height, inches
    fhh = 5  # File header box height, inches
    m = 0.5  # basic unit of margins, inches

    # Margins, CSS like: top, right, bottom, left.
    mt, mr, mb, ml = m, 2 * m, m, 2 * m
    mm = m  # padded margin between seismic and label

    # Width is determined by seismic width, plus sidelabel, plus margins.
    # Height is given by ips, but with a minimum of mih inches.
    if 'tslice' in direction:
        print('doing tslice')
        seismic_width = max([s.ninlines for s in ss]) / cfg['tpi']
        seismic_height_raw = max([s.nxlines for s in ss]) / cfg['tpi']
        print(seismic_width, seismic_height_raw)
    else:
        seismic_width = max([s.ntraces for s in ss]) / cfg['tpi']
        seismic_height_raw = cfg['ips'] * (s.tbasis[-1] - s.tbasis[0])

    w = ml + seismic_width + mm + wsl + mr  # inches
    seismic_height = len(ss) * seismic_height_raw
    h_reqd = mb + seismic_height + 0.75*(len(ss)-1) + mt  # inches
    h = max(mih, h_reqd)

    # Calculate where to start sidelabel and seismic data.
    # Depends on whether sidelabel is on the left or right.
    if cfg['sidelabel'] == 'right':
        ssl = (ml + seismic_width + mm) / w  # Start of side label (ratio)
        seismic_left = ml / w
    else:
        ssl = ml / w
        seismic_left = (ml + wsl + mm) / w

    adj = max(0, h - h_reqd) / 2
    seismic_bottom = (mb / h) + adj / h
    seismic_width_fraction = seismic_width / w
    seismic_height_fraction = seismic_height_raw / h

    # Publish some notices so user knows plot size.
    Notice.info("Width of plot   {} in".format(w))
    Notice.info("Height of plot  {} in".format(h))

    # Make the figure.
    fig = plt.figure(figsize=(w, h), facecolor='w')

    # Set the tickformat.
    tickfmt = mtick.FormatStrFormatter('%.0f')

    # Plot title.
    if cfg['filename']:
        title_ax = fig.add_axes([ssl, 1-mt/h, wsl/w, mt/h])
        title_ax = plotter.plot_title(title_ax, target, fs=1.5*fs, cfg=cfg)

    # Plot text header.
    start = (h - 1.5*mt - fhh) / h
    head_ax = fig.add_axes([ssl, start, wsl/w, fhh/h])
    head_ax = plotter.plot_header(head_ax, s.header, fs=fs-1, cfg=cfg)

    # Plot histogram.
    # Params for histogram plot.
    pady = 0.75 / h  # 0.75 inch
    padx = 0.75 / w   # 0.75 inch
    cstrip = 0.3/h   # color_strip height = 0.3 in
    charth = 1.5/h   # height of charts = 1.5 in
    chartw = wsl/w - mr/w - padx  # or ml/w for left-hand sidelabel; same thing
    chartx = (ssl + padx)
    histy = 1.5 * mb/h + charth + pady
    # Plot colourbar under histogram.
    clrbar_ax = fig.add_axes([chartx, histy - cstrip, chartw, cstrip])
    clrbar_ax = plotter.plot_colourbar(clrbar_ax, cmap=cfg['cmap'])
    # Plot histogram itself.
    hist_ax = fig.add_axes([chartx, histy, chartw, charth])
    hist_ax = plotter.plot_histogram(hist_ax,
                                     s.data,
                                     tickfmt,
                                     percentile=cfg['percentile'],
                                     fs=fs)

    # Plot spectrum.
    specy = 1.5 * mb/h
    spec_ax = fig.add_axes([chartx, specy, chartw, charth])

    try:
        spec_ax = s.plot_spectrum(ax=spec_ax,
                                  tickfmt=tickfmt,
                                  ntraces=20,
                                  fontsize=fs)
    except:
        pass

    for i, line in enumerate(ss):
        # Add the seismic axis.
        ax = fig.add_axes([seismic_left,
                           seismic_bottom + i*seismic_height_fraction + i*pady,
                           seismic_width_fraction,
                           seismic_height_fraction
                           ])

        # Plot seismic data.
        if cfg['display'].lower() in ['vd', 'varden', 'variable', 'both']:
            _ = ax.imshow(line.data.T,
                          cmap=cfg['cmap'],
                          clim=[-clip_val, clip_val],
                          extent=[0, 
                                  line.ntraces,
                                  1000*line.tbasis[-1],
                                  line.tbasis[0]],
                          aspect='auto'
                          )

            # This does not work: should cut off line at cfg['tmax']
            # ax.set_ylim(1000*cfg['tmax'] or 1000*line.tbasis[-1], line.tbasis[0])

        if cfg['display'].lower() in ['wiggle', 'both']:
            ax = line.wiggle_plot(cfg['number'], direction,
                               ax=ax,
                               skip=cfg['skip'],
                               gain=cfg['gain'],
                               rgb=cfg['colour'],
                               alpha=cfg['opacity'],
                               lw=cfg['lineweight'],
                               tmax=cfg['tmax'],
                               )

        if cfg['display'].lower() not in ['vd', 'varden', 'variable', 'wiggle', 'both']:
            Notice.fail("You must specify the type of display: wiggle, vd, both.")
            return

        # Seismic axis annotations.
        fs = cfg['fontsize'] - 2
        ax.set_xlim([0, line.data.shape[0]])
        ax.set_ylabel(line.ylabel, fontsize=fs)
        ax.set_xlabel(line.xlabel, fontsize=fs, horizontalalignment='center')
        ax.set_xticklabels(ax.get_xticks(), fontsize=fs)
        ax.set_yticklabels(ax.get_yticks(), fontsize=fs)
        ax.xaxis.set_major_formatter(tickfmt)
        ax.yaxis.set_major_formatter(tickfmt)


        # Watermark.
        if cfg['watermark_text']:
            ax = plotter.watermark_seismic(ax, cfg)

        # Make parasitic axes for labeling CDP number.
        par1 = ax.twiny()
        par1.spines["top"].set_position(("axes", 1.0))
        par1.plot(s.xlines, np.zeros_like(s.xlines))
        par1.set_xlabel(line.xlabel, fontsize=fs)
        par1.set_xticklabels(par1.get_xticks(), fontsize=fs)
        par1.xaxis.set_major_formatter(tickfmt)

    t2 = time.time()
    Notice.ok("Built plot in {:.1f} s".format(t2-t1))

    #####################################################################
    #
    # SAVE FILE
    #
    #####################################################################
    Notice.hr_header("Saving")

    dname, fname, ext = utils.path_bits(target)
    outfile = cfg['outfile'] or ''
    if not os.path.splitext(outfile)[1]:
        outfile = os.path.join(cfg['outfile'] or dname, fname + '.png')

    fig.savefig(outfile)

    t3 = time.time()
    Notice.ok("Saved image file {} in {:.1f} s".format(outfile, t3-t2))

    if cfg['stain_paper'] or cfg['coffee_rings'] or cfg['distort'] or cfg['scribble']:
        fname = os.path.splitext(outfile)[0] + ".stupid.png"
        fig.savefig(fname)
    else:
        return

    #####################################################################
    #
    # SAVE STUPID FILE
    #
    #####################################################################
    Notice.hr_header("Applying the stupidity")

    stupid_image = Image.open(fname)
    if cfg['stain_paper']: utils.stain_paper(stupid_image)
    utils.add_rings(stupid_image, cfg['coffee_rings'])
    if cfg['scribble']: utils.add_scribble(stupid_image)
    stupid_image.save(fname)

    t4 = time.time()
    Notice.ok("Saved stupid file {} in {:.1f} s".format(fname, t4-t3))

    return
Example #21
0
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()
Example #22
0
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
Example #23
0
    def update(self, transect, flat=False):
        """
        Updates the container data to a profile that intersect the
        transect line.

        Returns nothing. Sets attributes as a side effect.

        Args:
            transect (LineString): A transect line.
            flat (Bool): Reads data into a flat list instead of
                         sorting by files.
        """
        Notice.info("Updating " + self.__class__.__name__)

        self.reset_data()

        # Preprocessing
        prepared = prep(transect.buffer(self.settings['buffer']))

        # Get intersecting points
        points = filter(prepared.contains, self.lookup.keys())

        # Lookup for grouping traces into segy files
        count = 0
        file_lookup = {}
        for point in points:
            meta = self.lookup[point]
            count += 1
            f = meta["segyfile"]
            if f in file_lookup:
                proj_d = transect.project(point)
                if proj_d:
                    file_lookup[f]["pos"].append(proj_d)
                    file_lookup[f]["trace"].append(meta["trace"])
                    file_lookup[f]["point"].append(point)
            else:
                file_lookup[f] = {}
                file_lookup[f]["trace"] = [meta["trace"]]
                file_lookup[f]["pos"] = [transect.project(point)]
                file_lookup[f]["point"] = [point]

        # Read in the chunks from the segy file
        self.files = []
        for segyfile in file_lookup.keys():
            self.files.append(os.path.basename(segyfile))
            segy = readSEGY(segyfile, unpack_trace_headers=True)
            traces = file_lookup[segyfile]["trace"]
            coords = file_lookup[segyfile]["pos"]
            points = file_lookup[segyfile]["point"]

            # Get the sort order.
            idx = sorted(range(len(traces)), key=lambda k: traces[k])
            idx = filter(None, idx)

            coords = [coords[i] for i in idx]
            data = [segy.traces[traces[i]] for i in idx]

            if flat:
                self.data += data
                self.coords += coords
            else:
                self.data.append(data)
                self.coords.append(coords)