EMAworkbench icon indicating copy to clipboard operation
EMAworkbench copied to clipboard

Plot ticklabels for KDE over time

Open alexanderdrent opened this issue 4 years ago • 4 comments

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.

alexanderdrent avatar Jun 04 '20 14:06 alexanderdrent

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: ops

steipatr avatar Aug 13 '20 09:08 steipatr

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.

quaquel avatar Nov 01 '22 08:11 quaquel

Since I'm planning on a refactor of plotting for 2.4 anyways, shall I include this issue in that effort?

EwoutH avatar Nov 01 '22 08:11 EwoutH

yes that makes sense

quaquel avatar Nov 01 '22 08:11 quaquel