def viewTime(projData: ProjectData, startDate: str, endDate: str, **kwargs) -> Union[Figure, None]: """View timeseries in the project Parameters ---------- projData : ProjectData The project data instance startDate : str The start of the data range to plot endDate : str The end of the date range to plot sites : List[str], optional List of sites sampleFreqs : List[float], optional List of sample frequencies to plot chans : List[str], optional List of channels to plot polreverse : Dict[str, bool] Keys are channels and values are boolean flags for reversing scale : Dict[str, float] Keys are channels and values are floats to multiply the channel data by calibrate : bool, optional Boolean flag to calibrate data normalise : bool, optional Boolean flag to normalise the data. Default is False and setting to True will normalise each channel independently. notch : List[float], optional List of frequencies to notch out filter : Dict, optional Filter parameters show : bool, optional Boolean flag to show the plot save : bool, optional Boolean flag to save the plot to images folder plotoptions : Dict Dictionary of plot options Returns ------- matplotlib.pyplot.figure or None A matplotlib figure unless the plot is not shown and is saved, in which case None and the figure is closed. """ from resistics.project.shortcuts import getCalibrator from resistics.project.preprocess import ( applyPolarisationReversalOptions, applyScaleOptions, applyCalibrationOptions, applyFilterOptions, applyNormaliseOptions, applyNotchOptions, ) from resistics.common.plot import savePlot, plotOptionsTime options = {} options["sites"]: List[str] = projData.sites options["sampleFreqs"]: Union[List[float], List[str]] = projData.getSampleFreqs() options["chans"]: List[str] = ["Ex", "Ey", "Hx", "Hy", "Hz"] options["polreverse"]: Union[bool, Dict[str, bool]] = False options["scale"]: Union[bool, Dict[str, float]] = False options["calibrate"]: bool = False options["normalise"]: bool = False options["filter"]: Dict = {} options["notch"]: List[float] = [] options["show"]: bool = True options["save"]: bool = False options["plotoptions"]: Dict = plotOptionsTime() options = parseKeywords(options, kwargs) # prepare calibrator cal = getCalibrator(projData.calPath, projData.config) if options["calibrate"]: cal.printInfo() # format startDate and endDate start = datetime.strptime("{}.000".format(startDate), "%Y-%m-%d %H:%M:%S.%f") stop = datetime.strptime("{}.000".format(endDate), "%Y-%m-%d %H:%M:%S.%f") # collect relevant data - dictionary to store timeData timeDataAll = {} for site in options["sites"]: siteData = projData.getSiteData(site) if isinstance(siteData, bool): # site does not exist continue siteData.printInfo() measurements = siteData.getMeasurements() timeDataAll[site] = {} # loop over measurements and save data for each one for meas in measurements: sampleFreq = siteData.getMeasurementSampleFreq(meas) if sampleFreq not in options["sampleFreqs"]: continue # check if data contributes to user defined time period siteStart = siteData.getMeasurementStart(meas) siteStop = siteData.getMeasurementEnd(meas) if siteStop < start or siteStart > stop: continue reader = siteData.getMeasurement(meas) # get the samples of the datetimes sampleStart, sampleStop = reader.time2sample(start, stop) # as the samples returned from time2sample are rounded use sample2time to get the appropriate start and end times for those samples readStart, readStop = reader.sample2time(sampleStart, sampleStop) # get the data for any available channels meaning even those sites with missing channels can be plotted timeData = reader.getPhysicalData(readStart, readStop) projectText( "Plotting measurement {} of site {} between {} and {}".format( meas, site, readStart, readStop)) # apply various options applyPolarisationReversalOptions(options, timeData) applyScaleOptions(options, timeData) applyCalibrationOptions(options, cal, timeData, reader) applyFilterOptions(options, timeData) applyNotchOptions(options, timeData) applyNormaliseOptions(options, timeData) timeDataAll[site][meas] = timeData # plot all the data plotfonts = options["plotoptions"]["plotfonts"] fig = plt.figure(figsize=options["plotoptions"]["figsize"]) for site in timeDataAll: for meas in timeDataAll[site]: timeData = timeDataAll[site][meas] timeData.view( sampleStop=timeDataAll[site][meas].numSamples - 1, fig=fig, chans=options["chans"], label="{} - {}".format(site, meas), xlim=[start, stop], plotfonts=plotfonts, ) # add the suptitle st = fig.suptitle( "Time data from {} to {}".format(start.strftime("%Y-%m-%d %H-%M-%S"), stop.strftime("%Y-%m-%d %H-%M-%S")), fontsize=plotfonts["suptitle"], ) st.set_y(0.98) # do the axis labels numChans = len(options["chans"]) for idx, chan in enumerate(options["chans"]): plt.subplot(numChans, 1, idx + 1) # do the yaxis if isElectric(chan): plt.ylabel("mV/km", fontsize=plotfonts["axisLabel"]) if len(options["plotoptions"]["Eylim"]) > 0: plt.ylim(options["plotoptions"]["Eylim"]) else: if options["calibrate"]: plt.ylabel("nT", fontsize=plotfonts["axisLabel"]) else: plt.ylabel("mV", fontsize=plotfonts["axisLabel"]) if len(options["plotoptions"]["Hylim"]) > 0: plt.ylim(options["plotoptions"]["Hylim"]) plt.legend(loc=1, fontsize=plotfonts["legend"]) # plot format fig.tight_layout(rect=[0, 0.02, 1, 0.96]) fig.subplots_adjust(top=0.92) # plot show and save if options["save"]: impath = projData.imagePath filename = "timeData_{}_{}".format( start.strftime("%Y-%m-%d_%H-%M-%S_"), stop.strftime("%Y-%m-%d_%H-%M-%S")) savename = savePlot(impath, filename, fig) projectText("Image saved to file {}".format(savename)) if options["show"]: plt.show(block=options["plotoptions"]["block"]) if not options["show"] and options["save"]: plt.close(fig) return None return fig
def viewSpectraSection(projData: ProjectData, site: str, meas: str, **kwargs) -> Union[Figure, None]: """View spectra section for a measurement Parameters ---------- projData : projecData The project data site : str The site to view meas: str The measurement of the site to view chans : List[str], optional Channels to plot declevel : int, optional Decimation level to plot specdir : str, optional String that specifies spectra directory for the measurement show : bool, optional Show the spectra plot save : bool, optional Save the plot to the images directory plotoptions : Dict, optional Dictionary of plot options Returns ------- matplotlib.pyplot.figure or None A matplotlib figure unless the plot is not shown and is saved, in which case None and the figure is closed. If no data was found, then None is returned. """ from matplotlib.colors import LogNorm from resistics.common.plot import savePlot, plotOptionsSpec, colorbar2dSpectra options = {} options["chans"] = [] options["declevel"] = 0 options["specdir"] = projData.config.configParams["Spectra"]["specdir"] options["show"] = True options["save"] = False options["plotoptions"] = plotOptionsSpec() options = parseKeywords(options, kwargs) projectText( "Plotting spectra section for measurement {} and site {}".format( meas, site)) specReader = getSpecReader(projData, site, meas, **options) if specReader is None: return None # channels dataChans = specReader.getChannels() if len(options["chans"]) > 0: dataChans = options["chans"] # get windows numWindows = specReader.getNumWindows() sampleFreqDec = specReader.getSampleFreq() f = specReader.getFrequencyArray() # if plotting a section, ignore plotwindow if numWindows > 250: windows = list( np.linspace(0, numWindows, 250, endpoint=False, dtype=np.int32)) else: windows = np.arange(0, numWindows) # create figure plotfonts = options["plotoptions"]["plotfonts"] fig = plt.figure(figsize=options["plotoptions"]["figsize"]) st = fig.suptitle( "Spectra section, site = {}, meas = {}, fs = {:.2f} [Hz], decimation level = {:2d}, windows = {:d}, {} to {}" .format( site, meas, sampleFreqDec, options["declevel"], len(windows), windows[0], windows[-1], ), fontsize=plotfonts["suptitle"], ) st.set_y(0.98) # collect the data specData = np.empty(shape=(len(windows), len(dataChans), specReader.getDataSize()), dtype="complex") dates = [] for idx, iW in enumerate(windows): winData = specReader.readBinaryWindowLocal(iW) for cIdx, chan in enumerate(dataChans): specData[idx, cIdx, :] = winData.data[chan] dates.append(winData.startTime) ampLim = options["plotoptions"]["amplim"] for idx, chan in enumerate(dataChans): ax = plt.subplot(1, len(dataChans), idx + 1) plotData = np.transpose(np.absolute(np.squeeze(specData[:, idx, :]))) if len(ampLim) == 2: plt.pcolor( dates, f, plotData, norm=LogNorm(vmin=ampLim[0], vmax=ampLim[1]), cmap=colorbar2dSpectra(), ) else: plt.pcolor( dates, f, plotData, norm=LogNorm(vmin=plotData.min(), vmax=plotData.max()), cmap=colorbar2dSpectra(), ) cb = plt.colorbar() cb.ax.tick_params(labelsize=plotfonts["axisTicks"]) # set axis limits ax.set_ylim(0, specReader.getSampleFreq() / 2.0) ax.set_xlim([dates[0], dates[-1]]) if isMagnetic(chan): plt.title("Amplitude {} [nT]".format(chan), fontsize=plotfonts["title"]) else: plt.title("Amplitude {} [mV/km]".format(chan), fontsize=plotfonts["title"]) ax.set_ylabel("Frequency [Hz]", fontsize=plotfonts["axisLabel"]) ax.set_xlabel("Time", fontsize=plotfonts["axisLabel"]) # set tick sizes for label in ax.get_xticklabels() + ax.get_yticklabels(): label.set_fontsize(plotfonts["axisTicks"]) plt.grid(True) # plot format fig.autofmt_xdate(rotation=90, ha="center") fig.tight_layout(rect=[0.02, 0.02, 0.96, 0.92]) # plot show and save if options["save"]: impath = projData.imagePath filename = "spectraSection_{}_{}_dec{}_{}".format( site, meas, options["declevel"], options["specdir"]) savename = savePlot(impath, filename, fig) projectText("Image saved to file {}".format(savename)) if options["show"]: plt.show(block=options["plotoptions"]["block"]) if not options["show"] and options["save"]: plt.close(fig) return None return fig
def viewSpectraStack(projData: ProjectData, site: str, meas: str, **kwargs) -> Union[Figure, None]: """View spectra stacks for a measurement Parameters ---------- projData : projecData The project data site : str The site to view meas: str The measurement of the site to view chans : List[str], optional Channels to plot declevel : int, optional Decimation level to plot numstacks : int, optional The number of windows to stack coherences : List[List[str]], optional A list of coherences to add, specified as [["Ex", "Hy"], ["Ey", "Hx"]] specdir : str, optional String that specifies spectra directory for the measurement show : bool, optional Show the spectra plot save : bool, optional Save the plot to the images directory plotoptions : Dict, optional Dictionary of plot options Returns ------- matplotlib.pyplot.figure or None A matplotlib figure unless the plot is not shown and is saved, in which case None and the figure is closed. If no data was found, then None is returned. """ from resistics.common.plot import savePlot, plotOptionsSpec, colorbarMultiline options = {} options["chans"] = [] options["declevel"] = 0 options["numstacks"] = 10 options["coherences"] = [] options["specdir"] = projData.config.configParams["Spectra"]["specdir"] options["show"] = True options["save"] = False options["plotoptions"] = plotOptionsSpec() options = parseKeywords(options, kwargs) projectText("Plotting spectra stack for measurement {} and site {}".format( meas, site)) specReader = getSpecReader(projData, site, meas, **options) if specReader is None: return None # channels dataChans = specReader.getChannels() if len(options["chans"]) > 0: dataChans = options["chans"] numChans = len(dataChans) # get windows numWindows = specReader.getNumWindows() sampleFreqDec = specReader.getSampleFreq() f = specReader.getFrequencyArray() # calculate num of windows to stack in each set stackSize = int(np.floor(1.0 * numWindows / options["numstacks"])) if stackSize == 0: projectWarning("Too few windows for number of stacks {}".format( options["numstacks"])) options["numstacks"] = numWindows stackSize = 1 projectWarning("Number of stacks changed to {}".format( options["numstacks"])) # calculate number of rows - in case interested in coherences too nrows = (2 if len(options["coherences"]) == 0 else 2 + np.ceil(1.0 * len(options["coherences"]) / numChans)) # setup the figure plotfonts = options["plotoptions"]["plotfonts"] cmap = colorbarMultiline() fig = plt.figure(figsize=options["plotoptions"]["figsize"]) st = fig.suptitle( "Spectra stack, fs = {:.6f} [Hz], decimation level = {:2d}, windows in each set = {:d}" .format(sampleFreqDec, options["declevel"], stackSize), fontsize=plotfonts["suptitle"], ) st.set_y(0.98) # do the stacking for iP in range(0, options["numstacks"]): stackStart = iP * stackSize stackStop = min(stackStart + stackSize, numWindows) color = cmap(iP / options["numstacks"]) # dictionaries to hold data for this section stackedData = {} ampData = {} phaseData = {} powerData = {} # assign initial zeros for c in dataChans: stackedData[c] = np.zeros(shape=(specReader.getDataSize()), dtype="complex") ampData[c] = np.zeros(shape=(specReader.getDataSize()), dtype="complex") phaseData[c] = np.zeros(shape=(specReader.getDataSize()), dtype="complex") for c2 in dataChans: powerData[c + c2] = np.zeros(shape=(specReader.getDataSize()), dtype="complex") # now stack the data and create nice plots for iW in range(stackStart, stackStop): winData = specReader.readBinaryWindowLocal(iW) for c in dataChans: stackedData[c] += winData.data[c] ampData[c] += np.absolute(winData.data[c]) phaseData[c] += np.angle(winData.data[c]) * (180.0 / np.pi) # get coherency data for c2 in dataChans: powerData[c + c2] += winData.data[c] * np.conjugate( winData.data[c2]) if iW == stackStart: startTime = winData.startTime if iW == stackStop - 1: stopTime = winData.stopTime # scale powers and stacks ampLim = options["plotoptions"]["amplim"] for idx, c in enumerate(dataChans): stackedData[c] = stackedData[c] / (stackStop - stackStart) ampData[c] = ampData[c] / (stackStop - stackStart) phaseData[c] = phaseData[c] / (stackStop - stackStart) for c2 in dataChans: # normalisation powerData[c + c2] = 2 * powerData[c + c2] / (stackStop - stackStart) # normalisation powerData[c + c2][[0, -1]] = powerData[c + c2][[0, -1]] / 2 # plot ax1 = plt.subplot(nrows, numChans, idx + 1) plt.title("Amplitude {}".format(c), fontsize=plotfonts["title"]) h = ax1.semilogy( f, ampData[c], color=color, label="{} to {}".format( startTime.strftime("%m-%d %H:%M:%S"), stopTime.strftime("%m-%d %H:%M:%S"), ), ) if len(ampLim) == 2: ax1.set_ylim(ampLim) else: ax1.set_ylim(0.01, 1000) ax1.set_xlim(0, sampleFreqDec / 2.0) if isMagnetic(c): ax1.set_ylabel("Amplitude [nT]", fontsize=plotfonts["axisLabel"]) else: ax1.set_ylabel("Amplitude [mV/km]", fontsize=plotfonts["axisLabel"]) ax1.set_xlabel("Frequency [Hz]", fontsize=plotfonts["axisLabel"]) plt.grid(True) # set tick sizes for label in ax1.get_xticklabels() + ax1.get_yticklabels(): label.set_fontsize(plotfonts["axisTicks"]) # plot phase ax2 = plt.subplot(nrows, numChans, numChans + idx + 1) plt.title("Phase {}".format(c), fontsize=plotfonts["title"]) ax2.plot( f, phaseData[c], color=color, label="{} to {}".format( startTime.strftime("%m-%d %H:%M:%S"), stopTime.strftime("%m-%d %H:%M:%S"), ), ) ax2.set_ylim(-180, 180) ax2.set_xlim(0, sampleFreqDec / 2.0) ax2.set_ylabel("Phase [degrees]", fontsize=plotfonts["axisLabel"]) ax2.set_xlabel("Frequency [Hz]", fontsize=plotfonts["axisLabel"]) plt.grid(True) # set tick sizes for label in ax2.get_xticklabels() + ax2.get_yticklabels(): label.set_fontsize(plotfonts["axisTicks"]) # plot coherences for idx, coh in enumerate(options["coherences"]): c = coh[0] c2 = coh[1] cohNom = np.power(np.absolute(powerData[c + c2]), 2) cohDenom = powerData[c + c] * powerData[c2 + c2] coherence = cohNom / cohDenom ax = plt.subplot(nrows, numChans, 2 * numChans + idx + 1) plt.title("Coherence {} - {}".format(c, c2), fontsize=plotfonts["title"]) ax.plot( f, coherence, color=color, label="{} to {}".format( startTime.strftime("%m-%d %H:%M:%S"), stopTime.strftime("%m-%d %H:%M:%S"), ), ) ax.set_ylim(0, 1.1) ax.set_xlim(0, sampleFreqDec / 2) ax.set_ylabel("Coherence", fontsize=plotfonts["axisLabel"]) ax.set_xlabel("Frequency [Hz]", fontsize=plotfonts["axisLabel"]) plt.grid(True) # set tick sizes for label in ax.get_xticklabels() + ax.get_yticklabels(): label.set_fontsize(plotfonts["axisTicks"]) # fig legend and layout ax = plt.gca() h, l = ax.get_legend_handles_labels() fig.tight_layout(rect=[0.01, 0.01, 0.98, 0.81]) # legend legax = plt.axes(position=[0.01, 0.82, 0.98, 0.12], in_layout=False) plt.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False) plt.box(False) legax.legend(h, l, ncol=4, loc="upper center", fontsize=plotfonts["legend"]) # plot show and save if options["save"]: impath = projData.imagePath filename = "spectraStack_{}_{}_dec{}_{}".format( site, meas, options["declevel"], options["specdir"]) savename = savePlot(impath, filename, fig) projectText("Image saved to file {}".format(savename)) if options["show"]: plt.show(block=options["plotoptions"]["block"]) if not options["show"] and options["save"]: plt.close(fig) return None return fig
def viewSpectra(projData: ProjectData, site: str, meas: str, **kwargs) -> Union[Figure, None]: """View spectra for a measurement Parameters ---------- projData : projecData The project data site : str The site to view meas: str The measurement of the site to view chans : List[str], optional Channels to plot declevel : int, optional Decimation level to plot plotwindow : int, str, Dict, optional Windows to plot (local). If int, the window with local index plotwindow will be plotted. If string and "all", all the windows will be plotted if there are less than 20 windows, otherwise 20 windows throughout the whole spectra dataset will be plotted. If a dictionary, needs to have start and stop to define a range. specdir : str, optional String that specifies spectra directory for the measurement show : bool, optional Show the spectra plot save : bool, optional Save the plot to the images directory plotoptions : Dict, optional Dictionary of plot options Returns ------- matplotlib.pyplot.figure or None A matplotlib figure unless the plot is not shown and is saved, in which case None and the figure is closed. If no data was found, then None is returned. """ from resistics.common.plot import savePlot, plotOptionsSpec, colorbarMultiline options = {} options["chans"]: List[str] = [] options["declevel"]: int = 0 options["plotwindow"]: Union[int, Dict, str] = [0] options["specdir"]: str = projData.config.configParams["Spectra"][ "specdir"] options["show"]: bool = True options["save"]: bool = False options["plotoptions"]: Dict = plotOptionsSpec() options = parseKeywords(options, kwargs) projectText("Plotting spectra for measurement {} and site {}".format( meas, site)) specReader = getSpecReader(projData, site, meas, **options) if specReader is None: return None # channels dataChans = specReader.getChannels() if len(options["chans"]) > 0: dataChans = options["chans"] numChans = len(dataChans) # get windows numWindows = specReader.getNumWindows() sampleFreqDec = specReader.getSampleFreq() # get the window data windows = options["plotwindow"] if isinstance(windows, str) and windows == "all": if numWindows > 20: windows = list( np.linspace(0, numWindows, 20, endpoint=False, dtype=np.int32)) else: windows = list(np.arange(0, numWindows)) elif isinstance(windows, int): windows = [windows] # if an integer, make it into a list elif isinstance(windows, dict): windows = list(np.arange(windows["start"], windows["stop"] + 1)) # create a figure plotfonts = options["plotoptions"]["plotfonts"] cmap = colorbarMultiline() fig = plt.figure(figsize=options["plotoptions"]["figsize"]) for iW in windows: if iW >= numWindows: break color = cmap(iW / numWindows) winData = specReader.readBinaryWindowLocal(iW) winData.view( fig=fig, chans=dataChans, label="{} to {}".format( winData.startTime.strftime("%m-%d %H:%M:%S"), winData.stopTime.strftime("%m-%d %H:%M:%S"), ), plotfonts=plotfonts, color=color, ) st = fig.suptitle( "Spectra plot, site = {}, meas = {}, fs = {:.2f} [Hz], decimation level = {:2d}" .format(site, meas, sampleFreqDec, options["declevel"]), fontsize=plotfonts["suptitle"], ) st.set_y(0.98) # put on axis labels etc for idx, chan in enumerate(dataChans): ax = plt.subplot(numChans, 1, idx + 1) plt.title("Amplitude {}".format(chan), fontsize=plotfonts["title"]) if len(options["plotoptions"]["amplim"]) == 2: ax.set_ylim(options["plotoptions"]["amplim"]) ax.set_xlim(0, specReader.getSampleFreq() / 2.0) plt.grid(True) # fig legend and formatting ax = plt.gca() h, l = ax.get_legend_handles_labels() fig.tight_layout(rect=[0.02, 0.02, 0.77, 0.92]) # legend axis legax = plt.axes(position=[0.77, 0.02, 0.23, 0.88], in_layout=False) plt.tick_params(left=False, labelleft=False, bottom=False, labelbottom="False") plt.box(False) legax.legend(h, l, loc="upper left", fontsize=plotfonts["legend"]) # plot show and save if options["save"]: impath = projData.imagePath filename = "spectraData_{}_{}_dec{}_{}".format(site, meas, options["declevel"], options["specdir"]) savename = savePlot(impath, filename, fig) projectText("Image saved to file {}".format(savename)) if options["show"]: plt.show(block=options["plotoptions"]["block"]) if not options["show"] and options["save"]: plt.close(fig) return None return fig
def viewStatisticDensityplot( projData: ProjectData, site: str, sampleFreq: Union[int, float], stat: str, crossplots: List[List[str]], **kwargs ) -> Union[Figure, None]: """View statistic data as a density plot for a single sampling frequency of a site Parameters ---------- projData : ProjectData A project instance site : str The site for which to plot statistics stat : str The statistic to plot sampleFreq : float The sampling frequency for which to plot statistics crossplots : List[List[str]] The statistic element pairs to crossplot declevel : int The decimation level to plot eFreqI : int The evaluation frequency index specdir : str The spectra directory maskname : str Mask name xlim : List, optional Limits for the x axis ylim : List, optional Limits for the y axis maxcols : int The maximum number of columns in the plots show : bool, optional Show the spectra plot save : bool, optional Save the plot to the images directory plotoptions : Dict, optional Dictionary of plot options Returns ------- matplotlib.pyplot.figure or None A matplotlib figure unless the plot is not shown and is saved, in which case None and the figure is closed. If no data was found, None. """ from resistics.common.plot import ( savePlot, plotOptionsSpec, getPlotRowsAndCols, colorbar2dSpectra, ) options = {} options["declevel"] = 0 options["eFreqI"] = 0 options["specdir"] = projData.config.configParams["Spectra"]["specdir"] options["maskname"] = "" options["xlim"] = [] options["ylim"] = [] options["maxcols"] = 2 options["show"] = True options["save"] = False options["plotoptions"] = plotOptionsSpec() options = parseKeywords(options, kwargs) projectText( "Plotting density plot for statistic {}, site {} and sampling frequency {}".format( stat, site, sampleFreq ) ) statData = getStatisticDataForSampleFreq( projData, site, sampleFreq, stat, declevel=options["declevel"], specdir=options["specdir"], ) statMeas = list(statData.keys()) if len(statMeas) == 0: projectWarning( "No statistic files for site {}, sampling frequency {}, statistic {} and decimation level {}".format( site, sampleFreq, stat, options["declevel"] ) ) return None # get the evaluation frequency eFreq = statData[statMeas[0]].evalFreq[options["eFreqI"]] # get the mask data maskWindows = [] if options["maskname"] != "": maskData = getMaskData(projData, site, options["maskname"], sampleFreq) maskWindows = maskData.getMaskWindowsFreq( options["declevel"], options["eFreqI"] ) # plot information nrows, ncols = getPlotRowsAndCols(options["maxcols"], len(crossplots)) plotfonts = options["plotoptions"]["plotfonts"] fig = plt.figure(figsize=options["plotoptions"]["figsize"]) # suptitle st = fig.suptitle( "{} density plots for {}, sampling frequency {} Hz,\ndecimation level {} and evaluation frequency {} Hz".format( stat, site, sampleFreq, options["declevel"], eFreq ), fontsize=plotfonts["suptitle"], ) st.set_y(0.98) # now plot the data for idx, cplot in enumerate(crossplots): ax = plt.subplot(nrows, ncols, idx + 1) plt.title("Crossplot {}".format(cplot), fontsize=plotfonts["title"]) plotAll1 = [] plotAll2 = [] for meas in statMeas: stats = statData[meas].getStats(maskwindows=maskWindows) plotI1 = statData[meas].winStats.index(cplot[0]) plotData1 = np.squeeze(stats[:, options["eFreqI"], plotI1]) plotI2 = statData[meas].winStats.index(cplot[1]) plotData2 = np.squeeze(stats[:, options["eFreqI"], plotI2]) # add to all data if plotData1.size == 0: continue if plotData1.size == 1: plotAll1 = plotAll1 + [float(plotData1)] plotAll2 = plotAll2 + [float(plotData2)] else: plotAll1 = plotAll1 + plotData1.tolist() plotAll2 = plotAll2 + plotData2.tolist() plotAll1 = np.array(plotAll1) plotAll2 = np.array(plotAll2) nbins = 200 if len(options["xlim"]) > 0: plt.xlim(options["xlim"]) rangex = options["xlim"] else: minx = np.percentile(plotAll1, 2) maxx = np.percentile(plotAll1, 98) ax.set_xlim(minx, maxx) rangex = [minx, maxx] if len(options["ylim"]) > 0: plt.ylim(options["ylim"]) rangey = options["ylim"] else: miny = np.percentile(plotAll2, 2) maxy = np.percentile(plotAll2, 98) ax.set_ylim(miny, maxy) rangey = [miny, maxy] plt.hist2d( plotAll1, plotAll2, bins=(nbins, nbins), range=[rangex, rangey], cmap=plt.cm.inferno, ) # axis format plt.xlabel(cplot[0], fontsize=plotfonts["axisLabel"]) plt.ylabel(cplot[1], fontsize=plotfonts["axisLabel"]) plt.grid(True) # set tick sizes for label in ax.get_xticklabels() + ax.get_yticklabels(): label.set_fontsize(plotfonts["axisTicks"]) # plot format, show and save # fig.tight_layout(rect=[0.02, 0.02, 0.98, 0.92]) if options["save"]: impath = projData.imagePath sampleFreqStr = fileFormatSampleFreq(sampleFreq) filename = "statDensityplot_{:s}_{:s}_{:s}_dec{:d}_efreq{:d}_{:s}".format( stat, site, sampleFreqStr, options["declevel"], options["eFreqI"], options["specdir"], ) if options["maskname"] != "": filename = "{}_{}".format(filename, options["maskname"]) savename = savePlot(impath, filename, fig) projectText("Image saved to file {}".format(savename)) if options["show"]: plt.show(block=options["plotoptions"]["block"]) if not options["show"] and options["save"]: plt.close(fig) return None return fig
def viewStatisticHistogram( projData: ProjectData, site: str, sampleFreq: float, stat: str, **kwargs ) -> Union[Figure, None]: """View statistic histograms for a single sampling frequency of a site Parameters ---------- projData : ProjectData A project instance site : str The site for which to plot statistics stat : str The statistic to plot sampleFreq : float The sampling frequency for which to plot statistics declevel : int The decimation level to plot eFreqI : int The evaluation frequency index specdir : str The spectra directory maskname : str Mask name numbins : int The number of bins for the histogram data binning xlim : List, optional Limits for the x axis maxcols : int The maximum number of columns in the plots show : bool, optional Show the spectra plot save : bool, optional Save the plot to the images directory plotoptions : Dict, optional Dictionary of plot options Returns ------- matplotlib.pyplot.figure or None A matplotlib figure unless the plot is not shown and is saved, in which case None. If no data was found, None. """ from resistics.common.plot import savePlot, plotOptionsSpec, getPlotRowsAndCols options = {} options["declevel"] = 0 options["eFreqI"] = 0 options["specdir"] = projData.config.configParams["Spectra"]["specdir"] options["maskname"] = "" options["numbins"] = 40 options["xlim"] = [] options["maxcols"] = 4 options["show"] = True options["save"] = False options["plotoptions"] = plotOptionsSpec() options = parseKeywords(options, kwargs) projectText( "Plotting histogram for statistic {}, site {} and sampling frequency {}".format( stat, site, sampleFreq ) ) statData = getStatisticDataForSampleFreq( projData, site, sampleFreq, stat, declevel=options["declevel"], specdir=options["specdir"], ) statMeas = list(statData.keys()) if len(statMeas) == 0: projectWarning( "No statistic files for site {}, sampling frequency {}, statistic {} and decimation level {}".format( site, sampleFreq, stat, options["declevel"] ) ) return None # get the statistic components statComponents = statData[statMeas[0]].winStats # get the evaluation frequency eFreq = statData[statMeas[0]].evalFreq[options["eFreqI"]] # get the mask data maskWindows = [] if options["maskname"] != "": maskData = getMaskData(projData, site, options["maskname"], sampleFreq) maskWindows = maskData.getMaskWindowsFreq( options["declevel"], options["eFreqI"] ) # plot information nrows, ncols = getPlotRowsAndCols(options["maxcols"], len(statComponents)) numbins = options["numbins"] plotfonts = options["plotoptions"]["plotfonts"] fig = plt.figure(figsize=options["plotoptions"]["figsize"]) # suptitle st = fig.suptitle( "{} histogram for {}, sampling frequency {} Hz, decimation level {} and evaluation frequency {} Hz".format( stat, site, sampleFreq, options["declevel"], eFreq ), fontsize=plotfonts["suptitle"], ) st.set_y(0.98) # now plot the data for idx, val in enumerate(statComponents): ax = plt.subplot(nrows, ncols, idx + 1) plt.title("Histogram {}".format(val), fontsize=plotfonts["title"]) plotData = np.empty(shape=(0)) for meas in statMeas: stats = statData[meas].getStats(maskwindows=maskWindows) plotData = np.concatenate( (plotData, np.squeeze(stats[:, options["eFreqI"], idx])) ) # remove infinities and nans plotData = plotData[np.isfinite(plotData)] # x axis options xlim = ( options["xlim"] if len(options["xlim"]) > 0 else [np.min(plotData), np.max(plotData)] ) plt.xlim(xlim) plt.xlabel("Value", fontsize=plotfonts["axisLabel"]) # now plot with xlim in mind plt.hist(plotData, numbins, range=xlim, facecolor="red", alpha=0.75) plt.grid() # y axis options plt.ylabel("Count", fontsize=plotfonts["axisLabel"]) # set tick sizes for label in ax.get_xticklabels() + ax.get_yticklabels(): label.set_fontsize(plotfonts["axisTicks"]) # plot format, show and save fig.tight_layout(rect=[0.02, 0.02, 0.98, 0.92]) if options["save"]: impath = projData.imagePath sampleFreqStr = fileFormatSampleFreq(sampleFreq) filename = "statHist_{:s}_{:s}_{:s}_dec{:d}_efreq{:d}_{:s}".format( stat, site, sampleFreqStr, options["declevel"], options["eFreqI"], options["specdir"], ) if options["maskname"] != "": filename = "{}_{}".format(filename, options["maskname"]) savename = savePlot(impath, filename, fig) projectText("Image saved to file {}".format(savename)) if options["show"]: plt.show(block=options["plotoptions"]["block"]) if not options["show"] and options["save"]: plt.close(fig) return None return fig
def viewStatistic( projData: ProjectData, site: str, sampleFreq: Union[int, float], stat: str, **kwargs ) -> Union[Figure, None]: """View statistic data for a single sampling frequency of a site Parameters ---------- projData : ProjectData A project instance site : str The site for which to plot statistics stat : str The statistic to plot sampleFreq : float The sampling frequency for which to plot statistics declevel : int The decimation level to plot eFreqI : int The evaluation frequency index specdir : str The spectra directory maskname : str Mask name clim : List, optional Limits for colourbar axis xlim : List, optional Limits for the x axis ylim : List, optional Limits for the y axis colortitle : str, optional Title for the colourbar show : bool, optional Show the spectra plot save : bool, optional Save the plot to the images directory plotoptions : Dict, optional Dictionary of plot options Returns ------- matplotlib.pyplot.figure or None A matplotlib figure unless the plot is not shown and is saved, in which case None and the figure is closed. If no data was found, None. """ from resistics.common.plot import savePlot, plotOptionsSpec, getPlotRowsAndCols options = {} options["declevel"] = 0 options["eFreqI"] = 0 options["specdir"] = projData.config.configParams["Spectra"]["specdir"] options["maskname"] = "" options["clim"] = [] options["xlim"] = [] options["ylim"] = [] options["colortitle"] = "" options["show"] = True options["save"] = False options["plotoptions"] = plotOptionsSpec() options = parseKeywords(options, kwargs) projectText( "Plotting statistic {} for site {} and sampling frequency {}".format( stat, site, sampleFreq ) ) statData = getStatisticDataForSampleFreq( projData, site, sampleFreq, stat, declevel=options["declevel"], specdir=options["specdir"], ) statMeas = list(statData.keys()) if len(statMeas) == 0: projectWarning( "No statistic files for site {}, sampling frequency {}, statistic {} and decimation level {}".format( site, sampleFreq, stat, options["declevel"] ) ) return None # get the evaluation frequency eFreq = statData[statMeas[0]].evalFreq[options["eFreqI"]] # get the mask data maskWindows = [] if options["maskname"] != "": maskData = getMaskData(projData, site, options["maskname"], sampleFreq) maskWindows = maskData.getMaskWindowsFreq( options["declevel"], options["eFreqI"] ) # setup the figure plotfonts = options["plotoptions"]["plotfonts"] fig = plt.figure(figsize=options["plotoptions"]["figsize"]) # get the date limits siteData = projData.getSiteData(site) if len(options["xlim"]) == 0: start = siteData.getMeasurementStart(statMeas[0]) end = siteData.getMeasurementEnd(statMeas[0]) for meas in statMeas: start = min(start, siteData.getMeasurementStart(meas)) end = max(end, siteData.getMeasurementEnd(meas)) options["xlim"] = [start, end] # do the plots for meas in statMeas: statData[meas].view( options["eFreqI"], fig=fig, xlim=options["xlim"], ylim=options["ylim"], clim=options["clim"], label=meas, plotfonts=options["plotoptions"]["plotfonts"], maskwindows=maskWindows, ) # add a legened plt.legend(markerscale=4, fontsize=plotfonts["legend"]) # do the title after all the plots fig.suptitle( "{} values for {}, sampling frequency = {:.2f} Hz, decimation level = {} and evaluation frequency {} Hz".format( stat, site, sampleFreq, options["declevel"], eFreq ), fontsize=plotfonts["suptitle"], ) # plot format, show and save fig.tight_layout(rect=[0.02, 0.02, 0.98, 0.92]) if options["save"]: impath = projData.imagePath sampleFreqStr = fileFormatSampleFreq(sampleFreq) filename = "stat_{:s}_{:s}_{:s}_dec{:d}_efreq{:d}_{:s}".format( stat, site, sampleFreqStr, options["declevel"], options["eFreqI"], options["specdir"], ) if options["maskname"] != "": filename = "{}_{}".format(filename, options["maskname"]) savename = savePlot(impath, filename, fig) projectText("Image saved to file {}".format(savename)) if options["show"]: plt.show(block=options["plotoptions"]["block"]) if not options["show"] and options["save"]: plt.close(fig) return None return fig
def viewTipper(projData: ProjectData, **kwargs) -> List[Figure]: """View transfer function data Parameters ---------- projData : projecData The project data sites : List[str], optional List of sites to plot transfer functions for sampleFreqs : List[float], optional List of samples frequencies for which to plot transfer functions specdir : str, optional The spectra directories used postpend : str, optional The postpend on the transfer function files cols : bool, optional Boolean flag, True to arrange tipper plot as 1 row with 3 columns show : bool, optional Show the spectra plot save : bool, optional Save the plot to the images directory plotoptions : Dict A dictionary of plot options. For example, set the resistivity y limits using res_ylim, set the phase y limits using phase_ylim and set the xlimits using xlim """ from resistics.common.plot import ( savePlot, plotOptionsTipper, getTransferFunctionFigSize, transferFunctionColours, ) options = {} options["sites"] = projData.getSites() options["sampleFreqs"] = projData.getSampleFreqs() options["specdir"] = projData.config.configParams["Spectra"]["specdir"] options["postpend"] = "" options["cols"] = True options["save"] = False options["show"] = True options["plotoptions"] = plotOptionsTipper() options = parseKeywords(options, kwargs) # loop over sites figs = [] for site in options["sites"]: siteData = projData.getSiteData(site) sampleFreqs = set(siteData.getSampleFreqs()) # find the intersection with the options["freqs"] sampleFreqs = sampleFreqs.intersection(options["sampleFreqs"]) sampleFreqs = sorted(list(sampleFreqs)) # if prepend is a string, then make it a list if isinstance(options["postpend"], str): options["postpend"] = [options["postpend"]] plotfonts = options["plotoptions"]["plotfonts"] # now loop over the postpend options for pp in options["postpend"]: # add an underscore if not empty postpend = "_{}".format(pp) if pp != "" else pp fig = plt.figure(figsize=options["plotoptions"]["figsize"]) mks = ["o", "*", "d", "^", "h"] lstyles = ["solid", "dashed", "dashdot", "dotted"] # loop over sampling frequencies includedFreqs = [] for idx, sampleFreq in enumerate(sampleFreqs): tfData = getTransferFunctionData(projData, site, sampleFreq, specdir=options["specdir"], postpend=pp) if not tfData: continue includedFreqs.append(sampleFreq) projectText( "Plotting tipper for site {}, sample frequency {}".format( site, sampleFreq)) mk = mks[idx % len(mks)] ls = lstyles[idx % len(lstyles)] tfData.viewTipper( fig=fig, rows=options["cols"], mk=mk, ls=ls, label="{}".format(sampleFreq), xlim=options["plotoptions"]["xlim"], length_ylim=options["plotoptions"]["length_ylim"], angle_ylim=options["plotoptions"]["angle_ylim"], plotfonts=options["plotoptions"]["plotfonts"], ) # check if any files found if len(includedFreqs) == 0: continue # sup title sub = "Site {} tipper: {}".format(site, options["specdir"] + postpend) sub = "{}\nfs = {}".format( sub, arrayToString(includedFreqs, decimals=3)) st = fig.suptitle(sub, fontsize=plotfonts["suptitle"]) st.set_y(0.99) fig.tight_layout() fig.subplots_adjust(top=0.85) figs.append(fig) if options["save"]: impath = projData.imagePath filename = "tipper_{}_{}{}".format(site, options["specdir"], postpend) savename = savePlot(impath, filename, fig) projectText("Image saved to file {}".format(savename)) if not options["show"]: plt.close("all") else: plt.show(block=options["plotoptions"]["block"]) return figs