dermestid / bold-phylodiv-scripts

Scripts to calculate phylodiversity and its distribution from BOLD DNA barcode data.
1 stars 0 forks source link

Add map legend #122

Closed dermestid closed 3 years ago

dermestid commented 3 years ago

Code copied here from temporary version of update_pd.js:

    const rect_size = 20
    const legend_offset_x = 45;
    const legend_offset_y = 250
    map.selectAll(".legend")
        .attr("visibility", "hidden");
    let legend_group = map.selectAll("g.pd_legend");
    if (legend_group.empty()) {
        legend_group = map.append("g")
            .attr("class", "legend pd_legend")
            .style("outline", "solid black");
        legend_group.append("rect")
            .attr("x", legend_offset_x)
            .attr("y", legend_offset_y)
            .attr("fill", "white")
            .attr("width", 100)
            .attr("height", (rect_size + 5) * pick_colour.colours.length);
    }

    legend_group
        .attr("visibility", "visible")
        .selectAll("g")
        .data(pick_colour.colours, (d, i) => d ? i : this.id.substring(7))
        .join(
            enter => {
                const g = enter.append("g")
                    .attr("id", (c, i) => `legend_${i}`);
                g.append("rect")
                    .attr("width", rect_size)
                    .attr("height", rect_size)
                    .attr("x", legend_offset_x)
                    .attr("y", (c, i) => legend_offset_y + i * (rect_size + 5))
                    .attr("fill", c => c);
                g.append("text")
                    .attr("id", (c, i) => `legend_text_${i}`)
                    .attr("x", legend_offset_x + rect_size * 1.2)
                    .attr("y", (c, i) => 5 + legend_offset_y + i * (rect_size + 5) + rect_size / 2)
                    .text((c, i) => pick_colour.interval(id, i))
                    .attr("text-anchor", "left")
                    .style("alignment-baseline", "middle");
                return g;
            },
            update => update
                .select("text")
                .text((c, i) => pick_colour.interval(id, i))
        );
dermestid commented 3 years ago

Updated pick_colour.js:

export default function pick_colour(f, set, accessor, id = "", rounding = 0, method = { deciles: true, clusters: false }) {
    if (pick_colour.scale_cache === undefined)
        pick_colour.scale_cache = {};

    pick_colour.interval = (id, i) => {
        if (i === 0)
            return `0 - ${pick_colour.scale_cache[id][i]}`;
        else if (i >= pick_colour.scale_cache[id].length)
            return `> ${pick_colour.scale_cache[id][pick_colour.scale_cache[id].length - 1]}`;
        else
            return `${pick_colour.scale_cache[id][i - 1]} - ${pick_colour.scale_cache[id][i]}`
    };

    const round = n => {
        if (rounding <= 0) return n;
        if (n === 0) return n;
        const abs_n = (n > 0) ? n : -n;
        const places = Math.ceil(Math.log10(abs_n));
        const denom_order = places - rounding;
        const denom = 10 ** denom_order;
        const rounded = (denom * Math.floor(abs_n / denom));
        return (n > 0) ? rounded : -rounded;
    };

    if (pick_colour.colours === undefined)
        pick_colour.colours = ['#2c7bb6', '#abd9e9', '#e4efaf', '#fdae61', '#d7191c'];

    let scales = [];
    if (id !== "" && pick_colour.scale_cache[id] !== undefined) {
        scales = pick_colour.scale_cache[id];
    } else {
        if (method.clusters) {
            const data = set.map(accessor);
            scales = d3
                .scaleCluster()
                .domain(data)
                .range(pick_colour.colours)
                .clusters()
                .map(round);
        } else if (method.deciles) {
            const data = set.map(accessor).sort((a, b) => a - b);
            scales = [0.05, 0.3, 0.7, 0.95]
                .map(level => round(d3.quantileSorted(data, level)));
        }
        pick_colour.scale_cache[id] = scales;
    }

    // console.log(JSON.stringify(scales));

    const x = accessor(f);
    for (let i = 0; i < scales.length; i++) {
        if (x < scales[i]) {
            return pick_colour.colours[i];
        }
    }
    return pick_colour.colours[pick_colour.colours.length - 1];
}