Source code for schrodinger.ui.qt.figureoptions

"""
Module that provides a GUI-based editor for matplotlib's figure options

Copyright © 2009 Pierre Raybaut
Licensed under the terms of the MIT License
see the mpl licenses directory for a copy of the license

Additional changes copyright Schrodinger, LLC. All rights reserved.
"""

import os.path as osp

from matplotlib import markers
from matplotlib.backends.qt_compat import QtGui
from matplotlib.colors import to_hex

from schrodinger.Qt import IS_PYQT6
if not IS_PYQT6:
    # formlayout isn't compatible with Qt 6.  See PANEL-20903.
    import formlayout


[docs]def get_icon(name): import matplotlib basedir = osp.join(matplotlib.get_data_path(), 'images') return QtGui.QIcon(osp.join(basedir, name))
LINESTYLES = { '-': 'Solid', '--': 'Dashed', '-.': 'DashDot', ':': 'Dotted', 'steps': 'Steps', 'none': 'None', } MARKERS = markers.MarkerStyle.markers def _get_scale_options(default, allow_log, allow_linear): scale_options = [default] if allow_linear: scale_options.append('linear') if allow_log: scale_options.append('log') return scale_options
[docs]def figure_edit(axes, parent=None, allow_log=True, allow_linear=True): """Edit matplotlib figure options""" sep = (None, None) # separator has_curve = len(axes.get_lines()) > 0 xscale_options = _get_scale_options(axes.get_xscale(), allow_log, allow_linear) yscale_options = _get_scale_options(axes.get_yscale(), allow_log, allow_linear) # Get / General xmin, xmax = axes.get_xlim() ymin, ymax = axes.get_ylim() general = [('Title', axes.get_title()), sep, (None, "<b>X-Axis</b>"), ('Min', xmin), ('Max', xmax), ('Label', axes.get_xlabel()), ('Scale', xscale_options), sep, (None, "<b>Y-Axis</b>"), ('Min', ymin), ('Max', ymax), ('Label', axes.get_ylabel()), ('Scale', yscale_options)] if has_curve: # Get / Curves linedict = {} for line in axes.get_lines(): label = line.get_label() if label == '_nolegend_': continue linedict[label] = line curves = [] linestyles = list(LINESTYLES.items()) markers = list(MARKERS.items()) curvelabels = sorted(list(linedict)) for label in curvelabels: line = linedict[label] curvedata = [ ('Label', label), sep, (None, '<b>Line</b>'), ('Style', [line.get_linestyle()] + linestyles), ('Width', line.get_linewidth()), ('Color', to_hex(line.get_color())), sep, (None, '<b>Marker</b>'), ('Style', [line.get_marker()] + markers), ('Size', line.get_markersize()), ('Facecolor', to_hex(line.get_markerfacecolor())), ('Edgecolor', to_hex(line.get_markeredgecolor())), ] curves.append([curvedata, label, ""]) datalist = [(general, "Axes", "")] if has_curve: datalist.append((curves, "Curves", "")) def apply_callback(data, widgets=None): """This function will be called to apply changes""" if has_curve: general, curves = data else: general, = data # Set / General title, xmin, xmax, xlabel, xscale, ymin, ymax, ylabel, yscale = general if axes.get_xscale() != xscale: axes.set_xscale(xscale) if axes.get_yscale() != yscale: axes.set_yscale(yscale) axes.set_title(title) axes.set_xlim(xmin, xmax) axes.set_xlabel(xlabel) axes.set_ylim(ymin, ymax) axes.set_ylabel(ylabel) if has_curve: # Set / Curves for index, curve in enumerate(curves): line = linedict[curvelabels[index]] label, linestyle, linewidth, color, \ marker, markersize, markerfacecolor, markeredgecolor = curve line.set_label(label) line.set_linestyle(linestyle) line.set_linewidth(linewidth) line.set_color(color) if marker != 'none': line.set_marker(marker) line.set_markersize(markersize) line.set_markerfacecolor(markerfacecolor) line.set_markeredgecolor(markeredgecolor) # Recalculate the color and style of legend artists - note, this # does not work for multiple legends on the same figure. But it's # an improvement over the current situation of not working for any # legends. figure = axes.get_figure() all_axes = figure.get_axes() for legend in figure.legends: # Need to gather all the legend items from all the subplots all_handles = [] all_labels = [] for one_axes in all_axes: handles, labels = one_axes.get_legend_handles_labels() all_handles.extend(handles) all_labels.extend(labels) # Location and title are altered by the _init_legend_box # function, so preserve the current values loc = legend._loc title = legend.get_title().get_text() if title == 'None': title = None # This function recalculates colors and styles legend._init_legend_box(all_handles, all_labels) legend._loc = loc legend.set_title(title) # Redraw figure = axes.get_figure() figure.canvas.draw() if not IS_PYQT6: data = formlayout.fedit(datalist, title="Figure options", parent=parent, icon=get_icon('qt4_editor_options.svg'), apply=apply_callback) if data is not None: apply_callback(data)