Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 53 additions & 70 deletions highcharts/highstock/highstock.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

from jinja2 import Environment, PackageLoader

import json, uuid
import json
import uuid
import re
import datetime
import html
Expand All @@ -31,7 +32,7 @@

template_content = jinja2_env.get_template(CONTENT_FILENAME)
template_page = jinja2_env.get_template(PAGE_FILENAME)


class Highstock(object):
"""
Expand Down Expand Up @@ -59,20 +60,20 @@ def __init__(self, **kwargs):
# an Instance of Jinja2 template
self.template_page_highcharts = template_page
self.template_content_highcharts = template_content

# set Javascript src, Highcharts lib needs to make sure it's up to date
self.JSsource = [
'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js',
'https://code.highcharts.com/stock/highstock.js',
'https://code.highcharts.com/stock/modules/exporting.js',
'https://code.highcharts.com/highcharts-more.js',
]
'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js',
'https://code.highcharts.com/stock/highstock.js',
'https://code.highcharts.com/stock/modules/exporting.js',
'https://code.highcharts.com/highcharts-more.js',
]

# set CSS src
self.CSSsource = [
'https://www.highcharts.com/highslide/highslide.css',
'https://www.highcharts.com/highslide/highslide.css',

]
]
# set data
self.data = []
self.data_temp = []
Expand All @@ -84,8 +85,8 @@ def __init__(self, **kwargs):

# Data from jsonp
self.jsonp_data_flag = False
self.jsonp_data_url_list = [] # DEM 2017/04/25: List of JSON data sources
self.jsonp_data_url_list = [] # DEM 2017/04/25: List of JSON data sources

# javascript
self.jscript_head_flag = False
self.jscript_head = kwargs.get('jscript_head', None)
Expand Down Expand Up @@ -155,18 +156,16 @@ def __init__(self, **kwargs):

for keyword in allowed_kwargs:
if keyword in kwargs:
self.options['chart'].update_dict(**{keyword:kwargs[keyword]})
self.options['chart'].update_dict(**{keyword: kwargs[keyword]})
# Some Extra Vals to store:
self.data_set_count = 0
self.drilldown_data_set_count = 0


def __load_defaults__(self):
self.options["chart"].update_dict(renderTo='container')
self.options["title"].update_dict(text='A New Highchart')
self.options["credits"].update_dict(enabled=False)


def add_JSsource(self, new_src):
"""add additional js script source(s)"""
if isinstance(new_src, list):
Expand All @@ -177,7 +176,6 @@ def add_JSsource(self, new_src):
else:
raise OptionTypeError("Option: %s Not Allowed For Series Type: %s" % type(new_src))


def add_CSSsource(self, new_src):
"""add additional css source(s)"""
if isinstance(new_src, list):
Expand All @@ -188,60 +186,50 @@ def add_CSSsource(self, new_src):
else:
raise OptionTypeError("Option: %s Not Allowed For Series Type: %s" % type(new_src))


def add_data_set(self, data, series_type="line", name=None, **kwargs):
"""set data for series option in highstocks"""

self.data_set_count += 1
if not name:
name = "Series %d" % self.data_set_count
kwargs.update({'name':name})
kwargs.update({'name': name})

series_data = Series(data, series_type=series_type, **kwargs)
series_data.__options__().update(SeriesOptions(series_type=series_type, **kwargs).__options__())
self.data_temp.append(series_data)


def add_data_from_jsonp(self, data_src, data_name='json_data', series_type="line", name=None, **kwargs):
def add_data_from_jsonp(self, data_src, series_type="line", name=None, **kwargs):
"""set map data directly from a https source
the data_src is the https link for data
and it must be in jsonp format
"""
if not self.jsonp_data_flag:
self.jsonp_data_flag = True

if data_name == 'data':
data_name = 'json_'+ data_name

self.jsonp_data = data_name
self.add_data_set(RawJavaScriptText(self.jsonp_data), series_type, name=name, **kwargs)

self.add_data_set(None, series_type, name=name, **kwargs)
# DEM 2017/04/25: Append new JSON data source to a list instead of
# replacing whatever already exists
self.jsonp_data_url_list.append(json.dumps(data_src))


def add_navi_series(self, data, series_type="line", **kwargs):
"""set series for navigator option in highstocks"""

self.navi_seri_flag = True
series_data = Series(data, series_type=series_type, **kwargs)
series_data.__options__().update(SeriesOptions(series_type=series_type, **kwargs).__options__())
series_data.__options__().update(SeriesOptions(series_type=series_type, **kwargs).__options__())
self.navi_seri_temp = series_data

def add_navi_series_from_jsonp(self, data_src=None, data_name='json_data', series_type="line", **kwargs):
"""set series for navigator option in highstocks"""

if not self.jsonp_data_flag:
self.jsonp_data_flag = True
self.jsonp_data_url = json.dumps(data_src)
self.jsonp_data_url = json.dumps(data_src)

if data_name == 'data':
data_name = 'json_'+ data_name

self.jsonp_data = data_name

self.add_navi_series(RawJavaScriptText(self.jsonp_data), series_type, **kwargs)
data_name = 'json_' + data_name

self.add_navi_series(RawJavaScriptText(self.jsonp_data), series_type, **kwargs)

def add_JSscript(self, js_script, js_loc):
"""add (highcharts) javascript in the beginning or at the end of script
Expand All @@ -250,19 +238,18 @@ def add_JSscript(self, js_script, js_loc):
if js_loc == 'head':
self.jscript_head_flag = True
if self.jscript_head:
self.jscript_head = self.jscript_head + '\n' + js_script
self.jscript_head = self.jscript_head + '\n' + js_script
else:
self.jscript_head = js_script
elif js_loc == 'end':
self.jscript_end_flag = True
if self.jscript_end:
self.jscript_end = self.jscript_end + '\n' + js_script
self.jscript_end = self.jscript_end + '\n' + js_script
else:
self.jscript_end = js_script
else:
raise OptionTypeError("Not An Accepted script location: %s, either 'head' or 'end'"
% js_loc)

raise OptionTypeError("Not An Accepted script location: %s, either 'head' or 'end'"
% js_loc)

def set_options(self, option_type, option_dict, force_options=False):
"""set plot options """
Expand All @@ -274,13 +261,12 @@ def set_options(self, option_type, option_dict, force_options=False):
for each_dict in option_dict:
self.options[option_type].update(**each_dict)
elif option_type == 'colors':
self.options["colors"].set_colors(option_dict) # option_dict should be a list
elif option_type in ["global" , "lang"]: #Highcharts.setOptions:
self.options["colors"].set_colors(option_dict) # option_dict should be a list
elif option_type in ["global", "lang"]: # Highcharts.setOptions:
self.setOptions[option_type].update_dict(**option_dict)
else:
self.options[option_type].update_dict(**option_dict)


def set_dict_options(self, options):
"""for dictionary-like inputs (as object in Javascript)
options must be in python dictionary format
Expand All @@ -289,27 +275,25 @@ def set_dict_options(self, options):
for key, option_data in options.items():
self.set_options(key, option_data)
else:
raise OptionTypeError("Not An Accepted Input Format: %s. Must be Dictionary" %type(options))

raise OptionTypeError("Not An Accepted Input Format: %s. Must be Dictionary" % type(options))

def buildcontent(self):
"""build HTML content only, no header or body tags"""

self.buildcontainer()
self.option = json.dumps(self.options, cls = HighchartsEncoder)
self.setoption = json.dumps(self.setOptions, cls = HighchartsEncoder)
self.data = json.dumps(self.data_temp, cls = HighchartsEncoder)
self.option = json.dumps(self.options, cls=HighchartsEncoder)
self.setoption = json.dumps(self.setOptions, cls=HighchartsEncoder)
self.data = json.dumps(self.data_temp, cls=HighchartsEncoder)

# DEM 2017/04/25: Make 'data' available as an array
# ... this permits jinja2 array access to each data definition
# ... which is useful for looping over multiple data sources
self.data_list = [json.dumps(x, cls = HighchartsEncoder) for x in self.data_temp]

if self.navi_seri_flag:
self.navi_seri = json.dumps(self.navi_seri_temp, cls = HighchartsEncoder)
self.data_list = [json.dumps(x, cls=HighchartsEncoder) for x in self.data_temp]

self._htmlcontent = self.template_content_highcharts.render(chart=self).encode('utf-8')
if self.navi_seri_flag:
self.navi_seri = json.dumps(self.navi_seri_temp, cls=HighchartsEncoder)

self._htmlcontent = self.template_content_highcharts.render(chart=self).encode('utf-8')

def buildhtml(self):
"""build the HTML page
Expand All @@ -318,10 +302,9 @@ def buildhtml(self):
"""
self.buildcontent()
self.buildhtmlheader()
self.content = self._htmlcontent.decode('utf-8') # need to ensure unicode
self.content = self._htmlcontent.decode('utf-8') # need to ensure unicode
self._htmlcontent = self.template_page_highcharts.render(chart=self)
return self._htmlcontent


def buildhtmlheader(self):
"""generate HTML header content"""
Expand All @@ -340,7 +323,6 @@ def buildhtmlheader(self):
for js in self.header_js:
self.htmlheader += js


def buildcontainer(self):
"""generate HTML div"""
if self.container:
Expand All @@ -357,7 +339,7 @@ def buildcontainer(self):
else:
self.div_style += 'height:%s;' % self.options['chart'].height

self.div_name = self.options['chart'].__dict__['renderTo'] # recheck div name
self.div_name = self.options['chart'].__dict__['renderTo'] # recheck div name
self.container = self.containerheader + \
'<div id="%s" style="%s">%s</div>\n' % (self.div_name, self.div_style, self.loading)

Expand All @@ -372,31 +354,32 @@ def iframe(self):
htmlsrcdoc = re.sub(' +', ' ', htmlsrcdoc)
width = int(self.options['chart'].__dict__['width']) if self.options['chart'].__dict__.get('width') else 820
height = int(self.options['chart'].__dict__['height']) if self.options['chart'].__dict__.get('height') else 520

if self.options['chart'].__dict__.get('options3d'):
if len(htmlsrcdoc) < 99965000 :
return '<iframe style="border:0;outline:none;overflow:hidden" src="data:text/html,'+ htmlsrcdoc + '" height=' + str(height) + \
' width=' + str(width) + '></iframe>'
if len(htmlsrcdoc) < 99965000:
return '<iframe style="border:0;outline:none;overflow:hidden" src="data:text/html,' + htmlsrcdoc + '" height=' + str(height) + \
' width=' + str(width) + '></iframe>'
else:
return '<iframe style="border:0;outline:none;overflow:hidden" srcdoc="'+ htmlsrcdoc + '" height='+ str(height) + ' width=' + str(width) + '></iframe>'
return '<iframe style="border:0;outline:none;overflow:hidden" srcdoc="' + htmlsrcdoc + '" height=' + str(height) + ' width=' + str(width) + '></iframe>'
else:
return '<iframe style="border:0;outline:none;overflow:hidden" srcdoc="'+ htmlsrcdoc + '" height='+ str(height) + ' width=' + str(width) + '></iframe>'
return '<iframe style="border:0;outline:none;overflow:hidden" srcdoc="' + htmlsrcdoc + '" height=' + str(height) + ' width=' + str(width) + '></iframe>'

def __str__(self):
"""return htmlcontent"""
#self.buildhtml()
return self.htmlcontent

def save_file(self, filename = 'StockChart'):
def save_file(self, filename='StockChart'):
""" save htmlcontent as .html file """
filename = filename + '.html'

with open(filename, 'w') as f:
#self.buildhtml()
f.write(self.htmlcontent)

f.closed


class HighchartsEncoder(json.JSONEncoder):
def __init__(self, *args, **kwargs):
json.JSONEncoder.__init__(self, *args, **kwargs)
Expand All @@ -410,12 +393,12 @@ def default(self, obj):
elif isinstance(obj, datetime.datetime):
utc = obj.utctimetuple()
obj = (u"Date.UTC({year},{month},{day},{hours},{minutes},{seconds},{millisec})"
.format(year=utc[0], month=utc[1]-1, day=utc[2], hours=utc[3],
minutes=utc[4], seconds=utc[5], millisec=obj.microsecond/1000))
.format(year=utc[0], month=utc[1] - 1, day=utc[2], hours=utc[3],
minutes=utc[4], seconds=utc[5], millisec=obj.microsecond / 1000))
return RawJavaScriptText(obj)
elif isinstance(obj, BaseOptions) or isinstance(obj, MultiAxis):
return obj.__jsonable__()
elif isinstance(obj, CSSObject) or isinstance(obj, Formatter) or isinstance(obj, JSfunction):
elif isinstance(obj, CSSObject) or isinstance(obj, Formatter) or isinstance(obj, JSfunction):
return obj.__jsonable__()
elif isinstance(obj, SeriesOptions) or isinstance(obj, Series):
return obj.__jsonable__()
Expand All @@ -433,5 +416,5 @@ def encode(self, obj):

class OptionTypeError(Exception):

def __init__(self,*args):
def __init__(self, *args):
self.args = args
6 changes: 4 additions & 2 deletions highcharts/highstock/templates/content.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@
{% if chart.jsonp_data_flag %}
{% for data_url in chart.jsonp_data_url_list %}

$.getJSON({{data_url}}, function ({{chart.jsonp_data}})
$.getJSON({{data_url}}, function (json)
{
chart.addSeries({{chart.data_list[loop.index0]}});
var data = {{chart.data}}[{{loop.index0}}];
data.data = json;
chart.addSeries(data);
});

{% endfor %}
Expand Down