diff --git a/pyglance/glance/compare.py b/pyglance/glance/compare.py index 9c357aa3c342d1ddbc7f40ccbd9ac3c4a5c83a5e..ea3775f4634b128560d4a713acd4f9a8eed1e444 100644 --- a/pyglance/glance/compare.py +++ b/pyglance/glance/compare.py @@ -598,12 +598,10 @@ def inspect_library_call (a_path, var_list=None, # we are always going to want to draw a basic histogram of the data values to tell which # occur most frequently plotFunctionGenerationObjects.append(plotcreate.DataHistogramPlotFunctionFactory()) - + # if it's vector data with longitude and latitude, quiver plot it on the Earth if isVectorData and (not do_not_test_with_lon_lat) : - # TODO replace this at some point - #plotFunctionGenerationObjects.append(plotcreate.MappedQuiverPlotFunctionFactory()) - pass + plotFunctionGenerationObjects.append(plotcreate.InspectMappedQuiverPlotFunctionFactory()) # if the data is one dimensional we can plot it as lines elif (len(aData.shape) == 1) : @@ -864,8 +862,7 @@ def reportGen_library_call (a_path, b_path, var_list=None, do_not_test_with_lon_lat = (not include_images_for_this_variable) or (len(lon_lat_data) <= 0) # handle vector data - isVectorData = ( (MAGNITUDE_VAR_NAME_KEY in varRunInfo) and (DIRECTION_VAR_NAME_KEY in varRunInfo) and - (MAGNITUDE_B_VAR_NAME_KEY in varRunInfo) and (DIRECTION_B_VAR_NAME_KEY in varRunInfo) ) + isVectorData = (MAGNITUDE_VAR_NAME_KEY in varRunInfo) and (DIRECTION_VAR_NAME_KEY in varRunInfo) # check if this data can be displayed but # don't compare lon/lat sizes if we won't be plotting @@ -943,8 +940,8 @@ def reportGen_library_call (a_path, b_path, var_list=None, lon_lat_data[A_FILE_KEY][INVALID_MASK_KEY] if (A_FILE_KEY in lon_lat_data) and (INVALID_MASK_KEY in lon_lat_data[A_FILE_KEY]) else None) bUData, bVData = get_UV_info_from_magnitude_direction_info (bFile.file_object, - varRunInfo[MAGNITUDE_B_VAR_NAME_KEY] if (MAGNITUDE_B_VAR_NAME_KEY) in varRunInfo else None, - varRunInfo[DIRECTION_B_VAR_NAME_KEY] if (DIRECTION_B_VAR_NAME_KEY) in varRunInfo else None, + varRunInfo[MAGNITUDE_B_VAR_NAME_KEY] if (MAGNITUDE_B_VAR_NAME_KEY) in varRunInfo else varRunInfo[MAGNITUDE_VAR_NAME_KEY] if (MAGNITUDE_VAR_NAME_KEY) in varRunInfo else None, + varRunInfo[DIRECTION_B_VAR_NAME_KEY] if (DIRECTION_B_VAR_NAME_KEY) in varRunInfo else varRunInfo[DIRECTION_VAR_NAME_KEY] if (DIRECTION_VAR_NAME_KEY) in varRunInfo else None, lon_lat_data[B_FILE_KEY][INVALID_MASK_KEY] if (B_FILE_KEY in lon_lat_data) and (INVALID_MASK_KEY in lon_lat_data[B_FILE_KEY]) else None) @@ -958,7 +955,7 @@ def reportGen_library_call (a_path, b_path, var_list=None, plotFunctionGenerationObjects.append(plotcreate.BinTupleAnalysisFunctionFactory()) else : # if it's not bin/tuple, there are lots of other posibilities - + # if it's vector data with longitude and latitude, quiver plot it on the Earth if isVectorData and (not do_not_test_with_lon_lat) : plotFunctionGenerationObjects.append(plotcreate.MappedQuiverPlotFunctionFactory()) diff --git a/pyglance/glance/figures.py b/pyglance/glance/figures.py index edd0237d16d2096c11dc42f71364d4d7378af3c8..b42d91efffa107c779aae10cd8a184f7494e7627 100644 --- a/pyglance/glance/figures.py +++ b/pyglance/glance/figures.py @@ -660,16 +660,15 @@ def create_mapped_figure(data, latitude, longitude, in_projection, out_projectio return figure_obj -# create a figure including a quiver plot of our vector data mapped onto a map at the lon/lat -# given, the colorMap parameter can be used to control the colors the figure is drawn. -# if any masks are passed in the tagData list they will be plotted as an overlays -# set on the existing image -# TODO, this method has not been throughly tested -# TODO, this method needs an input colormap so the mismatch plot can be the right color def create_quiver_mapped_figure(data, latitude, longitude, in_projection, out_projection, boundingAxes, title_str, - invalidMask=None, tagData=None, uData=None, vData=None, units=None, **kwargs) : + invalidMask=None, tagData=None, uData=None, vData=None, units=None, colorMap=None, **kwargs) : + """create a figure including a quiver plot of our vector data mapped onto a map at the lon/lat - if (data is None) or (data.size <= 1) or (invalidMask is not None and data[~invalidMask].size <= 1): + if any masks are passed in the tagData list they will be plotted as an overlays set on the existing image + + """ + + if (data is None) or (data.size < 1) or (invalidMask is not None and data[~invalidMask].size < 1): LOG.debug("Not enough data to make a meaningful quiver mapped figure.") return None @@ -691,22 +690,21 @@ def create_quiver_mapped_figure(data, latitude, longitude, in_projection, out_pr # build the plot figure_obj = plt.figure() axes_obj = figure_obj.add_subplot(111, projection=out_projection,) - + # draw our data placed on a map maps.draw_basic_features(in_projection, axes_obj, boundingAxes, ) - img_temp = maps.quiver_plot_on_map(longitudeClean, latitudeClean, axes_obj, in_projection, uDataClean, vDataClean, colordata=colorData, ) + img_temp = maps.quiver_plot_on_map(longitudeClean, latitudeClean, axes_obj, in_projection, uDataClean, vDataClean, + colorMap=colorMap, colordata=colorData, ) # show the title axes_obj.set_title(title_str) - + # make a color bar if we have color data - """ todo, currently this crashes glance because of an error in matplot lib if colorData is not None : cbar = plt.colorbar(img_temp, format='%.3g') # add the units to the colorbar if (str.lower(str(units)) != "none") and (str.lower(str(units)) != "1") : cbar.set_label(units) - """ numMismatchPoints = _plot_tag_data_mapped(axes_obj, in_projection, tagDataClean, longitudeClean, latitudeClean, ) diff --git a/pyglance/glance/graphics.py b/pyglance/glance/graphics.py index 078cd03b29bfb3ce11193079ac2e43946615b752..e5c34eb947170bc447a39e3eb066465125868b77 100644 --- a/pyglance/glance/graphics.py +++ b/pyglance/glance/graphics.py @@ -280,7 +280,7 @@ def contourf_on_map(lon, lat, data, axes_object, in_projection, levelsToUse=None return img_temp -def quiver_plot_on_map(lon, lat, axes_object, in_projection, uData=None, vData=None, colordata=None, **kwargs) : +def quiver_plot_on_map(lon, lat, axes_object, in_projection, uData=None, vData=None, colordata=None, colorMap=None, **kwargs) : """ Show a quiver plot of the given vector data at the given longitude and latitude """ @@ -289,9 +289,9 @@ def quiver_plot_on_map(lon, lat, axes_object, in_projection, uData=None, vData=N if (uData is not None) and (vData is not None): if colordata is None: - img_temp = axes_object.quiver(lon, lat, uData, vData, transform=in_projection, **kwargs) + img_temp = axes_object.quiver(lon, lat, uData, vData, transform=in_projection, cmap=colorMap, **kwargs) else: - img_temp = axes_object.quiver(lon, lat, uData, vData, colordata, transform=in_projection, **kwargs) + img_temp = axes_object.quiver(lon, lat, uData, vData, colordata, transform=in_projection, cmap=colorMap, **kwargs) return img_temp diff --git a/pyglance/glance/plotcreatefns.py b/pyglance/glance/plotcreatefns.py index 92698f186a8e032c1e98fd0d976b35c08703ff3c..97f561c2e4390b9b928b20989bd2e395ed331843 100644 --- a/pyglance/glance/plotcreatefns.py +++ b/pyglance/glance/plotcreatefns.py @@ -1488,6 +1488,103 @@ class InspectMappedContourPlotFunctionFactory (PlottingFunctionFactory) : return functionsToReturn +class InspectMappedQuiverPlotFunctionFactory(PlottingFunctionFactory): + """ + This class creates quiver plots for a single file mapped onto a region of the earth. + Note: the plotting function requires u and v data. + """ + + def __init__(self): + LOG.debug("Creating InspectMappedQuiverPlotFunctionFactory object.") + + def create_plotting_functions( + self, + + # the most basic data set needed + aData, bData, # bData will not be used + variableDisplayName, + epsilon, + doPlotSettingsDict, + + # where the names of the created figures will be stored + original_fig_list, compared_fig_list, + + # parameters that are only needed for geolocated data + lonLatDataDict=None, + + # not used in this method (for contour plots) + dataRanges=None, dataRangeNames=None, dataColors=None, + shouldUseSharedRangeForOriginal=True, + + # not used in this method (for comparison plots) + differences=None, + + # only used for plotting quiver data + aUData=None, aVData=None, + bUData=None, bVData=None, # b versions will not be used + + # not used in this method (only used for line plots) + binIndex=None, tupleIndex=None, + binName=None, tupleName=None, + + # not used in this method (the optional epsilon for comparison of a percent of A) + epsilonPercent=None, + + # the optional units for display + units_a=None, units_b=None, # units_b will not be used + + # not used in this method (an optional range for a histogram) + histRange=None + + ): + + # FUTURE, for the moment, unpack these values into local variables; FUTURE use the objects directly and as needed + goodInAMask = aData.masks.valid_mask + aData = aData.data + + # the default for plotting geolocated data + mappedPlottingFunction = figures.create_quiver_mapped_figure + + functionsToReturn = {} + + assert (aUData is not None) + assert (aVData is not None) + + assert (lonLatDataDict is not None) + assert (goodInAMask is not None) + + # figure out where we're going to be plotting and using which projections + temp_lonlat = { + A_FILE_KEY: lonLatDataDict, + } + fullAxis, in_proj, out_proj = _get_extents_and_projections(temp_lonlat, + goodInAMask, None, + variableDisplayName) + + # make the plotting functions + + # make the original data plots + if (DO_PLOT_ORIGINALS_KEY not in doPlotSettingsDict) or (doPlotSettingsDict[DO_PLOT_ORIGINALS_KEY]): + assert (LAT_KEY in lonLatDataDict) + assert (LON_KEY in lonLatDataDict) + assert (lonLatDataDict[LAT_KEY].shape == lonLatDataDict[LON_KEY].shape) + + functionsToReturn[ORIG_A_FUNCTION_KEY] = \ + ((lambda: mappedPlottingFunction(aData, + lonLatDataDict[LAT_KEY], + lonLatDataDict[LON_KEY], + in_proj, out_proj, fullAxis, + (variableDisplayName + "\nin File A"), + invalidMask=(~goodInAMask), + uData=aUData, vData=aVData, + units=units_a)), + variableDisplayName + " in file a", + "A.png", original_fig_list) + + # FUTURE, any additional figures of the original data? + + return functionsToReturn + if __name__=='__main__': import doctest doctest.testmod()