"""
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))