def UpdateColorbarPP(stuff): v_min = np.int(textbox_pp_min.text) v_max = np.int(textbox_pp_max.text) my_gamma = np.double(textbox_pp_g.text) print("\n v_min = ", v_min) print("v_max = ", v_max) print("gamma = ", my_gamma) pp_image.set_norm(colors.PowerNorm(gamma=my_gamma)) pp_image.set_clim([v_min, v_max]) cb_pp = Colorbar(ax=c_ax_pp, mappable=pp_image, orientation='horizontal', ticklocation='top') cb_pp.locator = ticker.MaxNLocator(nbins=3) cb_pp.update_ticks()
def plot_cartopy(lons, lats, size, color, labels=None, projection='global', resolution='110m', continent_fill_color='0.8', water_fill_color='1.0', colormap=None, colorbar=None, marker="o", title=None, colorbar_ticklabel_format=None, show=True, proj_kwargs=None, **kwargs): # @UnusedVariable """ Creates a Cartopy plot with a data point scatter plot. :type lons: list/tuple of floats :param lons: Longitudes of the data points. :type lats: list/tuple of floats :param lats: Latitudes of the data points. :type size: float or list/tuple of floats :param size: Size of the individual points in the scatter plot. :type color: list/tuple of floats (or objects that can be converted to floats, like e.g. :class:`~obspy.core.utcdatetime.UTCDateTime`) :param color: Color information of the individual data points to be used in the specified color map (e.g. origin depths, origin times). :type labels: list/tuple of str :param labels: Annotations for the individual data points. :type projection: str, optional :param projection: The map projection. Currently supported are: * ``"global"`` (Will plot the whole world using :class:`~cartopy.crs.Mollweide`.) * ``"ortho"`` (Will center around the mean lat/long using :class:`~cartopy.crs.Orthographic`.) * ``"local"`` (Will plot around local events using :class:`~cartopy.crs.AlbersEqualArea`.) * Any other Cartopy :class:`~cartopy.crs.Projection`. An instance of this class will be created using the supplied ``proj_kwargs``. Defaults to "global" :type resolution: str, optional :param resolution: Resolution of the boundary database to use. Will be passed directly to the Cartopy module. Possible values are: * ``"110m"`` * ``"50m"`` * ``"10m"`` Defaults to ``"110m"``. For compatibility, you may also specify any of the Basemap resolutions defined in :func:`plot_basemap`. :type continent_fill_color: Valid matplotlib color, optional :param continent_fill_color: Color of the continents. Defaults to ``"0.9"`` which is a light gray. :type water_fill_color: Valid matplotlib color, optional :param water_fill_color: Color of all water bodies. Defaults to ``"white"``. :type colormap: str, any matplotlib colormap, optional :param colormap: The colormap for color-coding the events as provided in `color` kwarg. The event with the smallest `color` property will have the color of one end of the colormap and the event with the highest `color` property the color of the other end with all other events in between. Defaults to None which will use the default matplotlib colormap. :type colorbar: bool, optional :param colorbar: When left `None`, a colorbar is plotted if more than one object is plotted. Using `True`/`False` the colorbar can be forced on/off. :type title: str :param title: Title above plot. :type colorbar_ticklabel_format: str or function or subclass of :class:`matplotlib.ticker.Formatter` :param colorbar_ticklabel_format: Format string or Formatter used to format colorbar tick labels. :type show: bool :param show: Whether to show the figure after plotting or not. Can be used to do further customization of the plot before showing it. :type proj_kwargs: dict :param proj_kwargs: Keyword arguments to pass to the Cartopy :class:`~cartopy.ccrs.Projection`. In this dictionary, you may specify ``central_longitude='auto'`` or ``central_latitude='auto'`` to have this function calculate the latitude or longitude as it would for other projections. Some arguments may be ignored if you choose one of the built-in ``projection`` choices. """ import matplotlib.pyplot as plt min_color = min(color) max_color = max(color) if isinstance(color[0], (datetime.datetime, UTCDateTime)): datetimeplot = True color = [date2num(getattr(t, 'datetime', t)) for t in color] else: datetimeplot = False scal_map = ScalarMappable(norm=Normalize(min_color, max_color), cmap=colormap) scal_map.set_array(np.linspace(0, 1, 1)) fig = plt.figure() # The colorbar should only be plotted if more then one event is # present. if colorbar is not None: show_colorbar = colorbar else: if len(lons) > 1 and hasattr(color, "__len__") and \ not isinstance(color, (str, native_str)): show_colorbar = True else: show_colorbar = False if projection == "local": ax_x0, ax_width = 0.10, 0.80 elif projection == "global": ax_x0, ax_width = 0.01, 0.98 else: ax_x0, ax_width = 0.05, 0.90 proj_kwargs = proj_kwargs or {} if projection == 'global': proj_kwargs['central_longitude'] = np.mean(lons) proj = ccrs.Mollweide(**proj_kwargs) elif projection == 'ortho': proj_kwargs['central_latitude'] = np.mean(lats) proj_kwargs['central_longitude'] = np.mean(lons) proj = ccrs.Orthographic(**proj_kwargs) elif projection == 'local': if min(lons) < -150 and max(lons) > 150: max_lons = max(np.array(lons) % 360) min_lons = min(np.array(lons) % 360) else: max_lons = max(lons) min_lons = min(lons) lat_0 = max(lats) / 2. + min(lats) / 2. lon_0 = max_lons / 2. + min_lons / 2. if lon_0 > 180: lon_0 -= 360 deg2m_lat = 2 * np.pi * 6371 * 1000 / 360 deg2m_lon = deg2m_lat * np.cos(lat_0 / 180 * np.pi) if len(lats) > 1: height = (max(lats) - min(lats)) * deg2m_lat width = (max_lons - min_lons) * deg2m_lon margin = 0.2 * (width + height) height += margin width += margin else: height = 2.0 * deg2m_lat width = 5.0 * deg2m_lon # Do intelligent aspect calculation for local projection # adjust to figure dimensions w, h = fig.get_size_inches() aspect = w / h if show_colorbar: aspect *= 1.2 if width / height < aspect: width = height * aspect else: height = width / aspect proj_kwargs['central_latitude'] = lat_0 proj_kwargs['central_longitude'] = lon_0 proj = ccrs.AlbersEqualArea(**proj_kwargs) # User-supplied projection. elif isinstance(projection, type): if 'central_longitude' in proj_kwargs: if proj_kwargs['central_longitude'] == 'auto': proj_kwargs['central_longitude'] = np.mean(lons) if 'central_latitude' in proj_kwargs: if proj_kwargs['central_latitude'] == 'auto': proj_kwargs['central_latitude'] = np.mean(lats) if 'pole_longitude' in proj_kwargs: if proj_kwargs['pole_longitude'] == 'auto': proj_kwargs['pole_longitude'] = np.mean(lons) if 'pole_latitude' in proj_kwargs: if proj_kwargs['pole_latitude'] == 'auto': proj_kwargs['pole_latitude'] = np.mean(lats) proj = projection(**proj_kwargs) else: msg = "Projection '%s' not supported." % projection raise ValueError(msg) if show_colorbar: map_ax = fig.add_axes([ax_x0, 0.13, ax_width, 0.77], projection=proj) cm_ax = fig.add_axes([ax_x0, 0.05, ax_width, 0.05]) plt.sca(map_ax) else: ax_y0, ax_height = 0.05, 0.85 if projection == "local": ax_y0 += 0.05 ax_height -= 0.05 map_ax = fig.add_axes([ax_x0, ax_y0, ax_width, ax_height], projection=proj) if projection == 'local': x0, y0 = proj.transform_point(lon_0, lat_0, proj.as_geodetic()) map_ax.set_xlim(x0 - width / 2, x0 + width / 2) map_ax.set_ylim(y0 - height / 2, y0 + height / 2) else: map_ax.set_global() # Pick features at specified resolution. resolution = _CARTOPY_RESOLUTIONS[resolution] try: borders, land, ocean = _CARTOPY_FEATURES[resolution] except KeyError: borders = cfeature.NaturalEarthFeature(cfeature.BORDERS.category, cfeature.BORDERS.name, resolution, edgecolor='none', facecolor='none') land = cfeature.NaturalEarthFeature(cfeature.LAND.category, cfeature.LAND.name, resolution, edgecolor='face', facecolor='none') ocean = cfeature.NaturalEarthFeature(cfeature.OCEAN.category, cfeature.OCEAN.name, resolution, edgecolor='face', facecolor='none') _CARTOPY_FEATURES[resolution] = (borders, land, ocean) # Draw coast lines, country boundaries, fill continents. map_ax.set_axis_bgcolor(water_fill_color) map_ax.add_feature(ocean, facecolor=water_fill_color) map_ax.add_feature(land, facecolor=continent_fill_color) map_ax.add_feature(borders, edgecolor='0.75') map_ax.coastlines(resolution=resolution, color='0.4') # Draw grid lines - TODO: draw_labels=True doesn't work yet. if projection == 'local': map_ax.gridlines() else: # Draw lat/lon grid lines every 30 degrees. map_ax.gridlines(xlocs=range(-180, 181, 30), ylocs=range(-90, 91, 30)) # Plot labels if labels and len(lons) > 0: with map_ax.hold_limits(): for name, xpt, ypt, _colorpt in zip(labels, lons, lats, color): map_ax.text(xpt, ypt, name, weight="heavy", color="k", zorder=100, transform=ccrs.Geodetic(), path_effects=[ PathEffects.withStroke(linewidth=3, foreground="white") ]) scatter = map_ax.scatter(lons, lats, marker=marker, s=size, c=color, zorder=10, cmap=colormap, transform=ccrs.Geodetic()) if title: plt.suptitle(title) # Only show the colorbar for more than one event. if show_colorbar: if colorbar_ticklabel_format is not None: if isinstance(colorbar_ticklabel_format, (str, native_str)): formatter = FormatStrFormatter(colorbar_ticklabel_format) elif hasattr(colorbar_ticklabel_format, '__call__'): formatter = FuncFormatter(colorbar_ticklabel_format) elif isinstance(colorbar_ticklabel_format, Formatter): formatter = colorbar_ticklabel_format locator = MaxNLocator(5) else: if datetimeplot: locator = AutoDateLocator() formatter = AutoDateFormatter(locator) # Compat with old matplotlib versions. if hasattr(formatter, "scaled"): formatter.scaled[1 / (24. * 60.)] = '%H:%M:%S' else: locator = None formatter = None cb = Colorbar(cm_ax, scatter, cmap=colormap, orientation='horizontal', ticks=locator, format=formatter) # Compat with old matplotlib versions. if hasattr(cb, "update_ticks"): cb.update_ticks() if show: plt.show() return fig
class ColorbarWidget(QWidget): colorbarChanged = Signal() # The parent should simply redraw their canvas def __init__(self, parent=None): super(ColorbarWidget, self).__init__(parent) self.setWindowTitle("Colorbar") self.setMaximumWidth(200) self.cmap = QComboBox() self.cmap.addItems(sorted(cm.cmap_d.keys())) self.cmap.currentIndexChanged.connect(self.cmap_index_changed) self.cmin = QLineEdit() self.cmin_value = 0 self.cmin.setMaximumWidth(100) self.cmin.editingFinished.connect(self.clim_changed) self.cmin_layout = QHBoxLayout() self.cmin_layout.addStretch() self.cmin_layout.addWidget(self.cmin) self.cmin_layout.addStretch() self.cmax = QLineEdit() self.cmax_value = 1 self.cmax.setMaximumWidth(100) self.cmax.editingFinished.connect(self.clim_changed) self.cmin.setValidator(QDoubleValidator()) self.cmax.setValidator(QDoubleValidator()) self.cmax_layout = QHBoxLayout() self.cmax_layout.addStretch() self.cmax_layout.addWidget(self.cmax) self.cmax_layout.addStretch() self.norm_layout = QHBoxLayout() self.norm = QComboBox() self.norm.addItems(NORM_OPTS) self.norm.currentIndexChanged.connect(self.norm_changed) self.powerscale = QLineEdit() self.powerscale_value = 2 self.powerscale.setText("2") self.powerscale.setValidator(QDoubleValidator(0.001,100,3)) self.powerscale.setMaximumWidth(50) self.powerscale.editingFinished.connect(self.norm_changed) self.powerscale.hide() self.powerscale_label = QLabel("n=") self.powerscale_label.hide() self.norm_layout.addStretch() self.norm_layout.addWidget(self.norm) self.norm_layout.addStretch() self.norm_layout.addWidget(self.powerscale_label) self.norm_layout.addWidget(self.powerscale) self.autoscale = QCheckBox("Autoscaling") self.autoscale.setChecked(True) self.autoscale.stateChanged.connect(self.update_clim) self.canvas = FigureCanvas(Figure()) if parent: # Set facecolor to match parent self.canvas.figure.set_facecolor(parent.palette().window().color().getRgbF()) self.ax = self.canvas.figure.add_axes([0.4,0.05,0.2,0.9]) # layout self.layout = QVBoxLayout(self) self.layout.addWidget(self.cmap) self.layout.addLayout(self.cmax_layout) self.layout.addWidget(self.canvas, stretch=1) self.layout.addLayout(self.cmin_layout) self.layout.addLayout(self.norm_layout) self.layout.addWidget(self.autoscale) def set_mappable(self, mappable): """ When a new plot is created this method should be called with the new mappable """ self.ax.clear() try: # Use current cmap cmap = self.colorbar.get_cmap() except AttributeError: try: # else use viridis cmap = cm.viridis except AttributeError: # else default cmap = None self.colorbar = Colorbar(ax=self.ax, mappable=mappable) self.cmin_value, self.cmax_value = self.colorbar.get_clim() self.update_clim_text() self.cmap_changed(cmap) self.cmap.setCurrentIndex(sorted(cm.cmap_d.keys()).index(self.colorbar.get_cmap().name)) self.redraw() def cmap_index_changed(self): self.cmap_changed(self.cmap.currentText()) def cmap_changed(self, name): self.colorbar.set_cmap(name) self.colorbar.mappable.set_cmap(name) self.redraw() def norm_changed(self): """ Called when a different normalization is selected """ idx = self.norm.currentIndex() if NORM_OPTS[idx] == 'Power': self.powerscale.show() self.powerscale_label.show() else: self.powerscale.hide() self.powerscale_label.hide() self.colorbar.mappable.set_norm(self.get_norm()) self.set_mappable(self.colorbar.mappable) def get_norm(self): """ This will create a matplotlib.colors.Normalize from selected idx, limits and powerscale """ idx = self.norm.currentIndex() if self.autoscale.isChecked(): cmin = cmax = None else: cmin = self.cmin_value cmax = self.cmax_value if NORM_OPTS[idx] == 'Power': if self.powerscale.hasAcceptableInput(): self.powerscale_value = float(self.powerscale.text()) return PowerNorm(gamma=self.powerscale_value, vmin=cmin, vmax=cmax) elif NORM_OPTS[idx] == "SymmetricLog10": return SymLogNorm(1e-8 if cmin is None else max(1e-8, abs(cmin)*1e-3), vmin=cmin, vmax=cmax) else: return Normalize(vmin=cmin, vmax=cmax) def clim_changed(self): """ Called when either the min or max is changed. Will unset the autoscale. """ self.autoscale.blockSignals(True) self.autoscale.setChecked(False) self.autoscale.blockSignals(False) self.update_clim() def update_clim(self): """ This will update the clim of the plot based on min, max, and autoscale """ if self.autoscale.isChecked(): data = self.colorbar.mappable.get_array() try: try: self.cmin_value = data[~data.mask].min() self.cmax_value = data[~data.mask].max() except AttributeError: self.cmin_value = np.nanmin(data) self.cmax_value = np.nanmax(data) except (ValueError, RuntimeWarning): # all values mask pass self.update_clim_text() else: if self.cmin.hasAcceptableInput(): cmin = float(self.cmin.text()) if cmin < self.cmax_value: self.cmin_value = cmin else: # reset values back self.update_clim_text() if self.cmax.hasAcceptableInput(): cmax = float(self.cmax.text()) if cmax > self.cmin_value: self.cmax_value = cmax else: #reset values back self.update_clim_text() self.colorbar.set_clim(self.cmin_value, self.cmax_value) self.redraw() def update_clim_text(self): """ Update displayed limit values based on stored ones """ self.cmin.setText("{:.4}".format(self.cmin_value)) self.cmax.setText("{:.4}".format(self.cmax_value)) def redraw(self): """ Redraws the colobar and emits signal to cause the parent to redraw """ self.colorbar.update_ticks() self.colorbar.draw_all() self.canvas.draw_idle() self.colorbarChanged.emit()
class ColorbarWidget(QWidget): colorbarChanged = Signal() # The parent should simply redraw their canvas def __init__(self, parent=None): super(ColorbarWidget, self).__init__(parent) self.setWindowTitle("Colorbar") self.setMaximumWidth(200) self.dval = QDoubleValidator() self.cmin = QLineEdit() self.cmin_value = 0 self.cmin.setMaximumWidth(100) self.cmin.editingFinished.connect(self.clim_changed) self.cmin_layout = QHBoxLayout() self.cmin_layout.addStretch() self.cmin_layout.addWidget(self.cmin) self.cmin_layout.addStretch() self.cmax = QLineEdit() self.cmax_value = 1 self.cmax.setMaximumWidth(100) self.cmax.editingFinished.connect(self.clim_changed) self.cmin.setValidator(self.dval) self.cmax.setValidator(self.dval) self.cmax_layout = QHBoxLayout() self.cmax_layout.addStretch() self.cmax_layout.addWidget(self.cmax) self.cmax_layout.addStretch() self.norm_layout = QHBoxLayout() self.norm = QComboBox() self.norm.addItems(NORM_OPTS) self.norm.currentIndexChanged.connect(self.norm_changed) self.powerscale = QLineEdit() self.powerscale_value = 2 self.powerscale.setText("2") self.powerscale.setValidator(QDoubleValidator(0.001,100,3)) self.powerscale.setMaximumWidth(50) self.powerscale.editingFinished.connect(self.norm_changed) self.powerscale.hide() self.powerscale_label = QLabel("n=") self.powerscale_label.hide() self.norm_layout.addStretch() self.norm_layout.addWidget(self.norm) self.norm_layout.addStretch() self.norm_layout.addWidget(self.powerscale_label) self.norm_layout.addWidget(self.powerscale) self.autoscale = QCheckBox("Autoscaling") self.autoscale.setChecked(True) self.autoscale.stateChanged.connect(self.update_clim) self.canvas = FigureCanvas(Figure()) if parent: # Set facecolor to match parent self.canvas.figure.set_facecolor(parent.palette().window().color().getRgbF()) self.ax = self.canvas.figure.add_axes([0.4,0.05,0.2,0.9]) # layout self.layout = QVBoxLayout(self) self.layout.addLayout(self.cmax_layout) self.layout.addWidget(self.canvas, stretch=1) self.layout.addLayout(self.cmin_layout) self.layout.addLayout(self.norm_layout) self.layout.addWidget(self.autoscale) def set_mappable(self, mappable): """ When a new plot is created this method should be called with the new mappable """ self.ax.clear() self.colorbar = Colorbar(ax=self.ax, mappable=mappable) self.cmin_value, self.cmax_value = self.colorbar.get_clim() self.update_clim_text() self.redraw() def norm_changed(self): """ Called when a different normalization is selected """ idx = self.norm.currentIndex() if NORM_OPTS[idx] == 'Power': self.powerscale.show() self.powerscale_label.show() else: self.powerscale.hide() self.powerscale_label.hide() self.colorbar.mappable.set_norm(self.get_norm()) self.colorbarChanged.emit() def get_norm(self): """ This will create a matplotlib.colors.Normalize from selected idx, limits and powerscale """ idx = self.norm.currentIndex() if self.autoscale.isChecked(): cmin = cmax = None else: cmin = self.cmin_value cmax = self.cmax_value if NORM_OPTS[idx] == 'Power': if self.powerscale.hasAcceptableInput(): self.powerscale_value = float(self.powerscale.text()) return PowerNorm(gamma=self.powerscale_value, vmin=cmin, vmax=cmax) elif NORM_OPTS[idx] == "SymmetricLog10": return SymLogNorm(1e-8 if cmin is None else max(1e-8, abs(cmin)*1e-3), vmin=cmin, vmax=cmax) else: return Normalize(vmin=cmin, vmax=cmax) def clim_changed(self): """ Called when either the min or max is changed. Will unset the autoscale. """ self.autoscale.blockSignals(True) self.autoscale.setChecked(False) self.autoscale.blockSignals(False) self.update_clim() def update_clim(self): """ This will update the clim of the plot based on min, max, and autoscale """ if self.autoscale.isChecked(): data = self.colorbar.mappable.get_array() try: try: self.cmin_value = data[~data.mask].min() self.cmax_value = data[~data.mask].max() except AttributeError: self.cmin_value = np.nanmin(data) self.cmax_value = np.nanmax(data) except (ValueError, RuntimeWarning): # all values mask pass self.update_clim_text() else: if self.cmin.hasAcceptableInput(): self.cmin_value = float(self.cmin.text()) if self.cmax.hasAcceptableInput(): self.cmax_value = float(self.cmax.text()) self.colorbar.set_clim(self.cmin_value, self.cmax_value) self.redraw() def update_clim_text(self): """ Update displayed limit values based on stored ones """ self.cmin.setText("{:.4}".format(self.cmin_value)) self.cmax.setText("{:.4}".format(self.cmax_value)) def redraw(self): """ Redraws the colobar and emits signal to cause the parent to redraw """ self.colorbar.update_ticks() self.colorbar.draw_all() self.canvas.draw_idle() self.colorbarChanged.emit()
def plot_cartopy(lons, lats, size, color, labels=None, projection='global', resolution='110m', continent_fill_color='0.8', water_fill_color='1.0', colormap=None, colorbar=None, marker="o", title=None, colorbar_ticklabel_format=None, show=True, proj_kwargs=None, **kwargs): # @UnusedVariable """ Creates a Cartopy plot with a data point scatter plot. :type lons: list/tuple of floats :param lons: Longitudes of the data points. :type lats: list/tuple of floats :param lats: Latitudes of the data points. :type size: float or list/tuple of floats :param size: Size of the individual points in the scatter plot. :type color: list/tuple of floats (or objects that can be converted to floats, like e.g. :class:`~obspy.core.utcdatetime.UTCDateTime`) :param color: Color information of the individual data points to be used in the specified color map (e.g. origin depths, origin times). :type labels: list/tuple of str :param labels: Annotations for the individual data points. :type projection: str, optional :param projection: The map projection. Currently supported are: * ``"global"`` (Will plot the whole world using :class:`~cartopy.crs.Mollweide`.) * ``"ortho"`` (Will center around the mean lat/long using :class:`~cartopy.crs.Orthographic`.) * ``"local"`` (Will plot around local events using :class:`~cartopy.crs.AlbersEqualArea`.) * Any other Cartopy :class:`~cartopy.crs.Projection`. An instance of this class will be created using the supplied ``proj_kwargs``. Defaults to "global" :type resolution: str, optional :param resolution: Resolution of the boundary database to use. Will be passed directly to the Cartopy module. Possible values are: * ``"110m"`` * ``"50m"`` * ``"10m"`` Defaults to ``"110m"``. For compatibility, you may also specify any of the Basemap resolutions defined in :func:`plot_basemap`. :type continent_fill_color: Valid matplotlib color, optional :param continent_fill_color: Color of the continents. Defaults to ``"0.9"`` which is a light gray. :type water_fill_color: Valid matplotlib color, optional :param water_fill_color: Color of all water bodies. Defaults to ``"white"``. :type colormap: str, any matplotlib colormap, optional :param colormap: The colormap for color-coding the events as provided in `color` kwarg. The event with the smallest `color` property will have the color of one end of the colormap and the event with the highest `color` property the color of the other end with all other events in between. Defaults to None which will use the default matplotlib colormap. :type colorbar: bool, optional :param colorbar: When left `None`, a colorbar is plotted if more than one object is plotted. Using `True`/`False` the colorbar can be forced on/off. :type title: str :param title: Title above plot. :type colorbar_ticklabel_format: str or function or subclass of :class:`matplotlib.ticker.Formatter` :param colorbar_ticklabel_format: Format string or Formatter used to format colorbar tick labels. :type show: bool :param show: Whether to show the figure after plotting or not. Can be used to do further customization of the plot before showing it. :type proj_kwargs: dict :param proj_kwargs: Keyword arguments to pass to the Cartopy :class:`~cartopy.ccrs.Projection`. In this dictionary, you may specify ``central_longitude='auto'`` or ``central_latitude='auto'`` to have this function calculate the latitude or longitude as it would for other projections. Some arguments may be ignored if you choose one of the built-in ``projection`` choices. """ import matplotlib.pyplot as plt if isinstance(color[0], (datetime.datetime, UTCDateTime)): datetimeplot = True color = [date2num(getattr(t, 'datetime', t)) for t in color] else: datetimeplot = False fig = plt.figure() # The colorbar should only be plotted if more then one event is # present. if colorbar is not None: show_colorbar = colorbar else: if len(lons) > 1 and hasattr(color, "__len__") and \ not isinstance(color, (str, native_str)): show_colorbar = True else: show_colorbar = False if projection == "local": ax_x0, ax_width = 0.10, 0.80 elif projection == "global": ax_x0, ax_width = 0.01, 0.98 else: ax_x0, ax_width = 0.05, 0.90 proj_kwargs = proj_kwargs or {} if projection == 'global': proj_kwargs['central_longitude'] = np.mean(lons) proj = ccrs.Mollweide(**proj_kwargs) elif projection == 'ortho': proj_kwargs['central_latitude'] = np.mean(lats) proj_kwargs['central_longitude'] = mean_longitude(lons) proj = ccrs.Orthographic(**proj_kwargs) elif projection == 'local': if min(lons) < -150 and max(lons) > 150: max_lons = max(np.array(lons) % 360) min_lons = min(np.array(lons) % 360) else: max_lons = max(lons) min_lons = min(lons) lat_0 = max(lats) / 2. + min(lats) / 2. lon_0 = max_lons / 2. + min_lons / 2. if lon_0 > 180: lon_0 -= 360 deg2m_lat = 2 * np.pi * 6371 * 1000 / 360 deg2m_lon = deg2m_lat * np.cos(lat_0 / 180 * np.pi) if len(lats) > 1: height = (max(lats) - min(lats)) * deg2m_lat width = (max_lons - min_lons) * deg2m_lon margin = 0.2 * (width + height) height += margin width += margin else: height = 2.0 * deg2m_lat width = 5.0 * deg2m_lon # Do intelligent aspect calculation for local projection # adjust to figure dimensions w, h = fig.get_size_inches() aspect = w / h if show_colorbar: aspect *= 1.2 if width / height < aspect: width = height * aspect else: height = width / aspect proj_kwargs['central_latitude'] = lat_0 proj_kwargs['central_longitude'] = lon_0 proj_kwargs['standard_parallels'] = [lat_0, lat_0] proj = ccrs.AlbersEqualArea(**proj_kwargs) # User-supplied projection. elif isinstance(projection, type): if 'central_longitude' in proj_kwargs: if proj_kwargs['central_longitude'] == 'auto': proj_kwargs['central_longitude'] = mean_longitude(lons) if 'central_latitude' in proj_kwargs: if proj_kwargs['central_latitude'] == 'auto': proj_kwargs['central_latitude'] = np.mean(lats) if 'pole_longitude' in proj_kwargs: if proj_kwargs['pole_longitude'] == 'auto': proj_kwargs['pole_longitude'] = np.mean(lons) if 'pole_latitude' in proj_kwargs: if proj_kwargs['pole_latitude'] == 'auto': proj_kwargs['pole_latitude'] = np.mean(lats) proj = projection(**proj_kwargs) else: msg = "Projection '%s' not supported." % projection raise ValueError(msg) if show_colorbar: map_ax = fig.add_axes([ax_x0, 0.13, ax_width, 0.77], projection=proj) cm_ax = fig.add_axes([ax_x0, 0.05, ax_width, 0.05]) plt.sca(map_ax) else: ax_y0, ax_height = 0.05, 0.85 if projection == "local": ax_y0 += 0.05 ax_height -= 0.05 map_ax = fig.add_axes([ax_x0, ax_y0, ax_width, ax_height], projection=proj) if projection == 'local': x0, y0 = proj.transform_point(lon_0, lat_0, proj.as_geodetic()) map_ax.set_xlim(x0 - width / 2, x0 + width / 2) map_ax.set_ylim(y0 - height / 2, y0 + height / 2) else: map_ax.set_global() # Pick features at specified resolution. resolution = _CARTOPY_RESOLUTIONS[resolution] try: borders, land, ocean = _CARTOPY_FEATURES[resolution] except KeyError: borders = cfeature.NaturalEarthFeature(cfeature.BORDERS.category, cfeature.BORDERS.name, resolution, edgecolor='none', facecolor='none') land = cfeature.NaturalEarthFeature(cfeature.LAND.category, cfeature.LAND.name, resolution, edgecolor='face', facecolor='none') ocean = cfeature.NaturalEarthFeature(cfeature.OCEAN.category, cfeature.OCEAN.name, resolution, edgecolor='face', facecolor='none') _CARTOPY_FEATURES[resolution] = (borders, land, ocean) # Draw coast lines, country boundaries, fill continents. if MATPLOTLIB_VERSION >= [2, 0, 0]: map_ax.set_facecolor(water_fill_color) else: map_ax.set_axis_bgcolor(water_fill_color) map_ax.add_feature(ocean, facecolor=water_fill_color) map_ax.add_feature(land, facecolor=continent_fill_color) map_ax.add_feature(borders, edgecolor='0.75') map_ax.coastlines(resolution=resolution, color='0.4') # Draw grid lines - TODO: draw_labels=True doesn't work yet. if projection == 'local': map_ax.gridlines() else: # Draw lat/lon grid lines every 30 degrees. map_ax.gridlines(xlocs=range(-180, 181, 30), ylocs=range(-90, 91, 30)) # Plot labels if labels and len(lons) > 0: with map_ax.hold_limits(): for name, xpt, ypt, _colorpt in zip(labels, lons, lats, color): map_ax.text(xpt, ypt, name, weight="heavy", color="k", zorder=100, transform=ccrs.Geodetic(), path_effects=[ PathEffects.withStroke(linewidth=3, foreground="white")]) scatter = map_ax.scatter(lons, lats, marker=marker, s=size, c=color, zorder=10, cmap=colormap, transform=ccrs.Geodetic()) if title: plt.suptitle(title) # Only show the colorbar for more than one event. if show_colorbar: if colorbar_ticklabel_format is not None: if isinstance(colorbar_ticklabel_format, (str, native_str)): formatter = FormatStrFormatter(colorbar_ticklabel_format) elif hasattr(colorbar_ticklabel_format, '__call__'): formatter = FuncFormatter(colorbar_ticklabel_format) elif isinstance(colorbar_ticklabel_format, Formatter): formatter = colorbar_ticklabel_format locator = MaxNLocator(5) else: if datetimeplot: locator = AutoDateLocator() formatter = AutoDateFormatter(locator) # Compat with old matplotlib versions. if hasattr(formatter, "scaled"): formatter.scaled[1 / (24. * 60.)] = '%H:%M:%S' else: locator = None formatter = None cb = Colorbar(cm_ax, scatter, cmap=colormap, orientation='horizontal', ticks=locator, format=formatter) # Compat with old matplotlib versions. if hasattr(cb, "update_ticks"): cb.update_ticks() if show: plt.show() return fig
def add_ortho(lats, lons, colors, CClim, central_longitude, central_latitude, text=None, size=50, marker=['o', 'd'], colormap='viridis', fig=None, rect=[0.0, 0.0, 1.0, 1.0]): if not fig: fig = plt.figure() proj = ccrs.Orthographic(central_longitude=central_longitude, central_latitude=central_latitude) # left, bottom, width, height ax = fig.add_axes([rect[0], rect[1] + rect[3] * 0.12, rect[2], rect[3] * 0.85], projection=proj) cm_ax = fig.add_axes([rect[0], rect[1], rect[2], rect[3] * 0.08]) plt.sca(ax) # make the map global rather than have it zoom in to # the extents of any plotted data ax.set_global() ax.stock_img() ax.coastlines() ax.gridlines() lats_mark1 = [] lons_mark1 = [] colors_mark1 = [] lats_mark2 = [] lons_mark2 = [] colors_mark2 = [] cmap = get_cmap(colormap) cmap.set_under('grey') for lon, lat, color in zip(lons, lats, colors): if color > CClim: lats_mark1.append(lat) lons_mark1.append(lon) colors_mark1.append(color) else: lats_mark2.append(lat) lons_mark2.append(lon) colors_mark2.append(color) if len(lons_mark1) > 0: scatter = ax.scatter(lons_mark1, lats_mark1, s=size, c=colors_mark1, marker=marker[0], cmap=cmap, vmin=CClim, vmax=1, zorder=10, transform=ccrs.Geodetic()) if len(lons_mark2) > 0: scatter = ax.scatter(lons_mark2, lats_mark2, s=size, c=colors_mark2, marker=marker[1], cmap=cmap, vmin=CClim, vmax=1, zorder=10, transform=ccrs.Geodetic()) locator = MaxNLocator(5) cb = Colorbar(cm_ax, scatter, cmap=cmap, orientation='horizontal', ticks=locator, extend='min') cb.set_label('CC') # Compat with old matplotlib versions. if hasattr(cb, "update_ticks"): cb.update_ticks() ax.plot(central_longitude, central_latitude, color='red', marker='*', markersize=np.sqrt(size)) if (text): for lat, lon, text in zip(lats, lons, text): # Avoid plotting invisible texts. They clutter at the origin # otherwise dist = locations2degrees(lat, lon, central_latitude, central_longitude) if (dist < 90): plt.text(lon, lat, text, weight="heavy", transform=ccrs.Geodetic(), color="k", zorder=100, path_effects=[ PathEffects.withStroke(linewidth=3, foreground="white")]) return ax
def plot_basemap(lons, lats, size, color, labels=None, projection='global', resolution='l', continent_fill_color='0.8', water_fill_color='1.0', colormap=None, colorbar=None, marker="o", title=None, colorbar_ticklabel_format=None, show=True, **kwargs): # @UnusedVariable """ Creates a basemap plot with a data point scatter plot. :type lons: list/tuple of floats :param lons: Longitudes of the data points. :type lats: list/tuple of floats :param lats: Latitudes of the data points. :type size: float or list/tuple of floats :param size: Size of the individual points in the scatter plot. :type color: list/tuple of floats (or objects that can be converted to floats, like e.g. :class:`~obspy.core.utcdatetime.UTCDateTime`) :param color: Color information of the individual data points to be used in the specified color map (e.g. origin depths, origin times). :type labels: list/tuple of str :param labels: Annotations for the individual data points. :type projection: str, optional :param projection: The map projection. Currently supported are * ``"global"`` (Will plot the whole world.) * ``"ortho"`` (Will center around the mean lat/long.) * ``"local"`` (Will plot around local events) Defaults to "global" :type resolution: str, optional :param resolution: Resolution of the boundary database to use. Will be based directly to the basemap module. Possible values are * ``"c"`` (crude) * ``"l"`` (low) * ``"i"`` (intermediate) * ``"h"`` (high) * ``"f"`` (full) Defaults to ``"l"``. For compatibility, you may also specify any of the Cartopy resolutions defined in :func:`plot_cartopy`. :type continent_fill_color: Valid matplotlib color, optional :param continent_fill_color: Color of the continents. Defaults to ``"0.9"`` which is a light gray. :type water_fill_color: Valid matplotlib color, optional :param water_fill_color: Color of all water bodies. Defaults to ``"white"``. :type colormap: str, any matplotlib colormap, optional :param colormap: The colormap for color-coding the events as provided in `color` kwarg. The event with the smallest `color` property will have the color of one end of the colormap and the event with the highest `color` property the color of the other end with all other events in between. Defaults to None which will use the default matplotlib colormap. :type colorbar: bool, optional :param colorbar: When left `None`, a colorbar is plotted if more than one object is plotted. Using `True`/`False` the colorbar can be forced on/off. :type title: str :param title: Title above plot. :type colorbar_ticklabel_format: str or function or subclass of :class:`matplotlib.ticker.Formatter` :param colorbar_ticklabel_format: Format string or Formatter used to format colorbar tick labels. :type show: bool :param show: Whether to show the figure after plotting or not. Can be used to do further customization of the plot before showing it. """ min_color = min(color) max_color = max(color) if any([isinstance(c, (datetime.datetime, UTCDateTime)) for c in color]): datetimeplot = True color = [np.isfinite(float(t)) and date2num(t) or np.nan for t in color] else: datetimeplot = False scal_map = ScalarMappable(norm=Normalize(min_color, max_color), cmap=colormap) scal_map.set_array(np.linspace(0, 1, 1)) fig = plt.figure() # The colorbar should only be plotted if more then one event is # present. if colorbar is not None: show_colorbar = colorbar else: if len(lons) > 1 and hasattr(color, "__len__") and \ not isinstance(color, (str, native_str)): show_colorbar = True else: show_colorbar = False if projection == "local": ax_x0, ax_width = 0.10, 0.80 elif projection == "global": ax_x0, ax_width = 0.01, 0.98 else: ax_x0, ax_width = 0.05, 0.90 if show_colorbar: map_ax = fig.add_axes([ax_x0, 0.13, ax_width, 0.77]) cm_ax = fig.add_axes([ax_x0, 0.05, ax_width, 0.05]) else: ax_y0, ax_height = 0.05, 0.85 if projection == "local": ax_y0 += 0.05 ax_height -= 0.05 map_ax = fig.add_axes([ax_x0, ax_y0, ax_width, ax_height]) if projection == 'global': bmap = Basemap(projection='moll', lon_0=round(np.mean(lons), 4), resolution=_BASEMAP_RESOLUTIONS[resolution], ax=map_ax) elif projection == 'ortho': bmap = Basemap(projection='ortho', resolution=_BASEMAP_RESOLUTIONS[resolution], area_thresh=1000.0, lat_0=round(np.mean(lats), 4), lon_0=round(np.mean(lons), 4), ax=map_ax) elif projection == 'local': if min(lons) < -150 and max(lons) > 150: max_lons = max(np.array(lons) % 360) min_lons = min(np.array(lons) % 360) else: max_lons = max(lons) min_lons = min(lons) lat_0 = max(lats) / 2. + min(lats) / 2. lon_0 = max_lons / 2. + min_lons / 2. if lon_0 > 180: lon_0 -= 360 deg2m_lat = 2 * np.pi * 6371 * 1000 / 360 deg2m_lon = deg2m_lat * np.cos(lat_0 / 180 * np.pi) if len(lats) > 1: height = (max(lats) - min(lats)) * deg2m_lat width = (max_lons - min_lons) * deg2m_lon margin = 0.2 * (width + height) height += margin width += margin else: height = 2.0 * deg2m_lat width = 5.0 * deg2m_lon # do intelligent aspect calculation for local projection # adjust to figure dimensions w, h = fig.get_size_inches() aspect = w / h if show_colorbar: aspect *= 1.2 if width / height < aspect: width = height * aspect else: height = width / aspect bmap = Basemap(projection='aea', resolution=_BASEMAP_RESOLUTIONS[resolution], area_thresh=1000.0, lat_0=round(lat_0, 4), lon_0=round(lon_0, 4), width=width, height=height, ax=map_ax) # not most elegant way to calculate some round lats/lons def linspace2(val1, val2, N): """ returns around N 'nice' values between val1 and val2 """ dval = val2 - val1 round_pos = int(round(-np.log10(1. * dval / N))) # Fake negative rounding as not supported by future as of now. if round_pos < 0: factor = 10 ** (abs(round_pos)) delta = round(2. * dval / N / factor) * factor / 2 else: delta = round(2. * dval / N, round_pos) / 2 new_val1 = np.ceil(val1 / delta) * delta new_val2 = np.floor(val2 / delta) * delta N = (new_val2 - new_val1) / delta + 1 return np.linspace(new_val1, new_val2, N) N1 = int(np.ceil(height / max(width, height) * 8)) N2 = int(np.ceil(width / max(width, height) * 8)) parallels = linspace2(lat_0 - height / 2 / deg2m_lat, lat_0 + height / 2 / deg2m_lat, N1) # Old basemap versions have problems with non-integer parallels. try: bmap.drawparallels(parallels, labels=[0, 1, 1, 0]) except KeyError: parallels = sorted(list(set(map(int, parallels)))) bmap.drawparallels(parallels, labels=[0, 1, 1, 0]) if min(lons) < -150 and max(lons) > 150: lon_0 %= 360 meridians = linspace2(lon_0 - width / 2 / deg2m_lon, lon_0 + width / 2 / deg2m_lon, N2) meridians[meridians > 180] -= 360 bmap.drawmeridians(meridians, labels=[1, 0, 0, 1]) else: msg = "Projection '%s' not supported." % projection raise ValueError(msg) # draw coast lines, country boundaries, fill continents. map_ax.set_axis_bgcolor(water_fill_color) bmap.drawcoastlines(color="0.4") bmap.drawcountries(color="0.75") bmap.fillcontinents(color=continent_fill_color, lake_color=water_fill_color) # draw the edge of the bmap projection region (the projection limb) bmap.drawmapboundary(fill_color=water_fill_color) # draw lat/lon grid lines every 30 degrees. bmap.drawmeridians(np.arange(-180, 180, 30)) bmap.drawparallels(np.arange(-90, 90, 30)) # compute the native bmap projection coordinates for events. x, y = bmap(lons, lats) # plot labels if labels: if 100 > len(lons) > 1: for name, xpt, ypt, _colorpt in zip(labels, x, y, color): # Check if the point can actually be seen with the current bmap # projection. The bmap object will set the coordinates to very # large values if it cannot project a point. if xpt > 1e25: continue map_ax.text(xpt, ypt, name, weight="heavy", color="k", zorder=100, path_effects=[ PathEffects.withStroke(linewidth=3, foreground="white")]) elif len(lons) == 1: map_ax.text(x[0], y[0], labels[0], weight="heavy", color="k", path_effects=[ PathEffects.withStroke(linewidth=3, foreground="white")]) # scatter plot is removing valid x/y points with invalid color value, # so we plot those points separately. try: nan_points = np.isnan(np.array(color, dtype=np.float)) except ValueError: # `color' was not a list of values, but a list of colors. pass else: if nan_points.any(): x_ = np.array(x)[nan_points] y_ = np.array(y)[nan_points] size_ = np.array(size)[nan_points] scatter = bmap.scatter(x_, y_, marker=marker, s=size_, c="0.3", zorder=10, cmap=None) scatter = bmap.scatter(x, y, marker=marker, s=size, c=color, zorder=10, cmap=colormap) if title: plt.suptitle(title) # Only show the colorbar for more than one event. if show_colorbar: if colorbar_ticklabel_format is not None: if isinstance(colorbar_ticklabel_format, (str, native_str)): formatter = FormatStrFormatter(colorbar_ticklabel_format) elif hasattr(colorbar_ticklabel_format, '__call__'): formatter = FuncFormatter(colorbar_ticklabel_format) elif isinstance(colorbar_ticklabel_format, Formatter): formatter = colorbar_ticklabel_format locator = MaxNLocator(5) else: if datetimeplot: locator = AutoDateLocator() formatter = AutoDateFormatter(locator) # Compat with old matplotlib versions. if hasattr(formatter, "scaled"): formatter.scaled[1 / (24. * 60.)] = '%H:%M:%S' else: locator = None formatter = None cb = Colorbar(cm_ax, scatter, cmap=colormap, orientation='horizontal', ticks=locator, format=formatter) # Compat with old matplotlib versions. if hasattr(cb, "update_ticks"): cb.update_ticks() if show: plt.show() return fig
class ColorbarWidget(QWidget): colorbarChanged = Signal() # The parent should simply redraw their canvas scaleNormChanged = Signal() # register additional color maps from file register_customized_colormaps() # create the list cmap_list = sorted( [cmap for cmap in cm.cmap_d.keys() if not cmap.endswith('_r')]) def __init__(self, parent=None, default_norm_scale=None): """ :param default_scale: None uses linear, else either a string or tuple(string, other arguments), e.g. tuple('Power', exponent) """ super(ColorbarWidget, self).__init__(parent) self.setWindowTitle("Colorbar") self.setMaximumWidth(100) self.cmap = QComboBox() self.cmap.addItems(self.cmap_list) self.cmap.currentIndexChanged.connect(self.cmap_index_changed) self.crev = QCheckBox('Reverse') self.crev.stateChanged.connect(self.crev_checked_changed) self.cmin = QLineEdit() self.cmin_value = 0 self.cmin.setMaximumWidth(100) self.cmin.editingFinished.connect(self.clim_changed) self.cmin_layout = QHBoxLayout() self.cmin_layout.addStretch() self.cmin_layout.addWidget(self.cmin) self.cmin_layout.addStretch() self.linear_validator = QDoubleValidator(parent=self) self.log_validator = QDoubleValidator(MIN_LOG_VALUE, sys.float_info.max, 3, self) self.cmax = QLineEdit() self.cmax_value = 1 self.cmax.setMaximumWidth(100) self.cmax.editingFinished.connect(self.clim_changed) self.cmax_layout = QHBoxLayout() self.cmax_layout.addStretch() self.cmax_layout.addWidget(self.cmax) self.cmax_layout.addStretch() norm_scale = 'Linear' powerscale_value = 2 if default_norm_scale in NORM_OPTS: norm_scale = default_norm_scale if isinstance(default_norm_scale, tuple) and default_norm_scale[0] in NORM_OPTS: norm_scale = default_norm_scale[0] if norm_scale == 'Power': powerscale_value = float(default_norm_scale[1]) self.norm_layout = QHBoxLayout() self.norm = QComboBox() self.norm.addItems(NORM_OPTS) self.norm.setCurrentText(norm_scale) self.norm.currentIndexChanged.connect(self.norm_changed) self.update_clim_validator() self.powerscale = QLineEdit() self.powerscale_value = powerscale_value self.powerscale.setText(str(powerscale_value)) self.powerscale.setValidator(QDoubleValidator(0.001, 100, 3)) self.powerscale.setMaximumWidth(50) self.powerscale.editingFinished.connect(self.norm_changed) self.powerscale_label = QLabel("n=") if norm_scale != 'Power': self.powerscale.hide() self.powerscale_label.hide() self.norm_layout.addStretch() self.norm_layout.addWidget(self.norm) self.norm_layout.addStretch() self.norm_layout.addWidget(self.powerscale_label) self.norm_layout.addWidget(self.powerscale) self.autoscale = QCheckBox("Autoscaling") self.autoscale.setChecked(True) self.autoscale.stateChanged.connect(self.update_clim) self.canvas = FigureCanvas(Figure()) if parent: # Set facecolor to match parent self.canvas.figure.set_facecolor( parent.palette().window().color().getRgbF()) self.ax = self.canvas.figure.add_axes([0.0, 0.02, 0.2, 0.97]) # layout self.layout = QVBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(2) self.layout.addWidget(self.cmap) self.layout.addWidget(self.crev) self.layout.addLayout(self.cmax_layout) self.layout.addWidget(self.canvas, stretch=1) self.layout.addLayout(self.cmin_layout) self.layout.addLayout(self.norm_layout) self.layout.addWidget(self.autoscale) def set_mappable(self, mappable): """ When a new plot is created this method should be called with the new mappable """ # sanity check the mappable mappable = self._validate_mappable(mappable) self.ax.clear() try: # Use current cmap cmap = get_current_cmap(self.colorbar) except AttributeError: # else use default cmap = ConfigService.getString("plots.images.Colormap") self.colorbar = Colorbar(ax=self.ax, mappable=mappable) self.cmin_value, self.cmax_value = mappable.get_clim() self.update_clim_text() self.cmap_changed(cmap, False) mappable_cmap = get_current_cmap(mappable) if mappable_cmap.name.endswith('_r'): self.crev.setChecked(True) else: self.crev.setChecked(False) self.cmap.setCurrentIndex( self.cmap_list.index(mappable_cmap.name.replace('_r', ''))) self.redraw() def cmap_index_changed(self): self.cmap_changed(self.cmap.currentText(), self.crev.isChecked()) def crev_checked_changed(self): self.cmap_changed(self.cmap.currentText(), self.crev.isChecked()) def cmap_changed(self, name, rev): if rev: name += '_r' self.colorbar.mappable.set_cmap(name) if mpl_version_info() >= (3, 1): self.colorbar.update_normal(self.colorbar.mappable) else: self.colorbar.set_cmap(name) self.redraw() def mappable_changed(self): """ Updates the colormap and min/max values of the colorbar when the plot changes via settings. """ mappable_cmap = get_current_cmap(self.colorbar.mappable) low, high = self.colorbar.mappable.get_clim() self.cmin_value = low self.cmax_value = high self.update_clim_text() self.cmap.setCurrentIndex( sorted(cm.cmap_d.keys()).index(mappable_cmap.name)) self.redraw() def norm_changed(self): """ Called when a different normalization is selected """ idx = self.norm.currentIndex() if NORM_OPTS[idx] == 'Power': self.powerscale.show() self.powerscale_label.show() else: self.powerscale.hide() self.powerscale_label.hide() self.colorbar.mappable.set_norm(self.get_norm()) self.set_mappable(self.colorbar.mappable) self.update_clim_validator() self.scaleNormChanged.emit() def get_norm(self): """ This will create a matplotlib.colors.Normalize from selected idx, limits and powerscale """ idx = self.norm.currentIndex() if self.autoscale.isChecked(): cmin = cmax = None else: cmin = self.cmin_value cmax = self.cmax_value if NORM_OPTS[idx] == 'Power': if self.powerscale.hasAcceptableInput(): self.powerscale_value = float(self.powerscale.text()) return PowerNorm(gamma=self.powerscale_value, vmin=cmin, vmax=cmax) elif NORM_OPTS[idx] == "SymmetricLog10": return SymLogNorm( 1e-8 if cmin is None else max(1e-8, abs(cmin) * 1e-3), vmin=cmin, vmax=cmax) elif NORM_OPTS[idx] == "Log": cmin = MIN_LOG_VALUE if cmin is not None and cmin <= 0 else cmin return LogNorm(vmin=cmin, vmax=cmax) else: return Normalize(vmin=cmin, vmax=cmax) def get_colorbar_scale(self): norm = self.colorbar.norm scale = 'linear' kwargs = {} if isinstance(norm, SymLogNorm): scale = 'symlog' elif isinstance(norm, LogNorm): scale = 'log' elif isinstance(norm, PowerNorm): scale = 'function' kwargs = { 'functions': (lambda x: np.power(x, norm.gamma), lambda x: np.power(x, 1 / norm.gamma)) } return scale, kwargs def clim_changed(self): """ Called when either the min or max is changed. Will unset the autoscale. """ self.autoscale.blockSignals(True) self.autoscale.setChecked(False) self.autoscale.blockSignals(False) self.update_clim() def update_clim(self): """ This will update the clim of the plot based on min, max, and autoscale """ if self.autoscale.isChecked(): self._autoscale_clim() else: self._manual_clim() self.colorbar.mappable.set_clim(self.cmin_value, self.cmax_value) self.redraw() def update_clim_text(self): """ Update displayed limit values based on stored ones """ self.cmin.setText("{:.4}".format(self.cmin_value)) self.cmax.setText("{:.4}".format(self.cmax_value)) def redraw(self): """ Redraws the colobar and emits signal to cause the parent to redraw """ self.colorbar.update_ticks() self.colorbar.draw_all() self.canvas.draw_idle() self.colorbarChanged.emit() def update_clim_validator(self): if NORM_OPTS[self.norm.currentIndex()] == "Log": self.cmin.setValidator(self.log_validator) self.cmax.setValidator(self.log_validator) else: self.cmin.setValidator(self.linear_validator) self.cmax.setValidator(self.linear_validator) def _autoscale_clim(self): """Update stored colorbar limits The new limits are found from the colobar data """ data = self.colorbar.mappable.get_array() norm = NORM_OPTS[self.norm.currentIndex()] try: try: masked_data = data[~data.mask] # use the smallest positive value as vmin when using log scale, # matplotlib will take care of the data skipping part. masked_data = masked_data[ data > 0] if norm == "Log" else masked_data self.cmin_value = masked_data.min() self.cmax_value = masked_data.max() except (AttributeError, IndexError): data = data[np.nonzero(data)] if norm == "Log" else data self.cmin_value = np.nanmin(data) self.cmax_value = np.nanmax(data) except (ValueError, RuntimeWarning): # all values mask pass self.update_clim_text() def _manual_clim(self): """Update stored colorbar limits The new limits are found from user input""" if self.cmin.hasAcceptableInput(): cmin = float(self.cmin.text()) if cmin < self.cmax_value: self.cmin_value = cmin else: # reset values back self.update_clim_text() if self.cmax.hasAcceptableInput(): cmax = float(self.cmax.text()) if cmax > self.cmin_value: self.cmax_value = cmax else: # reset values back self.update_clim_text() def _create_linear_normalize_object(self): if self.autoscale.isChecked(): cmin = cmax = None else: cmin = self.cmin_value cmax = self.cmax_value return Normalize(vmin=cmin, vmax=cmax) def _validate_mappable(self, mappable): """Disable the Log option if no positive value can be found from given data (image)""" index = NORM_OPTS.index("Log") if mappable.get_array() is not None: if np.all(mappable.get_array() <= 0): self.norm.model().item(index, 0).setEnabled(False) self.norm.setItemData( index, "Log scale is disabled for non-positive data", Qt.ToolTipRole) if isinstance(mappable.norm, LogNorm): mappable.norm = self._create_linear_normalize_object() self.norm.blockSignals(True) self.norm.setCurrentIndex(0) self.norm.blockSignals(False) else: if not self.norm.model().item(index, 0).isEnabled(): self.norm.model().item(index, 0).setEnabled(True) self.norm.setItemData(index, "", Qt.ToolTipRole) return mappable
def plot_basemap( lons, lats, size, color, labels=None, projection="cyl", resolution="l", continent_fill_color="0.8", water_fill_color="1.0", colormap=None, marker="o", title=None, colorbar_ticklabel_format=None, show=True, **kwargs ): # @UnusedVariable """ Creates a basemap plot with a data point scatter plot. :type lons: list/tuple of floats :param lons: Longitudes of the data points. :type lats: list/tuple of floats :param lats: Latitudes of the data points. :type size: list/tuple of floats (or a single float) :param size: Size of the individual points in the scatter plot. :type color: list/tuple of floats/:class:`~obspy.core.utcdatetime.UTCDateTime` (or a single float) :param color: Color information of the individual data points. Can be :type labels: list/tuple of str :param labels: Annotations for the individual data points. :type projection: str, optional :param projection: The map projection. Currently supported are * ``"cyl"`` (Will plot the whole world.) * ``"ortho"`` (Will center around the mean lat/long.) * ``"local"`` (Will plot around local events) Defaults to "cyl" :type resolution: str, optional :param resolution: Resolution of the boundary database to use. Will be based directly to the basemap module. Possible values are * ``"c"`` (crude) * ``"l"`` (low) * ``"i"`` (intermediate) * ``"h"`` (high) * ``"f"`` (full) Defaults to ``"l"`` :type continent_fill_color: Valid matplotlib color, optional :param continent_fill_color: Color of the continents. Defaults to ``"0.9"`` which is a light gray. :type water_fill_color: Valid matplotlib color, optional :param water_fill_color: Color of all water bodies. Defaults to ``"white"``. :type colormap: str, optional, any matplotlib colormap :param colormap: The colormap for color-coding the events. The event with the smallest property will have the color of one end of the colormap and the event with the biggest property the color of the other end with all other events in between. Defaults to None which will use the default colormap for the date encoding and a colormap going from green over yellow to red for the depth encoding. :type title: str :param title: Title above plot. :type colorbar_ticklabel_format: str or func or subclass of :matplotlib:`matplotlib.ticker.Formatter` :param colorbar_ticklabel_format: Format string or Formatter used to format colorbar tick labels. :type show: bool :param show: Whether to show the figure after plotting or not. Can be used to do further customization of the plot before showing it. """ min_color = min(color) max_color = max(color) if isinstance(color[0], (datetime.datetime, UTCDateTime)): datetimeplot = True color = [date2num(t) for t in color] else: datetimeplot = False scal_map = ScalarMappable(norm=Normalize(min_color, max_color), cmap=colormap) scal_map.set_array(np.linspace(0, 1, 1)) fig = plt.figure() # The colorbar should only be plotted if more then one event is # present. if len(lons) > 1 and hasattr(color, "__len__") and not isinstance(color, (str, native_str)): show_colorbar = True else: show_colorbar = False if projection == "local": ax_x0, ax_width = 0.10, 0.80 else: ax_x0, ax_width = 0.05, 0.90 if show_colorbar: map_ax = fig.add_axes([ax_x0, 0.13, ax_width, 0.77]) cm_ax = fig.add_axes([ax_x0, 0.05, ax_width, 0.05]) plt.sca(map_ax) else: map_ax = fig.add_axes([ax_x0, 0.05, ax_width, 0.85]) if projection == "cyl": bmap = Basemap(resolution=resolution) elif projection == "ortho": bmap = Basemap( projection="ortho", resolution=resolution, area_thresh=1000.0, lat_0=np.mean(lats), lon_0=np.mean(lons) ) elif projection == "local": if min(lons) < -150 and max(lons) > 150: max_lons = max(np.array(lons) % 360) min_lons = min(np.array(lons) % 360) else: max_lons = max(lons) min_lons = min(lons) lat_0 = (max(lats) + min(lats)) / 2.0 lon_0 = (max_lons + min_lons) / 2.0 if lon_0 > 180: lon_0 -= 360 deg2m_lat = 2 * np.pi * 6371 * 1000 / 360 deg2m_lon = deg2m_lat * np.cos(lat_0 / 180 * np.pi) if len(lats) > 1: height = (max(lats) - min(lats)) * deg2m_lat width = (max_lons - min_lons) * deg2m_lon margin = 0.2 * (width + height) height += margin width += margin else: height = 2.0 * deg2m_lat width = 5.0 * deg2m_lon bmap = Basemap( projection="aeqd", resolution=resolution, area_thresh=1000.0, lat_0=lat_0, lon_0=lon_0, width=width, height=height, ) # not most elegant way to calculate some round lats/lons def linspace2(val1, val2, N): """ returns around N 'nice' values between val1 and val2 """ dval = val2 - val1 round_pos = int(round(-np.log10(1.0 * dval / N))) delta = round(2.0 * dval / N, round_pos) / 2 new_val1 = np.ceil(val1 / delta) * delta new_val2 = np.floor(val2 / delta) * delta N = (new_val2 - new_val1) / delta + 1 return np.linspace(new_val1, new_val2, N) N1 = int(np.ceil(height / max(width, height) * 8)) N2 = int(np.ceil(width / max(width, height) * 8)) bmap.drawparallels( linspace2(lat_0 - height / 2 / deg2m_lat, lat_0 + height / 2 / deg2m_lat, N1), labels=[0, 1, 1, 0] ) if min(lons) < -150 and max(lons) > 150: lon_0 %= 360 meridians = linspace2(lon_0 - width / 2 / deg2m_lon, lon_0 + width / 2 / deg2m_lon, N2) meridians[meridians > 180] -= 360 bmap.drawmeridians(meridians, labels=[1, 0, 0, 1]) else: msg = "Projection '%s' not supported." % projection raise ValueError(msg) # draw coast lines, country boundaries, fill continents. plt.gca().set_axis_bgcolor(water_fill_color) bmap.drawcoastlines(color="0.4") bmap.drawcountries(color="0.75") bmap.fillcontinents(color=continent_fill_color, lake_color=water_fill_color) # draw the edge of the bmap projection region (the projection limb) bmap.drawmapboundary(fill_color=water_fill_color) # draw lat/lon grid lines every 30 degrees. bmap.drawmeridians(np.arange(-180, 180, 30)) bmap.drawparallels(np.arange(-90, 90, 30)) # compute the native bmap projection coordinates for events. x, y = bmap(lons, lats) # plot labels if labels: if 100 > len(lons) > 1: for name, xpt, ypt, colorpt in zip(labels, x, y, color): # Check if the point can actually be seen with the current bmap # projection. The bmap object will set the coordinates to very # large values if it cannot project a point. if xpt > 1e25: continue plt.text( xpt, ypt, name, weight="heavy", color="k", zorder=100, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")], ) elif len(lons) == 1: plt.text( x[0], y[0], labels[0], weight="heavy", color="k", path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")], ) scatter = bmap.scatter(x, y, marker=marker, s=size, c=color, zorder=10, cmap=colormap) if title: plt.suptitle(title) # Only show the colorbar for more than one event. if show_colorbar: if colorbar_ticklabel_format is not None: if isinstance(colorbar_ticklabel_format, (str, native_str)): formatter = FormatStrFormatter(colorbar_ticklabel_format) elif hasattr(colorbar_ticklabel_format, "__call__"): formatter = FuncFormatter(colorbar_ticklabel_format) elif isinstance(colorbar_ticklabel_format, Formatter): formatter = colorbar_ticklabel_format locator = MaxNLocator(5) else: if datetimeplot: locator = AutoDateLocator() formatter = AutoDateFormatter(locator) formatter.scaled[1 / (24.0 * 60.0)] = "%H:%M:%S" else: locator = None formatter = None cb = Colorbar(cm_ax, scatter, cmap=colormap, orientation="horizontal", ticks=locator, format=formatter) # format=formatter) # ticks=mpl.ticker.MaxNLocator(4)) cb.update_ticks() if show: plt.show() return fig
def AnimateDiameterAndRawData_Big2(rawframes, static_background, rawframes_pre, sizes_df_lin, traj, ParameterJsonFile): from matplotlib.gridspec import GridSpec settings = nd.handle_data.ReadJson(ParameterJsonFile) fps = settings["Exp"]["fps"] my_gamma = settings["Animation"]["gamma"] microns_per_pixel = settings["Exp"]["Microns_per_pixel"] frames_tot = settings["Animation"]["frames_tot"] num_points_pdf = 100 # Diameter plot histogramm_min = settings["Plot"]["Histogramm_min"] histogramm_max = settings["Plot"]["Histogramm_max"] diam_grid = np.linspace(histogramm_min, histogramm_max, 1000) diam_grid_inv = 1 / diam_grid # here comes the font sizes global my_font_size my_font_size = 16 my_font_size_title = 22 global prob_inv_diam_sum prob_inv_diam_sum = np.zeros(num_points_pdf) # get min and max particle id part_id_min = np.min(traj.particle) part_id_max = np.max(traj.particle) # get min and max diameter diam_max = np.round(np.max(sizes_df_lin.diameter) + 5, -1) diam_min = np.round(np.min(sizes_df_lin.diameter) - 5, -1) # get particle id of TRAJECTORIES in the roi # particle_id_traj = traj[(traj.x > 800) & (traj.x < 1800)].particle.unique() particle_id_traj = traj.particle.unique() #get traj in ROI traj_roi = traj[np.isin(traj.particle, particle_id_traj)] frame = 0 # get trajectory of particles in current frame traj_roi_history = GetTrajHistory(frame, traj_roi) # get position and diameter of evaluated particles pos_roi, sizes_df_lin_frame = GetPosEvaluated(frame, traj_roi, sizes_df_lin) # design the subplot fig = plt.figure(figsize=[25, 13], constrained_layout=True) # gs = GridSpec(6, 3, figure=fig, width_ratios = [0.5,0.5,0.2]) gs = GridSpec(12, 5, figure=fig, width_ratios=[1] * 2 + [0.15] * 3, height_ratios=[1 / 2] * (2 * 3) + [1] * 2 + [1.5] + [0.5] * 3) ax_raw = fig.add_subplot(gs[0:2, 0:2], aspect="equal") # raw image ax_bg = fig.add_subplot(gs[2:4, 0:2], aspect="equal", sharex=ax_raw, sharey=ax_raw) # background ax_pp = fig.add_subplot(gs[4:6, 0:2], aspect="equal", sharex=ax_raw, sharey=ax_raw) # post-processed image ax_traj = fig.add_subplot(gs[6, 0:2], aspect="equal", sharex=ax_raw, sharey=ax_raw) # trajectories ax_eval = fig.add_subplot(gs[7, 0:2], aspect="equal", sharex=ax_raw, sharey=ax_raw) # particles colour in diameter ax_hist = fig.add_subplot(gs[8, 0]) # histogram of current frame ax_hist_cum = fig.add_subplot(gs[8, 1], sharex=ax_hist, sharey=ax_hist) # summed histogram # axis for the colorbars / legends c_ax_raw = plt.subplot(gs[0, 2:5]) c_ax_bg = plt.subplot(gs[2, 2:5]) c_ax_pp = plt.subplot(gs[4, 2:5]) c_ax_traj = plt.subplot(gs[6, 2:5]) c_ax_eval = plt.subplot(gs[7, 2:5]) # axis for min, max and gamma values ax_raw_min = plt.subplot(gs[1, 2]) ax_raw_max = plt.subplot(gs[1, 3]) ax_raw_g = plt.subplot(gs[1, 4]) ax_bg_min = plt.subplot(gs[3, 2]) ax_bg_max = plt.subplot(gs[3, 3]) ax_bg_g = plt.subplot(gs[3, 4]) ax_pp_min = plt.subplot(gs[5, 2]) ax_pp_max = plt.subplot(gs[5, 3]) ax_pp_g = plt.subplot(gs[5, 4]) #here come the sliders slider_frame_ax = plt.subplot(gs[9, 0:2]) slider_x_min_ax = plt.subplot(gs[10, 0]) slider_x_max_ax = plt.subplot(gs[11, 0]) slider_y_min_ax = plt.subplot(gs[10, 1]) slider_y_max_ax = plt.subplot(gs[11, 1]) # plot the stuff import matplotlib.colors as colors raw_image = ax_raw.imshow(rawframes[0, :, :], cmap='gray', norm=colors.PowerNorm(gamma=my_gamma), animated=True, vmin=0, vmax=np.max(rawframes)) bg_image = ax_bg.imshow(static_background, cmap='gray', norm=colors.PowerNorm(gamma=my_gamma), animated=True, vmin=0, vmax=np.max(static_background)) pp_image = ax_pp.imshow(rawframes_pre[0, :, :], cmap='gray', norm=colors.PowerNorm(gamma=my_gamma), animated=True, vmin=np.min(rawframes_pre), vmax=np.max(rawframes_pre)) ax_scatter_traj = ax_traj.scatter(traj_roi_history.x, traj_roi_history.y, s=3, c=traj_roi_history.particle, cmap='gist_ncar', alpha=1, vmin=0, vmax=part_id_max) # ax_scatter_traj = ax_traj.scatter(traj_roi_history.x, traj_roi_history.y, s = 3, c = traj_roi_history.particle, cmap = 'gist_ncar', alpha = 1, vmin=part_id_min, vmax=part_id_max) ax_scatter_diam = ax_eval.scatter(pos_roi.x, pos_roi.y, c=sizes_df_lin_frame.diameter, cmap='gist_ncar', vmin=diam_min, vmax=diam_max) # add titles and labels ax_raw.set_title('raw-data', fontsize=my_font_size_title) ax_raw.set_ylabel('y-Position [px]', fontsize=my_font_size) ax_bg.set_title('Background and stationary particles', fontsize=my_font_size_title) ax_bg.set_ylabel('y-Position [px]', fontsize=my_font_size) ax_pp.set_title('Processed image', fontsize=my_font_size_title) ax_pp.set_ylabel('y-Position [px]', fontsize=my_font_size) ax_traj.set_title('trajectory', fontsize=my_font_size_title) ax_traj.set_ylabel('y-Position [px]', fontsize=my_font_size) ax_eval.set_title('Diameter of each particle', fontsize=my_font_size_title) ax_eval.set_ylabel('y-Position [px]', fontsize=my_font_size) ax_eval.set_xlabel('x-Position [px]', fontsize=my_font_size) # COLORBARS from matplotlib.colorbar import Colorbar cb_raw = Colorbar(ax=c_ax_raw, mappable=raw_image, orientation='horizontal', ticklocation='top') cb_raw.set_label("Brightness", fontsize=my_font_size) cb_bg = Colorbar(ax=c_ax_bg, mappable=bg_image, orientation='horizontal', ticklocation='top') cb_bg.set_label("Brightness", fontsize=my_font_size) cb_pp = Colorbar(ax=c_ax_pp, mappable=pp_image, orientation='horizontal', ticklocation='top') cb_pp.set_label("Brightness", fontsize=my_font_size) cb_traj = Colorbar(ax=c_ax_traj, mappable=ax_scatter_traj, orientation='horizontal', ticklocation='top') cb_traj.set_label("Particle ID", fontsize=my_font_size) cb_eval = Colorbar(ax=c_ax_eval, mappable=ax_scatter_diam, orientation='horizontal', ticklocation='top') cb_eval.set_label("Diameter [nm]", fontsize=my_font_size) from matplotlib import ticker cb_raw.locator = ticker.MaxNLocator(nbins=3) cb_raw.update_ticks() cb_bg.locator = ticker.MaxNLocator(nbins=3) cb_bg.update_ticks() cb_pp.locator = ticker.MaxNLocator(nbins=3) cb_pp.update_ticks() cb_traj.locator = ticker.MaxNLocator(nbins=5) cb_traj.update_ticks() cb_eval.locator = ticker.MaxNLocator(nbins=5) cb_eval.update_ticks() # Here come the two histograms line_diam_frame, = ax_hist.plot(diam_grid, np.zeros_like(diam_grid)) line_diam_sum, = ax_hist_cum.plot(diam_grid, np.zeros_like(diam_grid)) # label and title ax_hist.set_xlabel('Diameter [nm]', fontsize=my_font_size) ax_hist.set_ylabel('Occurance', fontsize=my_font_size) ax_hist.set_title("Live Histogram", fontsize=my_font_size_title) ax_hist_cum.set_xlabel('Diameter [nm]', fontsize=my_font_size) ax_hist_cum.set_ylabel('Occurance', fontsize=my_font_size) ax_hist_cum.set_title("Cummulated Histogram", fontsize=my_font_size_title) # limits ax_hist.set_xlim([histogramm_min, histogramm_max]) ax_hist.set_ylim([0, 1.1]) ax_hist.set_yticks([]) ax_hist.tick_params(direction='out') # Global PDF inv_diam, inv_diam_std = nd.CalcDiameter.InvDiameter( sizes_df_lin, settings) prob_inv_diam = np.zeros_like(diam_grid_inv) for index, (loop_mean, loop_std, weight) in enumerate( zip(inv_diam, inv_diam_std, sizes_df_lin["traj length"])): #loop through all evaluated partices in that roi and frame #calc probability density function (PDF) my_pdf = scipy.stats.norm(loop_mean, loop_std).pdf(diam_grid_inv) # normalized nad weight my_pdf = my_pdf / np.sum(my_pdf) * weight #add up all PDFs prob_inv_diam = prob_inv_diam + my_pdf #normalized to 1 prob_inv_diam_show = prob_inv_diam / np.max(prob_inv_diam) line_diam_sum.set_ydata(prob_inv_diam_show) def animate(frame, x_min, x_max, y_min, y_max, UpdateFrame): global ColorbarDone print("\nframe", frame) print("x_min", x_min) print("x_max", x_max) print("y_min", y_min) print("y_max", y_max) print("Update Frame", UpdateFrame) # select new frame if required if UpdateFrame == True: rawframes_frame = rawframes[frame, :, :] rawframes_pp_frame = rawframes_pre[frame, :, :] raw_image.set_data(rawframes_frame) bg_image.set_data(static_background) pp_image.set_data(rawframes_pp_frame) # SET AXES ax_raw.set_xlim([x_min, x_max]) ax_raw.set_ylim([y_min, y_max]) ax_raw.tick_params(direction='out') # make the labels in um num_x_ticks = 5 num_y_ticks = 3 x_ticks_px = np.round( np.linspace(x_min, x_max, num_x_ticks, dtype='int'), -2) y_ticks_px = np.round( np.linspace(y_min, y_max, num_y_ticks, dtype='int'), -1) ax_raw.set_xticks(x_ticks_px) ax_raw.set_xticklabels(x_ticks_px) ax_raw.set_yticks(y_ticks_px) ax_raw.set_yticklabels(y_ticks_px) # get particle id of TRAJECTORIES in the roi particle_id_traj = traj[(traj.x > x_min) & (traj.x < x_max)].particle.unique() #get traj in ROI traj_roi = traj[traj.particle.isin(particle_id_traj)] # get trajectory of particles in current frame traj_roi_history = GetTrajHistory(frame, traj_roi) # get position and diameter of evaluated particles pos_roi, sizes_df_lin_roi_frame = GetPosEvaluated( frame, traj_roi, sizes_df_lin) #update figure time_ms = frame * (1 / fps) * 1000 time_ms = np.round(time_ms, 1) fig.suptitle('frame: ' + str(frame) + '; time: ' + str(time_ms) + ' ms', fontsize=my_font_size_title) ax_scatter_traj.set_offsets( np.transpose( np.asarray( [traj_roi_history.x.values, traj_roi_history.y.values]))) ax_scatter_traj.set_array(traj_roi_history.particle) ax_scatter_diam.set_offsets( np.transpose(np.asarray([pos_roi.x.values, pos_roi.y.values]))) ax_scatter_diam.set_array(sizes_df_lin_roi_frame.diameter) ## DIAMETER PDF FROM PREVIOUS POINTS sizes_df_lin_roi_frame = sizes_df_lin_roi_frame.sort_index() # get inverse diameter which is normal distributed (proportional to the diffusion) inv_diam, inv_diam_std = nd.CalcDiameter.InvDiameter( sizes_df_lin_roi_frame, settings) # probability of inverse diameter prob_inv_diam = np.zeros_like(diam_grid_inv) for index, (loop_mean, loop_std) in enumerate(zip(inv_diam, inv_diam_std)): #loop through all evaluated partices in that roi and frame #calc probability density function (PDF) my_pdf = scipy.stats.norm(loop_mean, loop_std).pdf(diam_grid_inv) # normalized my_pdf = my_pdf / np.sum(my_pdf) #add up all PDFs prob_inv_diam = prob_inv_diam + my_pdf #normalized to 1 if np.max(prob_inv_diam) > 0: prob_inv_diam_show = prob_inv_diam / np.max(prob_inv_diam) else: prob_inv_diam_show = prob_inv_diam line_diam_frame.set_ydata(prob_inv_diam_show) # # # # ## ACCUMULATED DIAMETER PDF # #normalized to 1 # prob_inv_diam_sum_show = prob_inv_diam_sum / np.max(prob_inv_diam_sum) # # line_diam_sum.set_ydata(prob_inv_diam_sum_show) print("Animation updated") return raw_image # Functions for Update the ROI and brightness def UpdateFrame(val): UpdateFrame = True UpdateAnimation(UpdateFrame, val) def UpdateROI(val): UpdateFrame = False UpdateAnimation(UpdateFrame, val) def UpdateAnimation(UpdateROI, val): frame = int(slider_frame.val) x_min = int(slider_x_min.val) x_max = int(slider_x_max.val) y_min = int(slider_y_min.val) y_max = int(slider_y_max.val) animate(frame, x_min, x_max, y_min, y_max, UpdateROI) plt.draw() def UpdateColorbarRawimage(stuff): v_min = np.int(textbox_raw_min.text) v_max = np.int(textbox_raw_max.text) my_gamma = np.double(textbox_raw_g.text) print("\n v_min = ", v_min) print("v_max = ", v_max) print("gamma = ", my_gamma) raw_image.set_norm(colors.PowerNorm(gamma=my_gamma)) raw_image.set_clim([v_min, v_max]) cb_raw = Colorbar(ax=c_ax_raw, mappable=raw_image, orientation='horizontal', ticklocation='top') cb_raw.locator = ticker.MaxNLocator(nbins=3) cb_raw.update_ticks() def UpdateColorbarBg(stuff): v_min = np.int(textbox_bg_min.text) v_max = np.int(textbox_bg_max.text) my_gamma = np.double(textbox_bg_g.text) print("\n v_min = ", v_min) print("v_max = ", v_max) print("gamma = ", my_gamma) bg_image.set_norm(colors.PowerNorm(gamma=my_gamma)) bg_image.set_clim([v_min, v_max]) cb_bg = Colorbar(ax=c_ax_bg, mappable=bg_image, orientation='horizontal', ticklocation='top') cb_bg.locator = ticker.MaxNLocator(nbins=3) cb_bg.update_ticks() def UpdateColorbarPP(stuff): v_min = np.int(textbox_pp_min.text) v_max = np.int(textbox_pp_max.text) my_gamma = np.double(textbox_pp_g.text) print("\n v_min = ", v_min) print("v_max = ", v_max) print("gamma = ", my_gamma) pp_image.set_norm(colors.PowerNorm(gamma=my_gamma)) pp_image.set_clim([v_min, v_max]) cb_pp = Colorbar(ax=c_ax_pp, mappable=pp_image, orientation='horizontal', ticklocation='top') cb_pp.locator = ticker.MaxNLocator(nbins=3) cb_pp.update_ticks() # anim = animation.FuncAnimation(fig, animate, init_func=init, frames = 100, interval=100, blit=True, repeat=False) # anim = animation.FuncAnimation(fig, animate, frames = 1000, interval = 10, repeat = False) min_frame = int(traj_roi.frame.min()) max_frame = int(traj_roi.frame.max()) show_frames = np.linspace(min_frame, max_frame, frames_tot, dtype='int') Do_Save = True # HERE COME THE TEXTBOXES AND SLIDERS from matplotlib.widgets import Slider, Button, TextBox #raw image textbox_raw_min = TextBox(ax_raw_min, "min: ", initial=str(np.min(rawframes[0, :, :])), hovercolor="y") textbox_raw_min.on_submit(UpdateColorbarRawimage) textbox_raw_max = TextBox(ax_raw_max, "max: ", initial=str(np.max(rawframes[0, :, :])), hovercolor="y") textbox_raw_max.on_submit(UpdateColorbarRawimage) textbox_raw_g = TextBox(ax_raw_g, "gamma: ", initial=str(my_gamma), hovercolor="y") textbox_raw_g.on_submit(UpdateColorbarRawimage) #bg textbox_bg_min = TextBox(ax_bg_min, "min: ", initial=str(np.int(np.min(static_background))), hovercolor="y") textbox_bg_min.on_submit(UpdateColorbarBg) textbox_bg_max = TextBox(ax_bg_max, "max: ", initial=str(np.int(np.max(static_background))), hovercolor="y") textbox_bg_max.on_submit(UpdateColorbarBg) textbox_bg_g = TextBox(ax_bg_g, "gamma: ", initial=str(my_gamma), hovercolor="y") textbox_bg_g.on_submit(UpdateColorbarBg) #preproccesd (pp) textbox_pp_min = TextBox(ax_pp_min, "min: ", initial=str(np.int(np.min( rawframes_pre[0, :, :]))), hovercolor="y") textbox_pp_min.on_submit(UpdateColorbarPP) textbox_pp_max = TextBox(ax_pp_max, "max: ", initial=str(np.int(np.max( rawframes_pre[0, :, :]))), hovercolor="y") textbox_pp_max.on_submit(UpdateColorbarPP) textbox_pp_g = TextBox(ax_pp_g, "gamma: ", initial=str(my_gamma), hovercolor="y") textbox_pp_g.on_submit(UpdateColorbarPP) # sliders frame_max = rawframes.shape[0] - 1 x_max_max = rawframes.shape[2] - 1 y_max_max = rawframes.shape[1] - 1 slider_frame = Slider(slider_frame_ax, "Frame: ", valmin=0, valmax=frame_max, valinit=0, valstep=1) slider_x_min = Slider(slider_x_min_ax, "x_min: ", valmin=0, valmax=x_max_max, valinit=0, valstep=1) slider_x_max = Slider(slider_x_max_ax, "x_max: ", valmin=0, valmax=x_max_max, valinit=x_max_max, valstep=1, slidermin=slider_x_min) slider_y_min = Slider(slider_y_min_ax, "y_min: ", valmin=0, valmax=y_max_max, valinit=0, valstep=1) slider_y_max = Slider(slider_y_max_ax, "y_max: ", valmin=0, valmax=y_max_max, valinit=y_max_max, valstep=1, slidermin=slider_y_min) slider_frame.on_changed(UpdateFrame) slider_x_min.on_changed(UpdateROI) slider_x_max.on_changed(UpdateROI) slider_y_min.on_changed(UpdateROI) slider_y_max.on_changed(UpdateROI) plt.show() # if Do_Save == True: # anim = animation.FuncAnimation(fig, animate, frames = show_frames, init_func=init, interval = 0, repeat = False) # anim.save('200204_2.html', writer = 'html', fps=1) # # else: # anim = animation.FuncAnimation(fig, animate, frames = show_frames, init_func=init, interval = 5, repeat = True) # return anim return
def add_ortho(lats, lons, colors, CClim, central_longitude, central_latitude, text=None, size=50, marker=['o', 'd'], colormap='viridis', fig=None, rect=[0.0, 0.0, 1.0, 1.0]): if not fig: fig = plt.figure() proj = ccrs.Orthographic(central_longitude=central_longitude, central_latitude=central_latitude) # left, bottom, width, height ax = fig.add_axes( [rect[0], rect[1] + rect[3] * 0.12, rect[2], rect[3] * 0.85], projection=proj) cm_ax = fig.add_axes([rect[0], rect[1], rect[2], rect[3] * 0.08]) plt.sca(ax) # make the map global rather than have it zoom in to # the extents of any plotted data ax.set_global() ax.stock_img() ax.coastlines() ax.gridlines() lats_mark1 = [] lons_mark1 = [] colors_mark1 = [] lats_mark2 = [] lons_mark2 = [] colors_mark2 = [] cmap = get_cmap(colormap) cmap.set_under('grey') for lon, lat, color in zip(lons, lats, colors): if color > CClim: lats_mark1.append(lat) lons_mark1.append(lon) colors_mark1.append(color) else: lats_mark2.append(lat) lons_mark2.append(lon) colors_mark2.append(color) if len(lons_mark1) > 0: scatter = ax.scatter(lons_mark1, lats_mark1, s=size, c=colors_mark1, marker=marker[0], cmap=cmap, vmin=CClim, vmax=1, zorder=10, transform=ccrs.Geodetic()) if len(lons_mark2) > 0: scatter = ax.scatter(lons_mark2, lats_mark2, s=size, c=colors_mark2, marker=marker[1], cmap=cmap, vmin=CClim, vmax=1, zorder=10, transform=ccrs.Geodetic()) locator = MaxNLocator(5) cb = Colorbar(cm_ax, scatter, cmap=cmap, orientation='horizontal', ticks=locator, extend='min') cb.set_label('CC') # Compat with old matplotlib versions. if hasattr(cb, "update_ticks"): cb.update_ticks() ax.plot(central_longitude, central_latitude, color='red', marker='*', markersize=np.sqrt(size)) if (text): for lat, lon, text in zip(lats, lons, text): # Avoid plotting invisible texts. They clutter at the origin # otherwise dist = locations2degrees(lat, lon, central_latitude, central_longitude) if (dist < 90): plt.text(lon, lat, text, weight="heavy", transform=ccrs.Geodetic(), color="k", zorder=100, path_effects=[ PathEffects.withStroke(linewidth=3, foreground="white") ]) return ax
def plot_basemap(lons, lats, size, color, labels=None, projection='cyl', resolution='l', continent_fill_color='0.8', water_fill_color='1.0', colormap=None, colorbar=None, marker="o", title=None, colorbar_ticklabel_format=None, show=True, **kwargs): # @UnusedVariable """ Creates a basemap plot with a data point scatter plot. :type lons: list/tuple of floats :param lons: Longitudes of the data points. :type lats: list/tuple of floats :param lats: Latitudes of the data points. :type size: float or list/tuple of floats :param size: Size of the individual points in the scatter plot. :type color: list/tuple of floats (or objects that can be converted to floats, like e.g. :class:`~obspy.core.utcdatetime.UTCDateTime`) :param color: Color information of the individual data points to be used in the specified color map (e.g. origin depths, origin times). :type labels: list/tuple of str :param labels: Annotations for the individual data points. :type projection: str, optional :param projection: The map projection. Currently supported are * ``"cyl"`` (Will plot the whole world.) * ``"ortho"`` (Will center around the mean lat/long.) * ``"local"`` (Will plot around local events) Defaults to "cyl" :type resolution: str, optional :param resolution: Resolution of the boundary database to use. Will be based directly to the basemap module. Possible values are * ``"c"`` (crude) * ``"l"`` (low) * ``"i"`` (intermediate) * ``"h"`` (high) * ``"f"`` (full) Defaults to ``"l"`` :type continent_fill_color: Valid matplotlib color, optional :param continent_fill_color: Color of the continents. Defaults to ``"0.9"`` which is a light gray. :type water_fill_color: Valid matplotlib color, optional :param water_fill_color: Color of all water bodies. Defaults to ``"white"``. :type colormap: str, any matplotlib colormap, optional :param colormap: The colormap for color-coding the events as provided in `color` kwarg. The event with the smallest `color` property will have the color of one end of the colormap and the event with the highest `color` property the color of the other end with all other events in between. Defaults to None which will use the default matplotlib colormap. :type colorbar: bool, optional :param colorbar: When left `None`, a colorbar is plotted if more than one object is plotted. Using `True`/`False` the colorbar can be forced on/off. :type title: str :param title: Title above plot. :type colorbar_ticklabel_format: str or function or subclass of :class:`matplotlib.ticker.Formatter` :param colorbar_ticklabel_format: Format string or Formatter used to format colorbar tick labels. :type show: bool :param show: Whether to show the figure after plotting or not. Can be used to do further customization of the plot before showing it. """ min_color = min(color) max_color = max(color) if isinstance(color[0], (datetime.datetime, UTCDateTime)): datetimeplot = True color = [date2num(t) for t in color] else: datetimeplot = False scal_map = ScalarMappable(norm=Normalize(min_color, max_color), cmap=colormap) scal_map.set_array(np.linspace(0, 1, 1)) fig = plt.figure() # The colorbar should only be plotted if more then one event is # present. if colorbar is not None: show_colorbar = colorbar else: if len(lons) > 1 and hasattr(color, "__len__") and \ not isinstance(color, (str, native_str)): show_colorbar = True else: show_colorbar = False if projection == "local": ax_x0, ax_width = 0.10, 0.80 else: ax_x0, ax_width = 0.05, 0.90 if show_colorbar: map_ax = fig.add_axes([ax_x0, 0.13, ax_width, 0.77]) cm_ax = fig.add_axes([ax_x0, 0.05, ax_width, 0.05]) plt.sca(map_ax) else: ax_y0, ax_height = 0.05, 0.85 if projection == "local": ax_y0 += 0.05 ax_height -= 0.05 map_ax = fig.add_axes([ax_x0, ax_y0, ax_width, ax_height]) if projection == 'cyl': bmap = Basemap(resolution=resolution) elif projection == 'ortho': bmap = Basemap(projection='ortho', resolution=resolution, area_thresh=1000.0, lat_0=np.mean(lats), lon_0=np.mean(lons)) elif projection == 'local': if min(lons) < -150 and max(lons) > 150: max_lons = max(np.array(lons) % 360) min_lons = min(np.array(lons) % 360) else: max_lons = max(lons) min_lons = min(lons) lat_0 = max(lats) / 2. + min(lats) / 2. lon_0 = max_lons / 2. + min_lons / 2. if lon_0 > 180: lon_0 -= 360 deg2m_lat = 2 * np.pi * 6371 * 1000 / 360 deg2m_lon = deg2m_lat * np.cos(lat_0 / 180 * np.pi) if len(lats) > 1: height = (max(lats) - min(lats)) * deg2m_lat width = (max_lons - min_lons) * deg2m_lon margin = 0.2 * (width + height) height += margin width += margin else: height = 2.0 * deg2m_lat width = 5.0 * deg2m_lon # do intelligent aspect calculation for local projection # adjust to figure dimensions w, h = fig.get_size_inches() aspect = w / h if show_colorbar: aspect *= 1.2 if width / height < aspect: width = height * aspect else: height = width / aspect bmap = Basemap(projection='aeqd', resolution=resolution, area_thresh=1000.0, lat_0=lat_0, lon_0=lon_0, width=width, height=height) # not most elegant way to calculate some round lats/lons def linspace2(val1, val2, N): """ returns around N 'nice' values between val1 and val2 """ dval = val2 - val1 round_pos = int(round(-np.log10(1. * dval / N))) # Fake negative rounding as not supported by future as of now. if round_pos < 0: factor = 10**(abs(round_pos)) delta = round(2. * dval / N / factor) * factor / 2 else: delta = round(2. * dval / N, round_pos) / 2 new_val1 = np.ceil(val1 / delta) * delta new_val2 = np.floor(val2 / delta) * delta N = (new_val2 - new_val1) / delta + 1 return np.linspace(new_val1, new_val2, N) N1 = int(np.ceil(height / max(width, height) * 8)) N2 = int(np.ceil(width / max(width, height) * 8)) bmap.drawparallels(linspace2(lat_0 - height / 2 / deg2m_lat, lat_0 + height / 2 / deg2m_lat, N1), labels=[0, 1, 1, 0]) if min(lons) < -150 and max(lons) > 150: lon_0 %= 360 meridians = linspace2(lon_0 - width / 2 / deg2m_lon, lon_0 + width / 2 / deg2m_lon, N2) meridians[meridians > 180] -= 360 bmap.drawmeridians(meridians, labels=[1, 0, 0, 1]) else: msg = "Projection '%s' not supported." % projection raise ValueError(msg) # draw coast lines, country boundaries, fill continents. map_ax.set_axis_bgcolor(water_fill_color) bmap.drawcoastlines(color="0.4") bmap.drawcountries(color="0.75") bmap.fillcontinents(color=continent_fill_color, lake_color=water_fill_color) # draw the edge of the bmap projection region (the projection limb) bmap.drawmapboundary(fill_color=water_fill_color) # draw lat/lon grid lines every 30 degrees. bmap.drawmeridians(np.arange(-180, 180, 30)) bmap.drawparallels(np.arange(-90, 90, 30)) # compute the native bmap projection coordinates for events. x, y = bmap(lons, lats) # plot labels if labels: if 100 > len(lons) > 1: for name, xpt, ypt, _colorpt in zip(labels, x, y, color): # Check if the point can actually be seen with the current bmap # projection. The bmap object will set the coordinates to very # large values if it cannot project a point. if xpt > 1e25: continue plt.text(xpt, ypt, name, weight="heavy", color="k", zorder=100, **path_effect_kwargs) elif len(lons) == 1: plt.text(x[0], y[0], labels[0], weight="heavy", color="k", **path_effect_kwargs) scatter = bmap.scatter(x, y, marker=marker, s=size, c=color, zorder=10, cmap=colormap) if title: plt.suptitle(title) # Only show the colorbar for more than one event. if show_colorbar: if colorbar_ticklabel_format is not None: if isinstance(colorbar_ticklabel_format, (str, native_str)): formatter = FormatStrFormatter(colorbar_ticklabel_format) elif hasattr(colorbar_ticklabel_format, '__call__'): formatter = FuncFormatter(colorbar_ticklabel_format) elif isinstance(colorbar_ticklabel_format, Formatter): formatter = colorbar_ticklabel_format locator = MaxNLocator(5) else: if datetimeplot: locator = AutoDateLocator() formatter = AutoDateFormatter(locator) formatter.scaled[1 / (24. * 60.)] = '%H:%M:%S' else: locator = None formatter = None cb = Colorbar(cm_ax, scatter, cmap=colormap, orientation='horizontal', ticks=locator, format=formatter) # format=formatter) # ticks=mpl.ticker.MaxNLocator(4)) cb.update_ticks() if show: plt.show() return fig