EMAworkbench
EMAworkbench copied to clipboard
Plot ticklabels for KDE over time
In the kde_over_time plotting function (and thus in the simple_kde function), the ticklabels are emptied using ax.set_xticklabels([]) ax.set_yticklabels([])
It would be nice if the years and outcome values would be indicated along the axis to provide better insight in what is plotted.
It doesn't answer your feature request, but you can add ticklabels back in manually by creating the figure, manipulating the axes, and then plotting/saving it. Here's possible approach from a recent project:
#outcomes of interest
ops = ['m-hotelops', 'm-beachops', 'm-diveops', 'm-boatops', 'm-waterops', 'm-all-ops']
#create KDE over time figure
fig, axes = kde_over_time(experiments, outcomes, outcomes_to_show = ops, log=True, colormap=cm.viridis)
#for each subplot in figure, set ticks and labels
for key in axes:
ax = axes[key]
#x-axis
ax.set_xlabel("time [years]")
ax.set_xticks(np.arange(0, 1051, 350))
ax.set_xticklabels(["0","10","20","30"], rotation="horizontal")
#y-axis
t = round(np.amax(outcomes[key]),2) #get upper bound of y-axis
yticks = ax.get_yticks() # Get locations and labels
ylabels = [t, 0]
ax.set_yticks([yticks[0], yticks[-1]])
ax.set_yticklabels(ylabels, va="center", rotation="horizontal")
#hacky legend label
ax.text(1.15, 0.5, "Kernel Density", transform=ax.transAxes, verticalalignment='center', rotation=90)
#format and save/plot figure
fig.set_size_inches(10, (len(ops)*3) )
plt.tight_layout()
plt.savefig("./figures/" + "ops.png", [dpi=300)
Results in:
I started looking into this, but it is a nontrivial issue to fix in general. We have to mimic the behavior of the MaxNLocator. This locator uses the view limits, but in this function, our view limits are based on the number of steps for which the KDE is calculated. So instead, we have to use the minimum and maximum values from the time dimension. Still, I haven't yet found an easy way of implementing this without diving deeper into custom locators in matplotlib.
Looking quickly at the source code of MaxNLocator, it might be sufficient to extend this class and overwrite the __init__
to include a vmin and vmax, and then use this in the __call__
method. Still have to test this idea.
Since I'm planning on a refactor of plotting for 2.4 anyways, shall I include this issue in that effort?
yes that makes sense