All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.tablesaw.plotting.StandardColors Maven / Gradle / Ivy

There is a newer version: 0.24.4
Show newest version
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package tech.tablesaw.plotting;

import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Range;
import com.opencsv.CSVReader;

import javax.annotation.Nullable;
import java.awt.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.Set;

/**
 *
 */
public class StandardColors {

    static final ImmutableMultimap colorMap = ImmutableMultimap.copyOf(loadColors());
    static ImmutableList neutralColors = ImmutableList.copyOf(loadNeutrals());

    /**
     * Loads the standard colors from a file
     *
     * @return
     */
    static Multimap loadColors() {

        Multimap standards = LinkedListMultimap.create();

        InputStream resourceAsStream = StandardColors.class.getResourceAsStream("/colors.txt");

        String[] nextLine;
        try (CSVReader reader = new CSVReader(new InputStreamReader(resourceAsStream))) {
            // Add the rows
            while ((nextLine = reader.readNext()) != null) {
                for (String colorData : nextLine) {
                    String[] colorSplit = colorData.trim().split(" ");
                    String vHue = colorSplit[0];
                    String valueChroma = colorSplit[1];
                    String[] valueAndChroma = valueChroma.split("/");
                    int vValue = Integer.parseInt(valueAndChroma[0]);
                    int vChroma = Integer.parseInt(valueAndChroma[1]);
                    String vHex = colorSplit[2];

                    StandardColor color = new StandardColor(vHue, vChroma, vValue, vHex);
                    if (!color.hue().equals(Hue.Neutral)) {
                        standards.put(color.hue(), color);
                    }
                }
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Unable to read predefined colors file", e);
        }
        return standards;
    }

    static List loadNeutrals() {

        ArrayList neutrals = new ArrayList<>();

        InputStream resourceAsStream = StandardColors.class.getResourceAsStream("/colors.txt");

        String[] nextLine;
        try (CSVReader reader = new CSVReader(new InputStreamReader(resourceAsStream))) {
            // Add the rows
            while ((nextLine = reader.readNext()) != null) {
                for (String colorData : nextLine) {
                    String[] colorSplit = colorData.trim().split(" ");
                    String vHue = colorSplit[0];
                    String valueChroma = colorSplit[1];
                    String[] valueAndChroma = valueChroma.split("/");
                    int vValue = Integer.parseInt(valueAndChroma[0]);
                    int vChroma = Integer.parseInt(valueAndChroma[1]);
                    String vHex = colorSplit[2];

                    StandardColor color = new StandardColor(vHue, vChroma, vValue, vHex);
                    if (color.hue().equals(Hue.Neutral)) {
                        neutrals.add(color);
                    }
                }
            }
        } catch (IOException ex) {
            throw new IllegalStateException("Unable to read predefined colors file", ex);
        }
        return neutrals;
    }

    static ImmutableList getNeutralColors() {
        return neutralColors;
    }

    static Set getHues() {
        return colorMap.keySet();
    }

    static ImmutableCollection getColors(Hue hue) {
        return colorMap.get(hue);
    }

    public static List getFilteredColors(Hue hue, Range chromaRange, Range
            valueRange) {
        List filtered = new ArrayList<>();
        ImmutableCollection colors = colorMap.get(hue);
        for (StandardColor color : colors) {
            if (chromaRange.contains(color.chroma()) && valueRange.contains(color.value())) {
                filtered.add(color);
            }
        }
        return filtered;
    }

    static Color[] allGreys() {
        List colors = new ArrayList<>(11);
        colors.add(Color.WHITE);
        for (StandardColor color : neutralColors) {
            colors.add(color.asColor());
        }
        colors.add(Color.BLACK);
        return colors.toArray(new Color[11]);
    }

    static Color[] ggPlotGreys() {
        List colors = new ArrayList<>(9);
        for (StandardColor color : neutralColors.subList(1, neutralColors.size())) {
            colors.add(color.asColor());
        }
        colors.add(Color.BLACK);
        return colors.toArray(new Color[9]);
    }

    static Color[] ggPlotGreys(int size) {
        size = Math.min(size, 9);
        List colors = new ArrayList<>(size);
        int start = (neutralColors.size() - size) + 1;
        for (StandardColor color : neutralColors.subList(start, neutralColors.size())) {
            colors.add(color.asColor());
        }
        colors.add(Color.BLACK);
        return colors.toArray(new Color[size]);
    }

    static Color[] ggPlotGreys6() {
        int size = 6;
        List colors = new ArrayList<>(size);
        colors.add(Color.WHITE);
        colors.add(neutralColors.get(2).asColor());
        colors.add(neutralColors.get(4).asColor());
        colors.add(neutralColors.get(6).asColor());
        colors.add(neutralColors.get(8).asColor());
        colors.add(Color.BLACK);
        return colors.toArray(new Color[size]);
    }

    /**
     * Returns n hues, chosen to maximize the visual distance between them. We exclude grays from the list
     */
    static List randomHues(int n) {
        List resultList = new ArrayList<>(n);
        int huesAvailable = Hue.values().length - 1; // we're going to take out the "neutral hue" aka gray
        int maxDistance = huesAvailable / n;
        Random random = new Random();
        int starting = random.nextInt(huesAvailable);
        List hues = new ArrayList<>(huesAvailable);
        for (int i = starting; i < huesAvailable; i++) {
            if (Hue.values()[i] != Hue.Neutral) {
                hues.add(Hue.values()[i]);
            }
        }
        for (int i = 0; i < starting; i++) {
            if (Hue.values()[i] != Hue.Neutral) {
                hues.add(Hue.values()[i]);
            }
        }

        for (int j = 0; j < huesAvailable && resultList.size() < n; j = j + maxDistance) {
            resultList.add(hues.get(j));
        }
        return resultList;
    }

    public static List randomColors(int n) {
        Random random = new Random();

        List hues = randomHues(n);
        List colors = new ArrayList<>(n);

        Range chromaRange = Range.closed(4, 12);
        Range valueRange = Range.closed(4, 8);

        for (Hue hue : hues) {
            List standardColors = getFilteredColors(hue, chromaRange, valueRange);
            StandardColor randomColor = standardColors.get(random.nextInt(standardColors.size()));
            colors.add(randomColor.asColor());
        }
        return colors;
    }

    public static Color[] standardColorArray() {
        List standardColors = standardColors();
        return standardColors().toArray(new Color[standardColors.size()]);
    }

    public static List standardColors() {

        List colors = new ArrayList<>();
        colors.add(color(Hue.Red_5, 14, 4));
        colors.add(color(Hue.Yellow_2_5, 12, 8));
        colors.add(color(Hue.Purple_7_5, 10, 4));
        colors.add(color(Hue.YellowRed_5, 12, 7));
        colors.add(color(Hue.PurpleBlue_2_5, 6, 8));

        colors.add(color(Hue.Yellow_5, 4, 7));
        colors.add(color(Hue.GreenYellow_5, 2, 5));
        colors.add(color(Hue.Green_2_5, 10, 6));
        colors.add(color(Hue.RedPurple_5, 10, 7));
        colors.add(color(Hue.PurpleBlue_2_5, 8, 4));

        colors.add(color(Hue.Red_7_5, 8, 7));
        colors.add(color(Hue.PurpleBlue_2_5, 10, 4));
        colors.add(color(Hue.YellowRed_7_5, 12, 7));
        colors.add(color(Hue.RedPurple_7_5, 12, 4));
        colors.add(color(Hue.Yellow_10, 10, 8));

        colors.add(color(Hue.YellowRed_2_5, 8, 3));
        colors.add(color(Hue.GreenYellow_5, 10, 7));
        colors.add(color(Hue.Red_10, 14, 5));
        colors.add(color(Hue.GreenYellow_5, 4, 2));
        colors.add(allGreys()[2]);

        return colors;
    }

    @Nullable
    static Color color(Hue hue, int chroma, int value) {
        Collection options = colorMap.get(hue);
        for (StandardColor standardColor : options) {
            if (standardColor.chroma() == chroma &&
                    standardColor.value() == value) {
                return standardColor.asColor();
            }
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy