def __init__(self, table_header=None, table_description=None, col_header=None, cell_values=None, raw_cell_values=None, col_types=None, row_header=None, col_formats=None): """ Create new H2OTwoDimTable object. :param table_header: Header for the entire table. :param table_description: Longer description of the table. :param col_header: list of column names (used in conjunction with) :param cell_values: table values, as an array of individual rows :param raw_cell_values: :param col_types: :param row_header: ignored. :param col_formats: ignored. """ assert_is_type(table_header, None, str) assert_is_type(table_description, None, str) assert_is_type(col_header, None, [str]) assert_is_type(col_types, None, [str]) assert_is_type( cell_values, None, I([[object]], lambda m: all(len(row) == len(m[0]) for row in m))) self._table_header = table_header self._table_description = table_description self._col_header = col_header self._col_types = col_types self._cell_values = cell_values or self._parse_values( raw_cell_values, col_types)
def start(jar_path=None, nthreads=-1, enable_assertions=True, max_mem_size=None, min_mem_size=None, ice_root=None, port="54321+", verbose=True): """ Start new H2O server on the local machine. :param jar_path: Path to the h2o.jar executable. If not given, then we will search for h2o.jar in the locations returned by `._jar_paths()`. :param nthreads: Number of threads in the thread pool. This should be related to the number of CPUs used. -1 means use all CPUs on the host. A positive integer specifies the number of CPUs directly. :param enable_assertions: If True, pass `-ea` option to the JVM. :param max_mem_size: Maximum heap size (jvm option Xmx), in bytes. :param min_mem_size: Minimum heap size (jvm option Xms), in bytes. :param ice_root: A directory where H2O stores its temporary files. Default location is determined by tempfile.mkdtemp(). :param port: Port where to start the new server. This could be either an integer, or a string of the form "DDDDD+", indicating that the server should start looking for an open port starting from DDDDD and up. :param verbose: If True, then connection info will be printed to the stdout. :returns: a new H2OLocalServer instance """ assert_is_type(jar_path, None, str) assert_is_type(port, None, int, str) assert_is_type(nthreads, -1, BoundInt(1, 4096)) assert_is_type(enable_assertions, bool) assert_is_type(min_mem_size, None, int) assert_is_type(max_mem_size, None, BoundInt(1 << 25)) assert_is_type(ice_root, None, I(str, os.path.isdir)) if jar_path: assert_satisfies(jar_path, jar_path.endswith("h2o.jar")) if min_mem_size is not None and max_mem_size is not None and min_mem_size > max_mem_size: raise H2OValueError("`min_mem_size`=%d is larger than the `max_mem_size`=%d" % (min_mem_size, max_mem_size)) if port is None: port = "54321+" baseport = None # TODO: get rid of this port gimmick and have 2 separate parameters. if is_type(port, str): if port.isdigit(): port = int(port) else: if not(port[-1] == "+" and port[:-1].isdigit()): raise H2OValueError("`port` should be of the form 'DDDD+', where D is a digit. Got: %s" % port) baseport = int(port[:-1]) port = 0 hs = H2OLocalServer() hs._verbose = bool(verbose) hs._jar_path = hs._find_jar(jar_path) hs._ice_root = ice_root if not ice_root: hs._ice_root = tempfile.mkdtemp() hs._tempdir = hs._ice_root if verbose: print("Attempting to start a local H2O server...") hs._launch_server(port=port, baseport=baseport, nthreads=int(nthreads), ea=enable_assertions, mmax=max_mem_size, mmin=min_mem_size) if verbose: print(" Server is running at %s://%s:%d" % (hs.scheme, hs.ip, hs.port)) atexit.register(lambda: hs.shutdown()) return hs
def start(jar_path=None, nthreads=-1, enable_assertions=True, max_mem_size=None, min_mem_size=None, ice_root=None, log_dir=None, log_level=None, max_log_file_size=None, port="54321+", name=None, extra_classpath=None, verbose=True, jvm_custom_args=None, bind_to_localhost=True): """ Start new H2O server on the local machine. :param jar_path: Path to the h2o.jar executable. If not given, then we will search for h2o.jar in the locations returned by `._jar_paths()`. :param nthreads: Number of threads in the thread pool. This should be related to the number of CPUs used. -1 means use all CPUs on the host. A positive integer specifies the number of CPUs directly. :param enable_assertions: If True, pass `-ea` option to the JVM. :param max_mem_size: Maximum heap size (jvm option Xmx), in bytes. :param min_mem_size: Minimum heap size (jvm option Xms), in bytes. :param log_dir: Directory for H2O logs to be stored if a new instance is started. Default directory is determined by H2O internally. :param log_level: The logger level for H2O if a new instance is started. :param max_log_file_size: Maximum size of INFO and DEBUG log files. The file is rolled over after a specified size has been reached. (The default is 3MB. Minimum is 1MB and maximum is 99999MB) :param ice_root: A directory where H2O stores its temporary files. Default location is determined by tempfile.mkdtemp(). :param port: Port where to start the new server. This could be either an integer, or a string of the form "DDDDD+", indicating that the server should start looking for an open port starting from DDDDD and up. :param name: name of the h2o cluster to be started :param extra_classpath: List of paths to libraries that should be included on the Java classpath. :param verbose: If True, then connection info will be printed to the stdout. :param jvm_custom_args: Custom, user-defined arguments for the JVM H2O is instantiated in :param bind_to_localhost: A flag indicating whether access to the H2O instance should be restricted to the local machine (default) or if it can be reached from other computers on the network. Only applicable when H2O is started from the Python client. :returns: a new H2OLocalServer instance """ assert_is_type(jar_path, None, str) assert_is_type(port, None, int, str) assert_is_type(name, None, str) assert_is_type(nthreads, -1, BoundInt(1, 4096)) assert_is_type(enable_assertions, bool) assert_is_type(min_mem_size, None, int) assert_is_type(max_mem_size, None, BoundInt(1 << 25)) assert_is_type(log_dir, str, None) assert_is_type(log_level, str, None) assert_satisfies( log_level, log_level in [None, "TRACE", "DEBUG", "INFO", "WARN", "ERRR", "FATA"]) assert_is_type(max_log_file_size, str, None) assert_is_type(ice_root, None, I(str, os.path.isdir)) assert_is_type(extra_classpath, None, [str]) assert_is_type(jvm_custom_args, list, None) assert_is_type(bind_to_localhost, bool) if jar_path: assert_satisfies(jar_path, jar_path.endswith("h2o.jar")) if min_mem_size is not None and max_mem_size is not None and min_mem_size > max_mem_size: raise H2OValueError( "`min_mem_size`=%d is larger than the `max_mem_size`=%d" % (min_mem_size, max_mem_size)) if port is None: port = "54321+" baseport = None # TODO: get rid of this port gimmick and have 2 separate parameters. if is_type(port, str): if port.isdigit(): port = int(port) else: if not (port[-1] == "+" and port[:-1].isdigit()): raise H2OValueError( "`port` should be of the form 'DDDD+', where D is a digit. Got: %s" % port) baseport = int(port[:-1]) port = 0 hs = H2OLocalServer() hs._verbose = bool(verbose) hs._jar_path = hs._find_jar(jar_path) hs._extra_classpath = extra_classpath hs._ice_root = ice_root hs._name = name if not ice_root: hs._ice_root = tempfile.mkdtemp() hs._tempdir = hs._ice_root if verbose: print("Attempting to start a local H2O server...") hs._launch_server(port=port, baseport=baseport, nthreads=int(nthreads), ea=enable_assertions, mmax=max_mem_size, mmin=min_mem_size, jvm_custom_args=jvm_custom_args, bind_to_localhost=bind_to_localhost, log_dir=log_dir, log_level=log_level, max_log_file_size=max_log_file_size) if verbose: print(" Server is running at %s://%s:%d" % (hs.scheme, hs.ip, hs.port)) atexit.register(lambda: hs.shutdown()) return hs
def std_coef_plot(self, num_of_features=None, server=False): """ Plot a GLM model's standardized coefficient magnitudes. :param num_of_features: the number of features shown in the plot. :param server: ? :returns: None. """ assert_is_type(num_of_features, None, I(int, lambda x: x > 0)) # check that model is a glm if self._model_json["algo"] != "glm": raise H2OValueError("This function is available for GLM models only") plt = _get_matplotlib_pyplot(server) if not plt: return # get unsorted tuple of labels and coefficients unsorted_norm_coef = self.coef_norm().items() # drop intercept value then sort tuples by the coefficient's absolute value drop_intercept = [tup for tup in unsorted_norm_coef if tup[0] != "Intercept"] norm_coef = sorted(drop_intercept, key=lambda x: abs(x[1]), reverse=True) signage = [] for element in norm_coef: # if positive including zero, color blue, else color orange (use same colors as Flow) if element[1] >= 0: signage.append("#1F77B4") # blue else: signage.append("#FF7F0E") # dark orange # get feature labels and their corresponding magnitudes feature_labels = [tup[0] for tup in norm_coef] norm_coef_magn = [abs(tup[1]) for tup in norm_coef] # specify bar centers on the y axis, but flip the order so largest bar appears at top pos = range(len(feature_labels))[::-1] # specify the bar lengths val = norm_coef_magn # check number of features, default is all the features if num_of_features is None: num_of_features = len(val) # plot horizontal plot fig, ax = plt.subplots(1, 1, figsize=(14, 10)) # create separate plot for the case where num_of_features = 1 if num_of_features == 1: plt.barh(pos[0], val[0], align="center", height=0.8, color=signage[0], edgecolor="none") # Hide the right and top spines, color others grey ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["bottom"].set_color("#7B7B7B") ax.spines["left"].set_color("#7B7B7B") # Only show ticks on the left and bottom spines ax.yaxis.set_ticks_position("left") ax.xaxis.set_ticks_position("bottom") plt.yticks([0], feature_labels[0]) ax.margins(y=0.5) else: plt.barh(pos[0:num_of_features], val[0:num_of_features], align="center", height=0.8, color=signage[0:num_of_features], edgecolor="none") # Hide the right and top spines, color others grey ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["bottom"].set_color("#7B7B7B") ax.spines["left"].set_color("#7B7B7B") # Only show ticks on the left and bottom spines ax.yaxis.set_ticks_position("left") ax.xaxis.set_ticks_position("bottom") plt.yticks(pos[0:num_of_features], feature_labels[0:num_of_features]) ax.margins(y=0.05) # generate custom fake lines that will be used as legend entries: # check if positive and negative values exist # if positive create positive legend if "#1F77B4" in signage[0:num_of_features] and "#FF7F0E" not in signage[0:num_of_features]: color_ids = {"Positive": "#1F77B4"} markers = [plt.Line2D([0, 0], [0, 0], color=color, marker="s", linestyle="") for color in signage[0:num_of_features]] lgnd = plt.legend(markers, color_ids, numpoints=1, loc="best", frameon=False, fontsize=13) lgnd.legendHandles[0]._legmarker.set_markersize(10) # if neg create neg legend elif "#FF7F0E" in signage[0:num_of_features] and "#1F77B4" not in signage[0:num_of_features]: color_ids = {"Negative": "#FF7F0E"} markers = [plt.Line2D([0, 0], [0, 0], color=color, marker="s", linestyle="") for color in set(signage[0:num_of_features])] lgnd = plt.legend(markers, color_ids, numpoints=1, loc="best", frameon=False, fontsize=13) lgnd.legendHandles[0]._legmarker.set_markersize(10) # if both provide both colors in legend else: color_ids = {"Positive": "#1F77B4", "Negative": "#FF7F0E"} markers = [plt.Line2D([0, 0], [0, 0], color=color, marker="s", linestyle="") for color in set(signage[0:num_of_features])] lgnd = plt.legend(markers, color_ids, numpoints=1, loc="best", frameon=False, fontsize=13) lgnd.legendHandles[0]._legmarker.set_markersize(10) lgnd.legendHandles[1]._legmarker.set_markersize(10) # Hide the right and top spines, color others grey ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["bottom"].set_color("#7B7B7B") ax.spines["left"].set_color("#7B7B7B") # Only show ticks on the left and bottom spines # ax.yaxis.set_ticks_position("left") # ax.xaxis.set_ticks_position("bottom") plt.yticks(pos[0:num_of_features], feature_labels[0:num_of_features]) plt.tick_params(axis="x", which="minor", bottom="off", top="off", labelbottom="off") plt.title("Standardized Coef. Magnitudes: H2O GLM", fontsize=20) # plt.axis("tight") # show plot if not server: plt.show()
def test_asserts(): """Test type-checking functionality.""" def assert_error(*args, **kwargs): """Check that assert_is_type() with given arguments throws an error.""" try: assert_is_type(*args, **kwargs) raise RuntimeError("Failed to throw an exception") except H2OTypeError as e: # Check whether the message can stringify properly message = str(e) assert len(message) < 1000 return class A(object): pass class B(A): pass class C(A): pass class D(B, C): pass assert_is_type(3, int) assert_is_type(2**100, int) assert_is_type("3", str) assert_is_type(u"3", str) assert_is_type("foo", u"foo") assert_is_type(u"foo", "foo") assert_is_type("I", *list("ABCDEFGHIJKL")) assert_is_type(False, bool) assert_is_type(43, str, bool, int) assert_is_type(4 / 3, int, float) assert_is_type(None, None) assert_is_type(None, A, str, None) assert_is_type([], [float]) assert_is_type([1, 4, 5], [int]) assert_is_type([1.0, 2, 5], [int, float]) assert_is_type([[2.0, 3.1, 0], [2, 4.4, 1.1], [-1, 0]], [[int, float]]) assert_is_type([1, None, 2], [int, float, None]) assert_is_type({1, 5, 1, 1, 3}, {int}) assert_is_type({1, "hello", 3}, {int, str}) assert_is_type({"foo": 1, "bar": 2}, {str: int}) assert_is_type({ "foo": 3, "bar": [5], "baz": None }, {str: U(int, None, [int])}) assert_is_type({ "foo": 1, "bar": 2 }, { "foo": int, "bar": U(int, float, None), "baz": bool }) assert_is_type((1, 3), (int, int)) assert_is_type(("a", "b", "c"), (int, int, int), (str, str, str)) assert_is_type([1, [2], [{3}]], [int, [int], [{3}]]) assert_is_type(A(), None, A) assert_is_type(B(), None, A) assert_is_type(C(), A, B) assert_is_type(D(), I(A, B, C)) assert_is_type(A, type) for a in range(-2, 5): assert_is_type(a, -2, -1, 0, 1, 2, 3, 4) assert_is_type(1, numeric) assert_is_type(2.2, numeric) assert_is_type(1, I(numeric, object)) assert_error(3, str) assert_error("Z", *list("ABCDEFGHIJKL")) assert_error(u"Z", "a", "...", "z") assert_error("X", u"x") assert_error(0, bool) assert_error(0, float, str, bool, None) assert_error([1, 5], [float]) assert_error((1, 3), (int, str), (str, int), (float, float)) assert_error(A(), None, B) assert_error(A, A) assert_error({ "foo": 1, "bar": "2" }, { "foo": int, "bar": U(int, float, None) }) assert_error(3, 0, 2, 4) assert_error(None, numeric) assert_error("sss", numeric) assert_error(B(), I(A, B, C)) assert_error(2, I(int, str)) url_regex = r"^(https?)://((?:[\w-]+\.)*[\w-]+):(\d+)/?$" assert_matches("Hello, world!", r"^(\w+), (\w*)!$") assert_matches("http://127.0.0.1:3233/", url_regex) m = assert_matches("https://localhost:54321", url_regex) assert m.group(1) == "https" assert m.group(2) == "localhost" assert m.group(3) == "54321" x = 5 assert_satisfies(x, x < 1000) assert_satisfies(x, x**x > 1000) assert_satisfies(url_regex, url_regex.lower() == url_regex) try: assert_satisfies(url_regex, url_regex.upper() == url_regex) except H2OValueError as e: assert "url_regex.upper() == url_regex" in str( e), "Error message is bad: " + str(e)
def test_asserts(): """Test type-checking functionality.""" def assert_error(*args, **kwargs): """Check that assert_is_type() with given arguments throws an error.""" try: assert_is_type(*args, **kwargs) raise RuntimeError("Failed to throw an exception") except H2OTypeError as exc: # Check whether the message can stringify properly message = str(exc) assert len(message) < 1000 return class A(object): """Dummy A.""" class B(A): """Dummy B.""" class C(A): """Dummy C.""" class D(B, C): """Dummy D.""" assert_is_type(3, int) assert_is_type(2**100, int) assert_is_type("3", str) assert_is_type(u"3", str) assert_is_type("foo", u"foo") assert_is_type(u"foo", "foo") assert_is_type("I", *list("ABCDEFGHIJKL")) assert_is_type(False, bool) assert_is_type(43, str, bool, int) assert_is_type(4 / 3, int, float) assert_is_type(None, None) assert_is_type(None, A, str, None) assert_is_type([], [float]) assert_is_type([1, 4, 5], [int]) assert_is_type([1.0, 2, 5], [int, float]) assert_is_type([[2.0, 3.1, 0], [2, 4.4, 1.1], [-1, 0]], [[int, float]]) assert_is_type([1, None, 2], [int, float, None]) assert_is_type({1, 5, 1, 1, 3}, {int}) assert_is_type({1, "hello", 3}, {int, str}) assert_is_type({"foo": 1, "bar": 2}, {str: int}) assert_is_type({"foo": 3, "bar": [5], "baz": None}, {str: U(int, None, [int])}) assert_is_type({"foo": 1, "bar": 2}, {"foo": int, "bar": U(int, float, None), "baz": bool}) assert_is_type({}, {"spam": int, "egg": int}) assert_is_type({"spam": 10}, {"spam": int, "egg": int}) assert_is_type({"egg": 1}, {"spam": int, "egg": int}) assert_is_type({"egg": 1, "spam": 10}, {"spam": int, "egg": int}) assert_is_type({"egg": 1, "spam": 10}, Dict(egg=int, spam=int)) assert_is_type({"egg": 1, "spam": 10}, Dict(egg=int, spam=int, ham=U(int, None))) assert_is_type((1, 3), (int, int)) assert_is_type(("a", "b", "c"), (int, int, int), (str, str, str)) assert_is_type((1, 3, 4, 7, 11, 18), Tuple(int)) assert_is_type((1, 3, "spam", 3, "egg"), Tuple(int, str)) assert_is_type([1, [2], [{3}]], [int, [int], [{3}]]) assert_is_type(A(), None, A) assert_is_type(B(), None, A) assert_is_type(C(), A, B) assert_is_type(D(), I(A, B, C)) assert_is_type(A, type) assert_is_type(B, lambda aa: issubclass(aa, A)) for a in range(-2, 5): assert_is_type(a, -2, -1, 0, 1, 2, 3, 4) assert_is_type(1, numeric) assert_is_type(2.2, numeric) assert_is_type(1, I(numeric, object)) assert_is_type(34, I(int, NOT(0))) assert_is_type(["foo", "egg", "spaam"], [I(str, NOT("spam"))]) assert_is_type(H2OFrame(), h2oframe) assert_is_type([[2.0, 3.1, 0], [2, 4.4, 1.1], [-1, 0, 0]], I([[numeric]], lambda v: all(len(vi) == len(v[0]) for vi in v))) assert_is_type([None, None, float('nan'), None, "N/A"], [None, "N/A", I(float, math.isnan)]) assert_error(3, str) assert_error(0, float) assert_error("Z", *list("ABCDEFGHIJKL")) assert_error(u"Z", "a", "...", "z") assert_error("X", u"x") assert_error(0, bool) assert_error(0, float, str, bool, None) assert_error([1, 5], [float]) assert_error((1, 3), (int, str), (str, int), (float, float)) assert_error(A(), None, B) assert_error(A, A) assert_error(A, lambda aa: issubclass(aa, B)) assert_error(135, I(int, lambda x: 0 <= x <= 100)) assert_error({"foo": 1, "bar": "2"}, {"foo": int, "bar": U(int, float, None)}) assert_error(3, 0, 2, 4) assert_error(None, numeric) assert_error("sss", numeric) assert_error(B(), I(A, B, C)) assert_error(2, I(int, str)) assert_error(0, I(int, NOT(0))) assert_error(None, NOT(None)) assert_error((1, 3, "2", 3), Tuple(int)) assert_error({"spam": 10}, Dict(spam=int, egg=int)) assert_error({"egg": 5}, Dict(spam=int, egg=int)) assert_error(False, h2oframe, pandas_dataframe, numpy_ndarray) assert_error([[2.0, 3.1, 0], [2, 4.4, 1.1], [-1, 0]], I([[numeric]], lambda v: all(len(vi) == len(v[0]) for vi in v))) try: # Cannot use `assert_error` here because typechecks module cannot detect args in (*args, *kwargs) assert_is_type(10000000, I(int, lambda port: 1 <= port <= 65535)) assert False, "Failed to throw an exception" except H2OTypeError as e: assert "integer & 1 <= port <= 65535" in str(e), "Bad error message: '%s'" % e url_regex = r"^(https?)://((?:[\w-]+\.)*[\w-]+):(\d+)/?$" assert_matches("Hello, world!", r"^(\w+), (\w*)!$") assert_matches("http://127.0.0.1:3233/", url_regex) m = assert_matches("https://localhost:54321", url_regex) assert m.group(1) == "https" assert m.group(2) == "localhost" assert m.group(3) == "54321" x = 5 assert_satisfies(x, x < 1000) assert_satisfies(x, x ** x > 1000) assert_satisfies(url_regex, url_regex.lower() == url_regex) try: assert_satisfies(url_regex, url_regex.upper() == url_regex) except H2OValueError as e: assert "url_regex.upper() == url_regex" in str(e), "Error message is bad: " + str(e) try: import pandas import numpy assert_is_type(pandas.DataFrame(), pandas_dataframe) assert_is_type(numpy.ndarray(shape=(5,)), numpy_ndarray) except ImportError: pass
def _std_coef_plot(self, num_of_features=None, server=False, save_plot_path=None): """ Plot a GLM model"s standardized coefficient magnitudes. :param num_of_features: the number of features shown in the plot. :param server: if true set server settings to matplotlib and show the graph :param save_plot_path: a path to save the plot via using matplotlib function savefig :returns: object that contains the resulting figure (can be accessed using result.figure()) """ assert_is_type(num_of_features, None, I(int, lambda x: x > 0)) plt = get_matplotlib_pyplot(server) if not plt: return decorate_plot_result(figure=RAISE_ON_FIGURE_ACCESS) # get unsorted tuple of labels and coefficients unsorted_norm_coef = self.coef_norm().items() # drop intercept value then sort tuples by the coefficient"s absolute value drop_intercept = [ tup for tup in unsorted_norm_coef if tup[0] != "Intercept" ] norm_coef = sorted(drop_intercept, key=lambda x: abs(x[1]), reverse=True) signage = [] for element in norm_coef: # if positive including zero, color blue, else color orange (use same colors as Flow) if element[1] >= 0: signage.append("#1F77B4") # blue else: signage.append("#FF7F0E") # dark orange # get feature labels and their corresponding magnitudes feature_labels = [tup[0] for tup in norm_coef] norm_coef_magn = [abs(tup[1]) for tup in norm_coef] # specify bar centers on the y axis, but flip the order so largest bar appears at top pos = range(len(feature_labels))[::-1] # specify the bar lengths val = norm_coef_magn # check number of features, default is all the features if num_of_features is None: num_of_features = len(val) # plot horizontal plot fig, ax = plt.subplots(1, 1, figsize=(14, 10)) # create separate plot for the case where num_of_features = 1 if num_of_features == 1: plt.barh(pos[0], val[0], align="center", height=0.8, color=signage[0], edgecolor="none") # Hide the right and top spines, color others grey ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["bottom"].set_color("#7B7B7B") ax.spines["left"].set_color("#7B7B7B") # Only show ticks on the left and bottom spines ax.yaxis.set_ticks_position("left") ax.xaxis.set_ticks_position("bottom") plt.yticks([0], feature_labels[0]) ax.margins(None, 0.5) else: plt.barh(pos[0:num_of_features], val[0:num_of_features], align="center", height=0.8, color=signage[0:num_of_features], edgecolor="none") # Hide the right and top spines, color others grey ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["bottom"].set_color("#7B7B7B") ax.spines["left"].set_color("#7B7B7B") # Only show ticks on the left and bottom spines ax.yaxis.set_ticks_position("left") ax.xaxis.set_ticks_position("bottom") plt.yticks(pos[0:num_of_features], feature_labels[0:num_of_features]) ax.margins(None, 0.05) # generate custom fake lines that will be used as legend entries: # check if positive and negative values exist # if positive create positive legend if "#1F77B4" in signage[0:num_of_features] and "#FF7F0E" not in signage[ 0:num_of_features]: color_ids = ("Positive", ) markers = [ plt.Line2D([0, 0], [0, 0], color=color, marker="s", linestyle="", markersize=10) for color in set(signage[0:num_of_features]) ] plt.legend(markers, color_ids, numpoints=1, loc="best", frameon=False, fontsize=13) # if neg create neg legend elif "#FF7F0E" in signage[ 0:num_of_features] and "#1F77B4" not in signage[ 0:num_of_features]: color_ids = ("Negative", ) markers = [ plt.Line2D([0, 0], [0, 0], color=color, marker="s", linestyle="", markersize=10) for color in set(signage[0:num_of_features]) ] plt.legend(markers, color_ids, numpoints=1, loc="best", frameon=False, fontsize=13) # if both provide both colors in legend else: color_ids = ("Positive", "Negative") markers = [ plt.Line2D([0, 0], [0, 0], color=color, marker="s", linestyle="", markersize=10) for color in ['#1F77B4', '#FF7F0E'] ] # blue should always be positive, orange negative plt.legend(markers, color_ids, numpoints=1, loc="best", frameon=False, fontsize=13) # Hide the right and top spines, color others grey ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["bottom"].set_color("#7B7B7B") ax.spines["left"].set_color("#7B7B7B") # Only show ticks on the left and bottom spines plt.yticks(pos[0:num_of_features], feature_labels[0:num_of_features]) plt.tick_params(axis="x", which="minor", bottom="off", top="off", labelbottom="off") plt.title("Standardized Coef. Magnitudes: H2O GLM", fontsize=20) if save_plot_path is not None: plt.savefig(fname=save_plot_path) # show plot if server: plt.show() return decorate_plot_result(figure=fig)