class HistoricalViewerApp: line_styles = ["solid"] colors = [ (0.0, 0.0, 1.0, 1.0), #Blue (1.0, 0.0, 0.0, 1.0), #Red (0.0, 1.0, 0.0, 1.0), #Green (1.0, 1.0, 0.0, 1.0) ] def __init__(self, width, height): self.path = config.find_options("general.cfg")['database'] self.descriptors = config.find_graphs("graphs.cfg") self.data = {} self.collections = {} self.nav_collections = {} self.color_map = {} self.connection = sql.connect(self.path, detect_types=(sql.PARSE_COLNAMES|sql.PARSE_DECLTYPES)) self.root = Tk.Tk() self.root.wm_title("Historical Data Viewer") self.intervals = self.connection.execute("SELECT * FROM intervals ORDER BY start;").fetchall() self.intervals = list(reversed(self.intervals)) #Grid layout: # Col 0 Col 1 # +------------+------+ # Row 0 | | ITVL | # | ZOOM | SLCT | # | - -GRAPH- -+------+ # Row 1 | | DATA | # | | SLCT | # +------------+------+ # Row 2 | NAV GRAPH | ZOOM | # | | SLCT | # +------------+------+ #Setup for the Tk/Agg plotting backend self.figure = Figure(figsize = (width+1, height+2), dpi = 100) self.figure.subplots_adjust(bottom=0.15) self.axes = self.figure.add_subplot(111, autoscale_on=True) self.axes.xaxis.labelpad *= 3 self.canvas = FigureCanvasTkAgg(self.figure, master=self.root) self.canvas.get_tk_widget().grid(row=0, column=0, rowspan=2) #Setup for the mini-navigation figure self.nav_figure = Figure(figsize = ((width+1)*1.05, 1.8), dpi = 100) self.nav_figure.subplots_adjust(bottom=0.3) self.nav_axes = self.nav_figure.add_subplot(111, autoscale_on=False) self.nav_axes.xaxis.labelpad *= 2 self.nav_span = self.nav_axes.axvspan(0.0,1.0, facecolor='g', alpha=0.5) self.nav_handle1 = self.nav_axes.axvspan(0.00,0.025, facecolor='black', alpha=0.5) self.nav_handle2 = self.nav_axes.axvspan(0.975,1.00, facecolor='black', alpha=0.5) self.nav_canvas = FigureCanvasTkAgg(self.nav_figure, master=self.root) self.nav_canvas.get_tk_widget().grid(row=2, column=0) #Set the z-order to something high so that it works as an overlay self.nav_span.zorder = 1000 self.nav_handle1.zorder = 1001 self.nav_handle2.zorder = 1001 ## self.nav_axes.xaxis.set_major_locator(ticker.NullLocator()) self.nav_axes.yaxis.set_major_locator(ticker.NullLocator()) #Setup for the choosing the interval we want to examine self.interval_frame = Tk.Frame(self.root) self.interval_frame.grid(row=0, column=1, sticky=N+E) picker_label = Tk.Label(self.interval_frame, text="Data Intervals") picker_label.grid(row=0, column=0, sticky=N) self.interval_picker = Tk.Listbox(self.interval_frame, selectmode=Tk.BROWSE, exportselection=0) self.interval_picker.grid(row=1, column=0, sticky=N+W+E) width = 20 for (name, start, end) in self.intervals: string = format_span(start, end) width = max(width, len(string)) self.interval_picker.insert(Tk.END, string) self.interval_picker.config(width=width) self.interval_picker.bind("<Double-Button-1>", self.select_interval) self.interval_scrollbar = Tk.Scrollbar(self.interval_frame, command=self.interval_picker.yview) self.interval_picker.config(yscrollcommand=self.interval_scrollbar.set) self.interval_scrollbar.grid(row=1, column=1, sticky=N+S+W) picker_button = Tk.Button(self.interval_frame, text="Select interval", command=self.select_interval) picker_button.grid(row=2, column=0, sticky=N+W) #----Variables for picking the table from the database-------------- self.source_frame = Tk.Frame(self.root) self.source_frame.config(relief=Tk.GROOVE, borderwidth=2) self.source_frame.grid(row=1, column=1, sticky=N+W+E+S) source_label = Tk.Label(self.source_frame, text="Show/Hide plots") source_label.grid(column=0, columnspan=2, sticky=N) def set_var_callback(cb, data, checkbutton, var=None): if var is None: var = Tk.IntVar() def wrapper_callback(): var.set(var.get()) return cb(data, var.get()) checkbutton.config(variable=var, command=wrapper_callback) self.checkbuttons = [] for i,desc in enumerate(self.descriptors): checkbutton = Tk.Checkbutton(self.source_frame, text=desc.title) toggle = Tk.Checkbutton(self.source_frame, text=" ") color = self.colors[i % len(self.colors)] checkbutton.config(relief=Tk.SUNKEN, indicatoron=False) toggle.config(indicatoron=False, background=tk_color(lighten(color)), highlightbackground=tk_color(color), activebackground=tk_color(color), selectcolor=tk_color(color), state=ACTIVE) var = Tk.IntVar() set_var_callback(self.toggle_source, desc, checkbutton, var) set_var_callback(self.toggle_source, desc, toggle, var) self.color_map[desc.table_name] = color toggle.grid(column=0, row=i+1, sticky=N+W) checkbutton.grid(column=1, row=i+1, sticky=N+W) self.checkbuttons.append(checkbutton) self.style_count = 0 self.min_y = self.descriptors[0].min_y self.max_y = self.descriptors[0].max_y self.grabbing_navbar = False self.grabbing_handle = False self.grab_start = None self.handle_grabbed = None self.grab_reference = None def run(self): self.nav_figure.canvas.mpl_connect("button_press_event", self.mpl_on_press) self.nav_figure.canvas.mpl_connect("button_release_event", self.mpl_on_release) self.nav_figure.canvas.mpl_connect("motion_notify_event", self.mpl_on_motion) self.select_interval(index=0) self.interval_picker.selection_set(first=0) for desc, checkbutton in zip(self.descriptors, self.checkbuttons): checkbutton.select() self.toggle_source(desc, True) self.root.mainloop() def update_bounds(self): size = to_ordinal(self.absolute_end) - to_ordinal(self.absolute_start) x1 = to_ordinal(self.start_date) x2 = to_ordinal(self.end_date) self.axes.set_xbound(x1, x2) self.nav_span.set_xy([[x1, self.min_y], [x1, self.max_y], [x2, self.max_y], [x2, self.min_y], [x1, self.min_y]]) if x1 > x2: x1, x2 = x2, x1 self.nav_handle1.set_xy([[x1, self.min_y], [x1, self.max_y], [x1-size*0.025, self.max_y], [x1-size*0.025, self.min_y], [x1, self.min_y]]) self.nav_handle2.set_xy([[x2, self.min_y], [x2, self.max_y], [x2+size*0.025, self.max_y], [x2+size*0.025, self.min_y], [x2, self.min_y]]) locator = KenLocator(7.8) self.axes.xaxis.set_major_locator(locator) self.axes.xaxis.set_major_formatter(KenFormatter(locator)) self.axes.set_xlabel(format_span(self.start_date, self.end_date)) self.nav_axes.set_xlabel(format_timedelta(self.end_date-self.start_date)) def update_data(self): for identifier in self.data: view = self.data[identifier] view.load(self.absolute_start, self.absolute_end) self.collections[identifier].set_segments([view.export()]) self.nav_collections[identifier].set_segments([view.export()]) def select_interval(self, index=None): #Support direct invocation, invocation by event, and as a command if not isinstance(index, int): if not self.interval_picker.curselection(): return index = int(self.interval_picker.curselection()[0]) name, start, end = self.intervals[index] self.absolute_start = self.start_date = start self.absolute_end = self.end_date = end size = to_ordinal(start) - to_ordinal(end) self.nav_axes.set_xlim(to_ordinal(start)+size*0.025, to_ordinal(end)-size*0.025) locator = KenLocator(7.8) self.nav_axes.xaxis.set_major_locator(locator) self.nav_axes.xaxis.set_major_formatter(KenFormatter(locator)) self.update_data() self.update_bounds() self.redraw() def toggle_source(self, desc, enabled): if desc.table_name in self.data: if enabled: data = self.data[desc.table_name].export() self.axes.set_ylabel(desc.units) else: data = [] self.collections[desc.table_name].set_segments([data]) self.nav_collections[desc.table_name].set_segments([data]) self.redraw() elif enabled: self.axes.set_ylabel(desc.units) self.add_source(desc.table_name, desc.title) self.min_y = min(self.min_y, desc.min_y) self.max_y = max(self.max_y, desc.max_y) self.axes.set_ybound(self.min_y,self.max_y) self.nav_axes.set_ybound(self.min_y, self.max_y) ## self.axes.legend(loc=3) self.redraw() def redraw(self): self.figure.canvas.draw() self.nav_figure.canvas.draw() def add_source(self, identifier, title): view = SQLIntervalView(self.connection, identifier, self.absolute_start, self.absolute_end) self.data[identifier] = view colors = [self.color_map.get(identifier, self.colors[0])] col = DatetimeCollection([view.export()], colors=colors) col.set_label(title) self.collections[identifier] = col col2 = DatetimeCollection([view.export()], colors=colors) self.nav_collections[identifier] = col2 self.axes.add_collection(col) self.nav_axes.add_collection(col2) def mpl_on_press(self, event): if event.button != 1 or self.grabbing_navbar or self.grabbing_handle: return trans = self.nav_axes.transData.inverted() xdata = trans.transform((event.x, event.y))[0] if self.nav_handle1.contains(event)[0]: self.grabbing_handle = True self.handle_grabbed = 1 self.grab_start = xdata self.grab_reference = to_ordinal(min(self.start_date, self.end_date)) elif self.nav_handle2.contains(event)[0]: self.grabbing_handle = True self.handle_grabbed = 2 self.grab_start = xdata self.grab_reference = to_ordinal(max(self.start_date, self.end_date)) elif self.nav_span.contains(event)[0]: self.grabbing_navbar = True self.grab_start = xdata self.grab_reference = (to_ordinal(self.start_date), to_ordinal(self.end_date)) def move_navbar(self, pos): left_end = to_ordinal(self.absolute_start) right_end = to_ordinal(self.absolute_end) x1, x2 = self.grab_reference if x1 > x2: x1, x2 = x2, x1 diff = pos - self.grab_start if diff < 0 and x1 + diff < left_end: self.start_date = self.absolute_start self.end_date = from_ordinal(left_end + (x2 - x1)) elif diff > 0 and x2 + diff > right_end: self.end_date = self.absolute_end self.start_date = from_ordinal(right_end - (x2 - x1)) else: self.start_date = from_ordinal(x1 + diff) self.end_date = from_ordinal(x2 + diff) self.update_bounds() self.redraw() def move_handle(self, pos): left_end = to_ordinal(self.absolute_start) right_end = to_ordinal(self.absolute_end) diff = pos - self.grab_start new_pos = max(min(self.grab_reference + diff, right_end), left_end) new_date = from_ordinal(new_pos) if self.handle_grabbed == 1: if new_date > self.end_date: self.handle_grabbed = 2 self.start_date = self.end_date self.end_date = new_date else: self.start_date = new_date else: if new_date < self.start_date: self.handle_grabbed = 1 self.end_date = self.start_date self.start_date = new_date else: self.end_date = new_date self.update_bounds() self.redraw() def mpl_on_release(self, event): if event.button != 1: return trans = self.nav_axes.transData.inverted() xdata = trans.transform((event.x, event.y))[0] if self.grabbing_navbar: self.grabbing_navbar = False self.move_navbar(xdata) elif self.grabbing_handle: self.grabbing_handle = False self.move_handle(xdata) def mpl_on_motion(self, event): trans = self.nav_axes.transData.inverted() xdata = trans.transform((event.x, event.y))[0] if self.grabbing_navbar: self.move_navbar(xdata) elif self.grabbing_handle: self.move_handle(xdata)
class HistoricalViewerApp: line_styles = ["solid"] colors = [ (0.0, 0.0, 1.0, 1.0), #Blue (1.0, 0.0, 0.0, 1.0), #Red (0.0, 1.0, 0.0, 1.0), #Green (1.0, 1.0, 0.0, 1.0) ] def __init__(self, width, height): self.path = config.find_options("general.cfg")['database'] self.descriptors = config.find_graphs("graphs.cfg") self.data = {} self.collections = {} self.nav_collections = {} self.color_map = {} self.connection = sql.connect(self.path, detect_types=(sql.PARSE_COLNAMES|sql.PARSE_DECLTYPES)) self.root = Tk.Tk() self.root.wm_title("Historical Data Viewer") self.intervals = self.connection.execute("SELECT * FROM intervals ORDER BY start;").fetchall() self.intervals = list(reversed(self.intervals)) #Grid layout: # Col 0 Col 1 # +------------+------+ # Row 0 | | ITVL | # | ZOOM | SLCT | # | - -GRAPH- -+------+ # Row 1 | | DATA | # | | SLCT | # +------------+------+ # Row 2 | NAV GRAPH | ZOOM | # | | SLCT | # +------------+------+ #Setup for the Tk/Agg plotting backend self.figure = Figure(figsize = (width+1, height+2), dpi = 100) self.figure.subplots_adjust(bottom=0.15) self.axes = self.figure.add_subplot(111, autoscale_on=True) #self.axes.xaxis.labelpad *= 3 self.canvas = FigureCanvasTkAgg(self.figure, master=self.root) self.canvas.get_tk_widget().grid(row=0, column=0, rowspan=2) #Setup for the mini-navigation figure self.nav_figure = Figure(figsize = ((width+1)*1.05, 1.8), dpi = 100) #self.nav_figure.subplots_adjust(bottom=0.3) self.nav_axes = self.nav_figure.add_subplot(111, autoscale_on=False) #self.nav_axes.xaxis.labelpad *= 2 self.nav_canvas = FigureCanvasTkAgg(self.nav_figure, master=self.root) self.nav_canvas.get_tk_widget().grid(row=2, column=0) self.nav_axes.yaxis.set_major_locator(ticker.NullLocator()) #Setup for the slider def scale_to_data(left, right, x): return from_ordinal(to_ordinal(left) + x * (to_ordinal(right) - to_ordinal(left))) def data_to_scale(left, right, x): return (to_ordinal(x) - to_ordinal(left)) / (to_ordinal(right) - to_ordinal(left)) self.slider = DoubleSlider(self.root, left_bound=datetime(1999,1,1), right_bound=datetime(1999,1,28), data_to_scale=data_to_scale, scale_to_data=scale_to_data, set_on_drag=False, on_change=self.update_bounds, on_drag=lambda left, right: self.update_bounds(left, right, True)) self.slider.grid(row=3, column=0, sticky=W+E) #Setup for the choosing the interval we want to examine self.interval_frame = Tk.Frame(self.root) self.interval_frame.grid(row=0, column=1, sticky=N+E) picker_label = Tk.Label(self.interval_frame, text="Data Intervals") picker_label.grid(row=0, column=0, sticky=N) self.interval_picker = Tk.Listbox(self.interval_frame, selectmode=Tk.BROWSE, exportselection=0) self.interval_picker.grid(row=1, column=0, sticky=N+W+E) width = 20 for (name, start, end) in self.intervals: string = format_span(start, end) width = max(width, len(string)) self.interval_picker.insert(Tk.END, string) self.interval_picker.config(width=width) self.interval_picker.bind("<Double-Button-1>", self.select_interval) self.interval_scrollbar = Tk.Scrollbar(self.interval_frame, command=self.interval_picker.yview) self.interval_picker.config(yscrollcommand=self.interval_scrollbar.set) self.interval_scrollbar.grid(row=1, column=1, sticky=N+S+W) picker_button = Tk.Button(self.interval_frame, text="Select interval", command=self.select_interval) picker_button.grid(row=2, column=0, sticky=N+W) #----Variables for picking the table from the database-------------- self.source_frame = Tk.Frame(self.root) self.source_frame.config(relief=Tk.GROOVE, borderwidth=2) self.source_frame.grid(row=1, column=1, sticky=N+W+E+S) source_label = Tk.Label(self.source_frame, text="Show/Hide plots") source_label.grid(column=0, columnspan=2, sticky=N) def set_var_callback(cb, data, checkbutton, var=None): if var is None: var = Tk.IntVar() def wrapper_callback(): var.set(var.get()) return cb(data, var.get()) checkbutton.config(variable=var, command=wrapper_callback) self.checkbuttons = [] for i,desc in enumerate(self.descriptors): checkbutton = Tk.Checkbutton(self.source_frame, text=desc.title) toggle = Tk.Checkbutton(self.source_frame, text=" ") color = self.colors[i % len(self.colors)] checkbutton.config(relief=Tk.SUNKEN, indicatoron=False) toggle.config(indicatoron=False, background=tk_color(lighten(color)), highlightbackground=tk_color(color), activebackground=tk_color(color), selectcolor=tk_color(color), state=ACTIVE) var = Tk.IntVar() set_var_callback(self.toggle_source, desc, checkbutton, var) set_var_callback(self.toggle_source, desc, toggle, var) self.color_map[desc.table_name] = color toggle.grid(column=0, row=i+1, sticky=N+W) checkbutton.grid(column=1, row=i+1, sticky=N+W) self.checkbuttons.append(checkbutton) self.style_count = 0 self.min_y = self.descriptors[0].min_y self.max_y = self.descriptors[0].max_y def run(self): left_pad = self.nav_figure.subplotpars.left * self.nav_figure.get_figwidth() * self.nav_figure.dpi right_pad = (1-self.nav_figure.subplotpars.right) * self.nav_figure.get_figwidth() * self.nav_figure.dpi self.slider.config(left_padding=left_pad, right_padding=right_pad) self.figure.canvas.draw() self.nav_figure.canvas.draw() self.slider.init() self.select_interval(index=0) self.interval_picker.selection_set(first=0) for desc, checkbutton in zip(self.descriptors, self.checkbuttons): checkbutton.select() self.toggle_source(desc, True) locator = KenLocator(7.8) self.nav_axes.xaxis.set_major_locator(locator) self.nav_axes.xaxis.set_major_formatter(KenFormatter(locator)) locator = KenLocator(7.8) self.axes.xaxis.set_major_locator(locator) self.axes.xaxis.set_major_formatter(KenFormatter(locator)) self.root.mainloop() def update_bounds(self, left, right, dragging=False): if not dragging: self.axes.set_xbound(to_ordinal(left), to_ordinal(right)) self.axes.set_xlabel(format_span(left, right) + " (" + format_timedelta(right - left) + ")") agg_canvas = self.nav_canvas.get_tk_widget() agg_canvas.delete("OVERLAY") # c1 c3 # +---+---------+---+ # |...| _/\ _ |...| # |...|/ \_/ \|...| # +---+---------+---+ # c2 c4 cx2, cy2 = self.nav_axes.transData.transform_point((to_ordinal(left), self.max_y)).tolist() cx3, cy3 = self.nav_axes.transData.transform_point((to_ordinal(right), self.min_y)).tolist() agg_canvas.create_rectangle([cx2, cy2, cx3, cy3], tags="OVERLAY", stipple = "gray50", fill = "green") ## cx1, cy1 = self.nav_axes.transData.transform_point((to_ordinal(self.slider.left_bound), self.min_y)).tolist() ## cx2, cy2 = self.nav_axes.transData.transform_point((to_ordinal(left), self.max_y)).tolist() ## agg_canvas.create_rectangle([(cx1+1, cy1+2), (cx2, cy2)], ## tags="OVERLAY", ## stipple="gray50", ## fill="red", outline="") ## ## cx3, cy3 = self.nav_axes.transData.transform_point((to_ordinal(right), self.min_y)).tolist() ## cx4, cy4 = self.nav_axes.transData.transform_point((to_ordinal(self.slider.right_bound), self.max_y)).tolist() ## agg_canvas.create_rectangle([(cx3, cy3+2), (cx4, cy4)], ## tags="OVERLAY", ## stipple="gray50", ## fill="red", outline="") if not dragging: self.figure.canvas.draw() self.nav_figure.canvas.draw() def select_interval(self, index=None): #Support direct invocation, invocation by event, and as a command if not isinstance(index, int): if not self.interval_picker.curselection(): return index = int(self.interval_picker.curselection()[0]) name, start, end = self.intervals[index] for identifier in self.data: view = self.data[identifier] view.load(start, end) self.collections[identifier].set_segments([view.export()]) self.collections[identifier].set_antialiased(False) self.nav_collections[identifier].set_segments([view.export()]) self.slider.config(left_bound=start, right_bound=end) self.slider.reset() self.nav_axes.set_xbound(to_ordinal(start), to_ordinal(end)) self.nav_axes.set_xlabel("%s (%s)" % (format_span(start, end), format_timedelta(end - start))) self.redraw() def toggle_source(self, desc, enabled): if desc.table_name in self.data: self.nav_collections[desc.table_name].set_visible(enabled) self.collections[desc.table_name].set_visible(enabled) self.redraw() elif enabled: self.axes.set_ylabel(desc.units) self.add_source(desc.table_name, desc.title) self.min_y = min(self.min_y, desc.min_y) self.max_y = max(self.max_y, desc.max_y) self.axes.set_ybound(self.min_y,self.max_y) self.nav_axes.set_ybound(self.min_y, self.max_y) ## self.axes.legend(loc=3) self.redraw() def redraw(self): self.figure.canvas.draw() self.nav_figure.canvas.draw() def add_source(self, identifier, title): left, right = sorted([self.slider.left_bound, self.slider.right_bound]) view = SQLIntervalView(self.connection, identifier, left, right) self.data[identifier] = view colors = [self.color_map.get(identifier, self.colors[0])] col = DatetimeCollection([view.export()], colors=colors) col.set_label(title) self.collections[identifier] = col col2 = DatetimeCollection([view.export()], colors=colors) self.nav_collections[identifier] = col2 self.axes.add_collection(col) self.nav_axes.add_collection(col2)
class DoubleSliderTestApp: def __init__(self, width, height): self.root = Tk.Tk() self.root.wm_title("Double Slider Test") self.plot = Figure(figsize = (width+1, height+2), dpi=72) self.axes = self.plot.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.plot, master=self.root) self.canvas.get_tk_widget().grid(row=0) self.nav_plot = Figure(figsize = (width+1, 2), dpi=72) self.nav_axes = self.nav_plot.add_subplot(111) self.nav_canvas = FigureCanvasTkAgg(self.nav_plot, master=self.root) self.nav_canvas.get_tk_widget().grid(row=1) self.nav_plot.subplots_adjust(bottom=0.2) self.agg_canvas = self.nav_canvas.get_tk_widget() self.slider = DoubleSlider(self.root, round=lambda x: round(x, 2), left_bound=2.0, right_bound=3.0) self.slider.grid(row=2, sticky=Tk.W+Tk.E+Tk.N+Tk.S) data = [(2.0, 0.6), (2.1, 0.9), (2.2, 0.7), (2.3, 0.8), (2.4, 0.5), (2.6, 0.2), (2.7, 0.3), (2.8, 0.6), (2.9, 0.4), (3.0, 0.1)] self.axes.set_xbound(2.0, 3.0) self.axes.add_collection(LineCollection([data])) self.nav_axes.set_xbound(2.0, 3.0) self.nav_axes.add_collection(LineCollection([data])) def run(self): self.plot.canvas.draw() self.nav_plot.canvas.draw() left_pad = self.nav_plot.subplotpars.left * self.nav_plot.get_figwidth() * self.nav_plot.dpi right_pad = (1-self.nav_plot.subplotpars.right) * self.nav_plot.get_figwidth() * self.nav_plot.dpi self.slider.config(left_padding=left_pad, right_padding=right_pad) def update_limits(left, right): self.agg_canvas.delete("OVERLAY") trans = blended_transform_factory(self.nav_axes.transData, self.nav_axes.transAxes) corner1 = trans.transform_point([left, 1]).tolist() corner2 = trans.transform_point([self.slider.left_bound, 0]).tolist() self.agg_canvas.create_rectangle([corner1, corner2], stipple="gray25", fill="gray",tags="OVERLAY") corner3 = trans.transform_point((right, 1)).tolist() corner4 = trans.transform_point((self.slider.right_bound, 0)).tolist() self.agg_canvas.create_rectangle([corner3, corner4], stipple="gray25", fill="gray",tags="OVERLAY") self.axes.set_xbound(left, right) self.plot.canvas.draw() self.slider.config(on_change=update_limits) self.slider.init() self.root.mainloop()
def create_at(self, fig: plt.Figure): fig.subplots_adjust(bottom=0.2) next_btn_pos = plt.axes([0.81, 0.05, 0.1, 0.075]) self._fig = fig self._btn_next = Button(next_btn_pos, "next") self._btn_next.on_clicked(self._next)
def set_figure_properties(fig: plt.Figure, **kwargs) -> None: """ Ease the configuration of a :class:`matplotlib.figure.Figure`. Parameters ---------- fig : matplotlib.figure.Figure The figure. Keyword arguments ----------------- fontsize : int Font size to use for the plot titles, and axes ticks and labels. Defaults to 12. tight_layout : bool `True` to fit the whole subplots into the figure area, `False` otherwise. Defaults to `True`. tight_layout_rect : Sequence[float] A rectangle (left, bottom, right, top) in the normalized figure coordinate that the whole subplots area (including labels) will fit into. Defaults to (0, 0, 1, 1). suptitle : str The figure title. Defaults to an empty string. xlabel : str TODO ylabel : str TODO figlegend_on : bool TODO figlegend_ax : int TODO figlegend_loc : `str` or `Tuple[float, float]` TODO figlegend_framealpha : float TODO figlegend_ncol : int TODO subplots_adjust_hspace : float TODO subplots_adjust_vspace : float TODO """ fontsize = kwargs.get("fontsize", 12) tight_layout = kwargs.get("tight_layout", True) tight_layout_rect = kwargs.get("tight_layout_rect", (0, 0, 1, 1)) suptitle = kwargs.get("suptitle", "") x_label = kwargs.get("x_label", "") x_labelpad = kwargs.get("x_labelpad", 20) y_label = kwargs.get("y_label", "") y_labelpad = kwargs.get("y_labelpad", 20) figlegend_on = kwargs.get("figlegend_on", False) figlegend_ax = kwargs.get("figlegend_ax", 0) figlegend_loc = kwargs.get("figlegend_loc", "lower center") figlegend_framealpha = kwargs.get("figlegend_framealpha", 1.0) figlegend_ncol = kwargs.get("figlegend_ncol", 1) wspace = kwargs.get("subplots_adjust_wspace", None) hspace = kwargs.get("subplots_adjust_hspace", None) rcParams["font.size"] = fontsize if suptitle is not None and suptitle != "": fig.suptitle(suptitle, fontsize=fontsize + 1) if x_label != "" or y_label != "": ax = fig.add_subplot(111) ax.set_frame_on(False) ax.set_xticks([]) ax.set_xticklabels([], visible=False) ax.set_yticks([]) ax.set_yticklabels([], visible=False) if x_label != "": ax.set_xlabel(x_label, labelpad=x_labelpad) if y_label != "": ax.set_ylabel(y_label, labelpad=y_labelpad) if tight_layout: fig.tight_layout(rect=tight_layout_rect) if figlegend_on: handles, labels = fig.get_axes()[figlegend_ax].get_legend_handles_labels() fig.legend( handles, labels, loc=figlegend_loc, framealpha=figlegend_framealpha, ncol=figlegend_ncol, ) if wspace is not None: fig.subplots_adjust(wspace=wspace) if hspace is not None: fig.subplots_adjust(hspace=hspace)