Source code for schrodinger.application.desmond.gchart

"""
Tools for using google chart.

Copyright Schrodinger, LLC. All rights reserved.

"""

# Contributors: Yujie Wu

from past.utils import old_div

SIMPLE_ENCODING_RESOLUTION = 62
SIMPLE_ENCODING_RANGE = (0, SIMPLE_ENCODING_RESOLUTION - 1)
SIMPLE_ENCODING_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
SIMPLE_CODE = []
for c in SIMPLE_ENCODING_CHAR:
    SIMPLE_CODE.append(c)

EXTENDED_ENCODING_RESOLUTION = 4096
EXTENDED_ENCODING_RANGE = (0, EXTENDED_ENCODING_RESOLUTION - 1)
EXTENDED_ENCODING_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-"
EXTENDED_CODE = []
for c in EXTENDED_ENCODING_CHAR:
    for d in EXTENDED_ENCODING_CHAR:
        EXTENDED_CODE.append(c + d)

# Color code: RRGGBBTT. Examples:
#
#    FF0000 = Red
#    00FF00 = Green
#    0000FF = Blue
#    000000 = Black
#    FFFFFF = White
#
# TT is an optional field, indicating the transparency. Value 00 is completely transparent, and FF is completely opaque.
#
#    0000FFFF = Solid blue
#    0000FF66 = Transparent blue
COLOR_CODE = [
    "000000",
    "FF0000",
    "00FF00",
    "0000FF",
    "800080",
    "FFFF00",
    "FFA500",
    "FF00FF",
    "87CEEB",
    "FFD700",
    "C0C0C0",
]
COLOR_NAME = [
    "black",
    "red",
    "green",
    "blue",
    "purple",
    "yellow",
    "orange",
    "violet",
    "skyblue",
    "gold",
    "grey",
]

URL_CHAR_MAP = {
    "$": "%24",
    "&": "%26",
    "+": "%2B",
    ",": "%2C",
    "/": "%2F",
    ":": "%3A",
    ";": "%3B",
    "=": "%3D",
    "?": "%3F",
    "@": "%40",
    "|": "%7C",
    " ": "+",
    "\n": "|",
    "#": "%23",
    "%": "%25",
}


[docs]def urlencode(s): """ """ ret = "" n = len(s) for i in range(n): if (s[i] < " " and s[i] != "\n"): continue if (s[i] in URL_CHAR_MAP): ret += URL_CHAR_MAP[s[i]] else: ret += s[i] return ret
[docs]def encode_simple(values): """ """ ret = "" for v in values: if (v is None or v < 0): ret += "_" else: ret += SIMPLE_CODE[int(v)] return ret
[docs]def encode_extended(values): """ """ ret = "" for v in values: if (v is None or v < 0): ret += "__" else: ret += EXTENDED_CODE[int(v)] return ret
[docs]def compile_xy(x, *y, **kw): """ """ encoding_scheme = kw["encoding_scheme"] if ("encoding_scheme" in kw) else "simple" shown_data = kw["shown_data"] if ("shown_data" in kw) else -1 show_x = kw["show_x"] if ("show_x" in kw) else False x_min, x_max = kw["x_range"] if ("x_range" in kw) else ( min(x), max(x), ) y_min, y_max = kw["y_range"] if ("y_range" in kw) else ( min([min(e) for e in y]), max([max(e) for e in y]), ) x_span = x_max - x_min y_span = y_max - y_min plot_x_min = x_min - x_span * 0.0 plot_x_max = x_max + x_span * 0.1 plot_x_span = plot_x_max - plot_x_min plot_y_min = y_min - y_span * 0.0 plot_y_max = y_max + y_span * 0.1 plot_y_span = plot_y_max - plot_y_min resolution = EXTENDED_ENCODING_RESOLUTION if ( encoding_scheme == "extended") else SIMPLE_ENCODING_RESOLUTION x_delta = old_div(plot_x_span, resolution) y_delta = old_div(plot_y_span, resolution) if (show_x): x_ = [] for e in x: x_.append(int(old_div((e - plot_x_min), x_delta))) data = [] for this_y in y: d = [] for e in this_y: d.append(int(old_div((e - plot_y_min), y_delta))) data.append(d) num_data = len(x_) if (show_x) else 0 for d in data: num_data += len(d) if (num_data > 1792): # Too many data. We have to shrink the amount of data. sample_rate = old_div(num_data, 1792.0) new_data = [] for d in data: new_d = [] num_d = len(d) i = 0 while (i < num_d): new_d.append(d[int(i)]) i += sample_rate new_data.append(new_d) data = new_data if (show_x): new_x_ = [] num_x_ = len(x_) i = 0 while (i < num_x_): new_x_.append(x_[int(i)]) i += sample_rate x_ = new_x_ if (encoding_scheme == "extended"): s = "chd=e:" if (shown_data < 0) else "chd=e%d:" % ( (shown_data + 1) if (show_x) else shown_data) if (show_x): s += encode_extended(x_) + "," for d in data: s += encode_extended(d) + "," else: s = "chd=s:" if (shown_data < 0) else "chd=s%d:" % ( (shown_data + 1) if (show_x) else shown_data) if (show_x): s += encode_simple(x_) + "," for d in data: s += encode_simple(d) + "," return x_min, x_max, plot_y_min, plot_y_max, s[0:-1]
MARKER_SYMBOL = None
[docs]def get_xy_url(x, *y, **kw): """ """ chart_type = "lc" if ("chart_type" in kw): if (kw["chart_type"] == "scatter"): url = "http://chart.apis.google.com/chart?cht=s&" chart_type = "s" global MARKER_SYMBOL if (MARKER_SYMBOL is None): MARKER_SYMBOL = { "arrow": "a", "cross": "c", "rectangle": "C", "diamond": "d", "circle": "o", "square": "s", "x": "x", } if ("marker" in kw): symbol, color, size = kw["marker"] j = COLOR_NAME.index(color) color = COLOR_CODE[j] url += "chm=%s,%s,0,-1,%d&" % ( MARKER_SYMBOL[symbol], color, size, ) elif (kw["chart_type"] == "line"): url = "http://chart.apis.google.com/chart?cht=lc&" else: raise ValueError("Unsupported chart type: %s" % kw["chart_type"]) else: url = "http://chart.apis.google.com/chart?cht=lc&" num_y = len(y) err_y = kw["err_y"] if ("err_y" in kw) else [] if (err_y): new_err_y = [] err_top = [] err_bot = [] for this_y, this_err_y in zip(y, err_y): for e, f in zip(this_y, this_err_y): err_top.append(e + f) err_bot.append(e - f) new_err_y += [ err_top, err_bot, ] err_y = new_err_y y += tuple(err_y) if (chart_type == "s"): y_ = y y = [] for e in y_: y += e x_min, x_max, y_min, y_max, dat_str = compile_xy(x, *[ y, ], show_x=True, **kw) else: kw["shown_data"] = num_y x_min, x_max, y_min, y_max, dat_str = compile_xy(x, *y, **kw) size = kw["size"] if ("size" in kw) else ( 300, 200, ) url += "chs=%dx%d&" % tuple(size) x_label = None y_label = None url += "chxt=x,y" if ("x_label" in kw): url += ",x" x_label = urlencode(kw["x_label"]) if ("y_label" in kw): url += ",y" y_label = urlencode(kw["y_label"]) url += "&" if (x_label and y_label): url += "chxl=2:|%s|3:|%s&chxp=2,50|3,50&" % ( x_label, y_label, ) elif (x_label): url += "chxl=2:|%s&chxp=2,50&" % x_label elif (y_label): url += "chxl=2:|%s&chxp=2,50&" % y_label x_min, x_max = kw["x_range"] if ("x_range" in kw) else ( x_min, x_max, ) y_min, y_max = kw["y_range"] if ("y_range" in kw) else ( y_min, y_max, ) axis_range = "chxr=0,%.4g,%.4g|1,%.4g,%.4g&" % ( x_min, x_max, y_min, y_max, ) axis_range = axis_range.replace("e+0", "e") axis_range = axis_range.replace("e+", "e") url += axis_range if (chart_type == "lc" or "color" in kw): color = kw["color"] if ("color" in kw) else COLOR_CODE color_used = [] num_color = len(color) url += "chco=" for i in range(num_y): c = color[i % num_color] if (c in COLOR_NAME): j = COLOR_NAME.index(c) c = COLOR_CODE[j] url += "%s," % c color_used.append(c) url = url[0:-1] + "&" # Compiles error bars. err_series_index = num_y if (err_y): url += "chm=E," for i in range(old_div(len(err_y), 2)): url += "%s,%d,,1:5" % ( color_used[i], err_series_index, ) err_series_index += 2 url += "&" if ("bg" in kw): c = kw["bg"] if (c in COLOR_NAME): j = COLOR_NAME.index(c) c = COLOR_CODE[j] url += "chf=bg,s,%s&" % c if ("legend" in kw and kw["legend"] is not None): legend = kw["legend"] url += "chdl=" for e in legend: url += "%s|" % urlencode(e) url = url[0:-1] + "&" if ("title" in kw): url += "chtt=%s&" % urlencode(kw["title"]) url += dat_str return url
if ("__main__" == __name__): import os import sys argc = len(sys.argv) if (1 == argc): print( "Usage: $SCHRODINGER/run %s <data-file> [x_label [y_label [title [y_range]]]]" % sys.argv[0]) sys.exit(0) if (not os.path.isfile(sys.argv[1])): print("Data file not found: %s" % sys.argv[1]) sys.exit(0) try: x_label = sys.argv[2] except IndexError: x_label = "" try: y_label = sys.argv[3] except IndexError: y_label = "" try: title = sys.argv[4] except IndexError: title = "" try: y_range = sys.argv[5] y_range = [float(e) for e in y_range.split()] except IndexError: y_range = () lines = open(sys.argv[1], "r").read().split("\n") x = [] y = [] y_err = [] for line in lines: line = line.strip() if (line != "" and line[0] != "#"): token = line.split() x.append(float(token[0])) y.append(float(token[1])) try: y_err.append(float(token[2])) except IndexError: pass if (y_err): if (y_range): url = get_xy_url(x, y, err_y=[y_err], x_label=x_label, y_label=y_label, title=title, y_range=y_range) else: url = get_xy_url(x, y, err_y=[y_err], x_label=x_label, y_label=y_label, title=title) else: if (y_range): url = get_xy_url(x, y, x_label=x_label, y_label=y_label, title=title, y_range=y_range) else: url = get_xy_url(x, y, x_label=x_label, y_label=y_label, title=title) print("number of chars in the url:", len(url)) print(url) import schrodinger.application.desmond.util as util print(util.html_embed_image(url))