sh0nk / matplotlib4j

Matplotlib for java: A simple graph plot library for java, scala and kotlin with powerful python matplotlib

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Histogram bar alignments seem to be imprecise

toninagy opened this issue · comments

plot.hist().add(measurements).rwidth(0.1).bins(4).stacked(false).align(HistBuilder.Align.mid).orientation(HistBuilder.Orientation.vertical);
plot.xlim(1,2);
plot.title("First run");
plot.show();

This alignment is imprecise, e.g. if I zoom in on the plot, I've got a bar on 1.09, 1.29, 1.47 and 1.66 whereas the measurements list includes the double values of 1.0, 1.25, 1.5, 1.75.
If I adjust the HistBuilder.Align from mid to left, only the bar above 1.0 will be placed correctly, the others are off by a few decimal points. If I set it the Align property to right, then the other end will be precisely placed. But either way, I can't seem to make this work so that all bars are placed precisely.

Hi @toninagy

First of all, the behavior is actually derived from the original matplotlib instead of matplotlib4j. In fact, you must see the translated python code when you run this code.

    @Test
    public void testOriginal() throws IOException, PythonExecutionException {
        Plot plt = new PlotImpl(DRY_RUN);
        List<Double> x = Lists.newArrayList(1.0, 1.25, 1.5, 1.75);
        plt.hist().add(x).rwidth(0.1).bins(4).stacked(false).align(HistBuilder.Align.mid).orientation(HistBuilder.Orientation.vertical);
        plt.xlim(1,2);
        plt.title("Original");
        plt.show();
    }
DEBUG - .plot command: ret_a985458e_a3a8_4f2f_92ef_277545c853c4 = plt.hist([[1.0, 1.25, 1.5, 1.75]],rwidth=0.1,bins=4,orientation="vertical",stacked=False,align="mid")
DEBUG - .plot command: plt.xlim(1,2)
DEBUG - .plot command: plt.title("Original")

Screen Shot 2021-03-10 at 2 30 49

On that condition, I can answer how to do workaround. Actually when you specify .bin(4), it just orders the values split into 4 bins, but not decide the positions. To decide the bin edge position, you can use .bin(list). For your case, this is the complete code to fix.

    @Test
    public void testFixed() throws IOException, PythonExecutionException {
        Plot plt = new PlotImpl(DRY_RUN);
        List<Double> x = Lists.newArrayList(1.0, 1.25, 1.5, 1.75);
        List<Double> bin = Lists.newArrayList(1.0, 1.25, 1.5, 1.75, 2.0);
        plt.hist().add(x).rwidth(0.1).bins(bin).stacked(false).align(HistBuilder.Align.left).orientation(HistBuilder.Orientation.vertical);
        plt.xlim(1,2);
        plt.title("Fixed");
        plt.show();
    }

Screen Shot 2021-03-10 at 2 30 59

This must be interesting for you to see how to handle the hist function: https://stackoverflow.com/questions/27083051/matplotlib-xticks-not-lining-up-with-histogram

Thank you so much, I appreciate your answer and your work!
Cheers