code: def _shared_ax_config(
      ax: Axes,
      file_key: Tuple[str, ...],
      column_key: Tuple[str, ...],
      row_key: Tuple[str, ...],
      metric: Metric,
  ) -> None:
      title_key = column_key + row_key
      if metric.name in title_key:
          title_key = tuple(k for k in title_key if k != metric.name)
      if title_key:
          ax.set_title(_join_key(title_key))
  
      ax.tick_params(axis="x", labelrotation=30)
  
      if metric.unit is None:
          y_label = metric.pretty_name
      else:
          y_label = f"{metric.pretty_name} ({metric.unit})"
      ax.set_ylabel(y_label)
  
      if metric.lower_bound is not None:
          ax.set_ylim(bottom=metric.lower_bound)
      if metric.upper_bound is not None:
          ax.set_ylim(top=metric.upper_bound)
  
file_path: GPflow/benchmark/plotters.py
imports: from dataclasses import replace
  from math import isnan
  from typing import Collection, Tuple
  import pandas
  from matplotlib.axes import Axes
  from matplotlib.dates import date2num
  from benchmark.grouping import GroupingKey, GroupingSpec, group
  from benchmark.metadata import BenchmarkMetadata, parse_timestamp
  from benchmark.metric_api import METRICS, Metric
  from benchmark.plotter_api import make_plotter
label_desc: Use image node_id 3 for calling a global function with example usage: _shared_ax_config(ax, file_key, column_key, row_key, metric) without return types