diff --git a/Utilities/Python/fdsplotlib.py b/Utilities/Python/fdsplotlib.py index a5e28474d2..ed6a9a199a 100644 --- a/Utilities/Python/fdsplotlib.py +++ b/Utilities/Python/fdsplotlib.py @@ -728,6 +728,7 @@ def plot_to_fig(x_data,y_data,**kwargs): plot_style = get_plot_style("fds") import matplotlib.pyplot as plt + import matplotlib.ticker as ticker plt.rcParams.update({ "pdf.use14corefonts": True, @@ -765,6 +766,7 @@ def plot_to_fig(x_data,y_data,**kwargs): default_legend_location = 'best' default_legend_framealpha = 1 default_markevery = 1 + detault_nticks = 6 markerfacecolor = None markeredgecolor = 'black' marker = None @@ -1056,13 +1058,40 @@ def plot_to_fig(x_data,y_data,**kwargs): ax.set_xlim(xmin,xmax) ax.set_ylim(ymin,ymax) + # --- Tick handling AFTER limits are set --- + if ax.get_xscale() == 'linear': + # ----- LINEAR AXIS ----- + if xticks is None and xnumticks is None: + ax.xaxis.set_major_locator(ticker.MaxNLocator(nbins=detault_nticks, min_n_ticks=4)) + sf = ticker.ScalarFormatter(useMathText=True) + sf.set_powerlimits((-3, 4)) + ax.xaxis.set_major_formatter(sf) + + elif ax.get_xscale() == 'log': + # ----- LOG AXIS ----- + # Do not touch scalar formatters – LogFormatter is correct. + ax.xaxis.set_major_locator(ticker.LogLocator(base=10)) + ax.xaxis.set_major_formatter(ticker.LogFormatterSciNotation(base=10)) + + # Same for y-axis + if ax.get_yscale() == 'linear': + if yticks is None and ynumticks is None: + ax.yaxis.set_major_locator(ticker.MaxNLocator(nbins=detault_nticks, min_n_ticks=4)) + sf = ticker.ScalarFormatter(useMathText=True) + sf.set_powerlimits((-3, 4)) + ax.yaxis.set_major_formatter(sf) + + elif ax.get_yscale() == 'log': + ax.yaxis.set_major_locator(ticker.LogLocator(base=10)) + ax.yaxis.set_major_formatter(ticker.LogFormatterSciNotation(base=10)) + # set number of ticks if requested by the user - if xnumticks != None: + if xnumticks is not None: if plot_type in ('loglog', 'semilogx'): ax.set_xticks(np.logspace(xmin, xmax, xnumticks)) else: ax.set_xticks(np.linspace(xmin, xmax, xnumticks)) - if ynumticks != None: + if ynumticks is not None: if plot_type in ('loglog', 'semilogy'): ax.set_yticks(np.logspace(ymin, ymax, ynumticks)) else: @@ -1072,12 +1101,6 @@ def plot_to_fig(x_data,y_data,**kwargs): if xticks is not None: ax.set_xticks(xticks) if yticks is not None: ax.set_yticks(yticks) - - if plot_type in ('loglog', 'semilogy'): - apply_global_exponent(ax, axis='y', fontsize=axeslabel_fontsize) - if plot_type in ('loglog', 'semilogx'): - apply_global_exponent(ax, axis='x', fontsize=axeslabel_fontsize) - if kwargs.get('revision_label'): add_version_string(ax=ax, version_str=kwargs.get('revision_label'), plot_type=plot_type, font_size=version_fontsize) @@ -1088,70 +1111,6 @@ def plot_to_fig(x_data,y_data,**kwargs): return fig -def apply_global_exponent(ax, axis='y', fontsize=10, minor_subs=None): - import numpy as np - from matplotlib.ticker import FuncFormatter, LogLocator - - if axis == 'y': - ticks = ax.get_yticks() - axis_obj = ax.yaxis - lims = ax.get_ylim() - else: - ticks = ax.get_xticks() - axis_obj = ax.xaxis - lims = ax.get_xlim() - - # Keep only positive finite ticks (for log axes) - ticks = np.array([t for t in ticks if t > 0 and np.isfinite(t)]) - if ticks.size == 0: - return - - # Choose representative exponent - exp = int(np.floor(np.log10(np.median(ticks)))) - scale = 10.0**exp - - # Major formatter: fixed-point decimals - def fmt(val, pos): - v = val / scale - return "{:g}".format(v) - - axis_obj.set_major_formatter(FuncFormatter(fmt)) - axis_obj.get_offset_text().set_visible(False) - - # Decide what to do with minor tick labels - span_decades = np.log10(lims[1]) - np.log10(max(lims[0], 1e-300)) - - # Default subs = 2, 4, 6, 8 - if minor_subs is None: - minor_subs = [2, 4, 6, 8] - - if span_decades <= 1.1: # only ~1 decade - axis_obj.set_minor_locator(LogLocator(base=10.0, subs=minor_subs, numticks=10)) - axis_obj.set_minor_formatter(FuncFormatter(lambda val, pos: "{:g}".format(val/scale))) - else: - ax.tick_params(axis=axis, which='minor', labelleft=False, labelbottom=False) - - # Force tick labels NOT to go through TeX - if axis == 'y': - for label in ax.get_yticklabels() + ax.get_yticklabels(minor=True): - label.set_usetex(False) - else: - for label in ax.get_xticklabels() + ax.get_xticklabels(minor=True): - label.set_usetex(False) - - # Place the ×10^exp text at the axis end - if exp != 0: - if axis == 'y': - ax.text(0, 1.01, rf"$\times 10^{{{exp}}}$", - transform=ax.transAxes, - ha='left', va='bottom', fontsize=fontsize) - else: - ax.text(1.0, -0.1, rf"$\times 10^{{{exp}}}$", - transform=ax.transAxes, - ha='right', va='top', fontsize=fontsize) - - - def parse_matlab_style(style): color = '' marker = ''