kyoslib_py 4.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kyoslib_py/__init__.py ADDED
File without changes
@@ -0,0 +1,192 @@
1
+ import os
2
+
3
+ import pandas as pd
4
+
5
+ from kyoslib_py.kyos_api import call_kyos_api_v1
6
+
7
+
8
+ def write_curve_to_csv(curves, delTypes, grID, fullFileName):
9
+ """Stores the forward curves in generalized data format on the disk in ./ForwardCurves directory
10
+
11
+ Args:
12
+ curves (dict): HTTP response body which provided by kyos_api.call_kyos_api_v1
13
+ delTypes (list): baseload:1, peak:2, offpeak:3
14
+ grID (int): granularity id of the requested forward curve(e.g. half-hour:1, hour:2, day:3, month:5)
15
+ fullFileName (str): full path of the file(e.g. "./ForwardCurves/ForwardCurveDaily_2_20200101")
16
+
17
+ Note:
18
+ The current implementation allows to store only data based on monthly granularity.
19
+
20
+ Example:
21
+ >>> from kyoslib_py.forward_curve import write_curve_to_csv
22
+ >>> curves = {}
23
+ >>> data = {}
24
+ >>> month = {}
25
+ >>> baseload = [{'date':'2020-01-01', 'value':20.2}, {'date':'2020-02-01', 'value':30.3}]
26
+ >>> month['baseload'] = baseload
27
+ >>> data['month'] = month
28
+ >>> curves['data'] = data
29
+ >>> write_curve_to_csv(curves, [1, 2, 3], 5, "./ForwardCurves/ForwardCurveMonthlyDeliveryTypes_2_20200101")
30
+ """
31
+
32
+ if grID == 1: # half-hourly
33
+ return
34
+ elif grID == 2: # hourly
35
+ return
36
+ elif grID == 3: # daily
37
+ return
38
+ elif grID == 5: # monthly
39
+ curves_df = pd.DataFrame()
40
+ numDelType = len(delTypes)
41
+ # read dates from base load and store in the table, column name should be "0" for the date column
42
+ curves_df['0'] = [x['date'] for x in curves['data']['month']['baseload']]
43
+
44
+ for i in range(numDelType):
45
+
46
+ if delTypes[i] == 1:
47
+ curves_df[str(delTypes[i])] = [
48
+ x['value'] for x in curves['data']['month']['baseload']
49
+ ]
50
+ elif delTypes[i] == 2:
51
+ curves_df[str(delTypes[i])] = [
52
+ x['value'] for x in curves['data']['month']['peakload']
53
+ ]
54
+ elif delTypes[i] == 3:
55
+ curves_df[str(delTypes[i])] = [
56
+ x['value'] for x in curves['data']['month']['offpeak']
57
+ ]
58
+ # write monthly curves to csv
59
+ curves_df.to_csv(fullFileName, index=False)
60
+ return
61
+
62
+
63
+ def get_curve_api(fwdCurveID, granularityID, deliveryTypes, tradingDates, isCSVWrite):
64
+ """Performs API requests to KYOS API and stores the curve inputs in a generalized format in CSV files or
65
+ returns a pandas.DataFrame
66
+
67
+ Args:
68
+ fwdCurveID (int): id of the curve profile
69
+ granularityID (int): half-hour:1, hour:2, day:3, month:5
70
+ deliveryTypes (list or int): list of delivery type ids(int array), base load:1, peak:2, off-peak:3
71
+ tradingDates (list): list of trading dates(string array) e.g. ['2019-01-01', '2019-01-02', '2019-01-03']
72
+ isCSVWrite (bool): indicator of creating csv files, 0 or 1, we will provide a DataFrame in case of zero.
73
+
74
+ Returns:
75
+ (pandas.DataFrame): Contains all requested curves. If isCSVWrite equals 1 then the dataframe will be empty and
76
+ the curves will be saved as CSV files on the disk in directory ./ForwardCurves.
77
+
78
+ Note:
79
+ The current implementation allows to read only data based on monthly granularity.
80
+ KYOS API provides the curves with the daylight saving switches for the half-hourly and hourly curves.
81
+ KYOS API supports base load, peak and off-peak delivery types.
82
+
83
+ Example:
84
+ >>> from kyoslib_py.forward_curve import get_curve_api
85
+ >>> arg = {'fwdCurveID': 4, 'granularityID': 5, 'deliveryTypes': [1, 2, 3],
86
+ >>> 'tradingDates': ['2019-01-01', '2019-01-02'], 'isCSVWrite': 1}
87
+ >>> curves_df = get_curve_api(**arg)
88
+ >>> arg = {'fwdCurveID': 4, 'granularityID': 5, 'deliveryTypes': 1 ,
89
+ >>> 'tradingDates': '2019-01-01', 'isCSVWrite': 1}
90
+ >>> curves_df2 = get_curve_api(**arg)
91
+ """
92
+ # Initialize output directory
93
+ curDir = os.getcwd()
94
+ outputDir = os.path.join(curDir, 'ForwardCurves')
95
+ if isCSVWrite and (not os.path.exists(outputDir)):
96
+ os.mkdir(outputDir)
97
+ forward_curves_df = pd.DataFrame()
98
+ # ################################################# INPUT VALIDATION ###########################################
99
+ # Check the granularity input
100
+ if granularityID == 1:
101
+ fileName = f"ForwardCurveHalfHourlyDST_{fwdCurveID}_"
102
+ granularity = 'half_hour'
103
+ print('The function does not support reading of the ' + granularity + ' curves !!!')
104
+ return forward_curves_df
105
+ elif granularityID == 2:
106
+ fileName = f"ForwardCurveHourlyDST_{fwdCurveID}_"
107
+ granularity = 'hour'
108
+ print('The function does not support reading of the ' + granularity + ' curves !!!')
109
+ return forward_curves_df
110
+ elif granularityID == 3:
111
+ fileName = f"ForwardCurveDaily_{fwdCurveID}_"
112
+ granularity = 'day'
113
+ print('The function does not support reading of the ' + granularity + ' curves !!!')
114
+ return forward_curves_df
115
+ elif granularityID == 5:
116
+ fileName = f"ForwardCurveMonthlyDeliveryTypes_{fwdCurveID}_"
117
+ granularity = 'month'
118
+ else:
119
+ print('The granularity id:' + str(granularityID) + ' is not supported in KYOS API!!!')
120
+ return forward_curves_df
121
+ # in case of empty delivery type after the cleaning process, initialize base load in the list
122
+ if deliveryTypes is None:
123
+ deliveryTypes = [1]
124
+
125
+ # Check the delivery type input, deliveryTypes should be a list
126
+ if type(deliveryTypes) != list:
127
+ deliveryTypes = [deliveryTypes]
128
+ if len(deliveryTypes) == 0:
129
+ deliveryTypes.append(1) # in case of empty delivery type list, import the base load curve
130
+ else:
131
+ # remove the unsupported delivery types from the list
132
+ deliveryTypes = [
133
+ deliveryTypes for deliveryTypes in deliveryTypes if deliveryTypes in [1, 2, 3]
134
+ ]
135
+
136
+ # Check tradingDates, it should be provided as a list
137
+ if type(tradingDates) != list:
138
+ tradingDates = [tradingDates]
139
+
140
+ # ########################################### IMPORT CURVES #######################################################
141
+ numTradDays = tradingDates.__len__()
142
+ for i in range(numTradDays):
143
+ tradingDate_i = tradingDates[i]
144
+ query = f"/curves/results/{fwdCurveID}/{tradingDate_i}?filter[granularity]={granularity}"
145
+
146
+ status, data = call_kyos_api_v1(query)
147
+ if 200 >= status < 300:
148
+ print(query + ' Imported!')
149
+ if isCSVWrite == 1: # in this case, we will store the curves on disk per trading dates
150
+ fullName = os.path.join(
151
+ outputDir, f"{fileName}{tradingDate_i.replace('-', '')}.csv"
152
+ )
153
+ write_curve_to_csv(data, deliveryTypes, granularityID, fullName)
154
+ else: # in this case, we will store the curves in a dataframe
155
+ if granularityID == 1: # half-hourly
156
+ return
157
+ elif granularityID == 2: # hourly
158
+ return
159
+ elif granularityID == 3: # daily
160
+ return
161
+ elif granularityID == 5: # monthly
162
+ curves_df_i = pd.DataFrame()
163
+ numDelType = len(deliveryTypes)
164
+ # update curve id and trading dates column
165
+ numMonths = data['data']['month']['baseload'].__len__()
166
+ curves_df_i['curve_id'] = [fwdCurveID for _ in range(numMonths)]
167
+ curves_df_i['trading_dates'] = [tradingDate_i for _ in range(numMonths)]
168
+
169
+ # read dates from base load and store in the table as delivery dates
170
+ curves_df_i['delivery_dates'] = [
171
+ x['date'] for x in data['data']['month']['baseload']
172
+ ]
173
+ for i in range(numDelType):
174
+
175
+ if deliveryTypes[i] == 1:
176
+ curves_df_i['baseload'] = [
177
+ x['value'] for x in data['data']['month']['baseload']
178
+ ]
179
+ elif deliveryTypes[i] == 2:
180
+ curves_df_i['peak'] = [
181
+ x['value'] for x in data['data']['month']['peakload']
182
+ ]
183
+ elif deliveryTypes[i] == 3:
184
+ curves_df_i['offpeak'] = [
185
+ x['value'] for x in data['data']['month']['offpeak']
186
+ ]
187
+
188
+ forward_curves_df = pd.concat([forward_curves_df, curves_df_i])
189
+ else:
190
+ print(query + ' could not be imported!')
191
+
192
+ return forward_curves_df
@@ -0,0 +1,397 @@
1
+ import csv
2
+ import json
3
+ import os
4
+
5
+ import numpy as np
6
+ import plotly.express as px
7
+ from plotly.io import write_json as plotly_write_json
8
+
9
+
10
+ class PlatformGraphs(object):
11
+ """Handle the mapping of plotly graphs to a format which can be displayed by the KYOS platform.
12
+ There can be at most one instance of this class (singleton design pattern)."""
13
+
14
+ _instance = None # keep instance reference
15
+
16
+ def __new__(cls):
17
+ if not cls._instance:
18
+ cls._instance = super(PlatformGraphs, cls).__new__(cls)
19
+ # initialize output directory for platform graphs
20
+ output_location = os.path.join(os.getcwd(), 'Output', 'PlatformDisplay')
21
+ if not os.path.exists(output_location):
22
+ os.makedirs(output_location)
23
+ cls._instance.output_location = output_location
24
+ return cls._instance
25
+
26
+ def save2disk(
27
+ self,
28
+ fig,
29
+ filename: str,
30
+ xanchor='left',
31
+ yanchor='bottom',
32
+ orientation='h',
33
+ x=0.1,
34
+ y=-0.075,
35
+ ):
36
+ """Save a plotly graph object in a json format and in a proper location on the KYOS servers.
37
+
38
+ Args:
39
+ fig (plotly.graph_objects): a fully built plotly figure
40
+ filename (str): under what filename should the graph be saved on the server's hard-disk.
41
+ Note that the filename plays a role in the order of displaying graphs in the fornt end.
42
+ xanchor (str) : (Optional) One of ( "auto" | "left" | "center" | "right" ) Sets the title's horizontal
43
+ alignment with respect to its x position. "left" means that the title starts at x. Default:"left"
44
+ yanchor (str) : (Optional) One of ( "auto" | "top" | "middle" | "bottom" ) Sets the title's vertical
45
+ alignment with respect to its y position. "top" means that the title's cap line is at y. Default:"bottom"
46
+ orientation (str) : (Optional) one of ( "v" | "h" ). Sets the orientation of the legend. Default:"h"
47
+ x (float): (Optional) number between or equal to -2 and 3 Sets the x position (in normalized coordinates)
48
+ of the legend. KYOS Platform Defaults to 0.1
49
+ y (float): (Optional) number between or equal to -2 and 3 Sets the y position (in normalized coordinates)
50
+ of the legend. KYOS Platform Defaults to -0.075
51
+ Example:
52
+ >>> graph_object = PlatformGraphs()
53
+ >>> fig = px.histogram()
54
+ >>> graph_object.save2disk(fig, filename="001_option_value")
55
+ """
56
+ # legend style same over the whole platform
57
+ # -> styling can be moved to a separate method
58
+ fig.update_layout(
59
+ legend={
60
+ 'xanchor': xanchor,
61
+ 'yanchor': yanchor,
62
+ 'orientation': orientation,
63
+ 'x': x,
64
+ 'y': y,
65
+ }
66
+ )
67
+ fig.update_layout(
68
+ plot_bgcolor="#FFF", # Sets background color to white
69
+ xaxis=dict(
70
+ linecolor="#BCCCDC", # Sets color of X-axis line
71
+ showgrid=False, # Removes X-axis grid lines
72
+ ),
73
+ yaxis=dict(
74
+ linecolor='gray',
75
+ showgrid=True, # Keep Y-axis grid lines
76
+ ),
77
+ )
78
+
79
+ full_path = os.path.join(self.output_location, filename + "_plotly.json")
80
+ plotly_write_json(fig, full_path)
81
+
82
+
83
+ def make_platform_table(
84
+ df, table_name, bold_row_name=True, bold_column_name=True, columns_names=None
85
+ ):
86
+ """Function which outputs a pandas dataframe in a format which can be displayed in the KYOS platform.
87
+
88
+ Args:
89
+ df (pandas.Dataframe): A single row index is allowed. Multiple column indexes are allowed.
90
+ bold_row_name (bool): Display the row name in bold font when showing it in the platform front-end
91
+ bold_column_name (bool): Display the column name in bold font when showing it in the platform front-end
92
+ columns_names (None|list): None: use the column names of the dataframe | list of list: user defined columns names (should include name for the row index as well)
93
+
94
+ Notes:
95
+ The data in the dataframe saved in a csv file in the desired format.
96
+
97
+ Example:
98
+ >>> make_platform_table(data_df, '001_Option_Value', bold_column_name=True)
99
+ """
100
+ current_dir = os.path.dirname(os.path.realpath('__file__'))
101
+ # create output directory
102
+ output_dir = os.path.join(current_dir, 'Output/PlatformDisplay/')
103
+ os.makedirs(output_dir, exist_ok=True)
104
+
105
+ values = df.values.tolist()
106
+
107
+ # attach row names to the values
108
+ # currently only a single row name index is supported
109
+ all_rows = df.index.values.tolist()
110
+ n_row_indx = len(all_rows)
111
+ for r in range(n_row_indx):
112
+ name = all_rows[r]
113
+ if bold_row_name == True and name != "":
114
+ # add a tag to display the column name as bold
115
+ name = "<b>" + name.replace('_', ' ') + "</b>"
116
+ values[r].insert(0, name)
117
+
118
+ # Generate columns names consistent with the platform display format
119
+ if columns_names == None:
120
+ all_columns = df.columns.values.tolist()
121
+ all_col_names = []
122
+ if type(all_columns[0]) == str:
123
+ n_col_indx = 1
124
+ else: # tuple of all column indexes' name
125
+ n_col_indx = len(all_columns[0])
126
+
127
+ for i in range(n_col_indx):
128
+ col_names = [""] # currently only a single row name indexation is supported
129
+ unique_name = None
130
+ for col in all_columns:
131
+ if n_col_indx == 1:
132
+ name = col # col is just a string name
133
+ else:
134
+ name = str(col[i]) # column is a tuple of string names
135
+
136
+ if unique_name is not None and name == unique_name:
137
+ # a dataframe outputs the same name for a column when we have multi-indexing
138
+ # to display properly in the platform we drop the repeating names
139
+ name = ""
140
+ else:
141
+ unique_name = name
142
+
143
+ if bold_column_name == True and name != "":
144
+ # add a tag to display the column name as bold
145
+ name = "<b>" + name + "</b>"
146
+ col_names.append(name)
147
+ all_col_names.append(col_names)
148
+ else:
149
+ n_col_rows = len(columns_names[0])
150
+ all_col_names = []
151
+ for i in range(n_col_rows):
152
+ col_names = [x[i] for x in columns_names]
153
+ all_col_names.append(col_names)
154
+
155
+ with open(output_dir + table_name + ".csv", "w") as f:
156
+ writer = csv.writer(f)
157
+ writer.writerows(all_col_names)
158
+ with open(output_dir + table_name + ".csv", "a") as f:
159
+ writer = csv.writer(f)
160
+ writer.writerows(values)
161
+
162
+
163
+ def make_platform_histogram(
164
+ values, values_names, n_bins='auto', title=' ', output_filename='name'
165
+ ):
166
+ """Build a histogram based on one or more value series. The histogram will be displayed dynamically in the
167
+ Kyos Analytical Platform.
168
+
169
+ Args:
170
+ values (numpy.ndarray): a histogram is built for each value series.
171
+ The min/max of the histogram buckets is based on the smallest/biggest element of all series.
172
+ [shape = (n_rows, n_series)]
173
+
174
+ values_names (list): a list of string names for each series.
175
+ [len = n_series]
176
+
177
+ n_bins (int): how many bins should be used in the histogram.
178
+
179
+ title (string): title of the histogram
180
+
181
+ output_filename (string): beginning of the name of the output json file. It can be used to order how graphs are
182
+ displayed in the platform. Graph with start of the name "001_" will be displayed first.
183
+
184
+
185
+ Note:
186
+ The histogram graph is build using the "Highcharts" package. For more info refer to [HighCharts](https://www.highcharts.com/demo/column-basic)
187
+
188
+ Example:
189
+ >>> make_platform_histogram(values=values, values_names=['Value'],
190
+ >>> title='Total Option Value (EUR)',
191
+ >>> n_bins=20, output_filename='001_option_value')
192
+ """
193
+ # find bin edges based on all value series.
194
+ bin_edges = np.histogram_bin_edges(values, bins=n_bins, range=None, weights=None)
195
+ bin_means = list()
196
+ for b in range(len(bin_edges[:-1])):
197
+ bin_means.append((bin_edges[b] + bin_edges[b + 1]) / 2)
198
+
199
+ # find the frequency histogram per a single series
200
+ series = []
201
+ n_series = values.shape[1]
202
+ for i in range(n_series):
203
+ hist, bin_edges_out = np.histogram(values[:, i], bins=bin_edges)
204
+ hist_frequency = hist / hist.sum() * 100
205
+ hist_frequency = hist_frequency.tolist()
206
+ series.append({'name': values_names[i], 'data': hist_frequency})
207
+
208
+ y_label = 'Frequency'
209
+ column_chart = {
210
+ 'chart': {'type': 'column'},
211
+ 'title': {'text': title},
212
+ 'subtitle': {'text': ' '},
213
+ 'xAxis': {
214
+ 'labels': {'format': '{value:,.0f}'},
215
+ 'categories': bin_means,
216
+ 'crosshair': 'true',
217
+ },
218
+ 'yAxis': {
219
+ 'labels': {'format': '{value} %'},
220
+ 'min': 0,
221
+ 'title': {
222
+ 'text': y_label,
223
+ },
224
+ },
225
+ 'tooltip': {
226
+ 'headerFormat': ' ',
227
+ 'pointFormat': '<p><span style="color:{series.color}">&#x25cf;</span> <b>{series.name}: </b>{point.y:.1f} %</p>',
228
+ 'shared': 'true',
229
+ 'useHTML': 'true',
230
+ },
231
+ 'credits': {'text': 'Kyos Energy Consulting', 'href': 'http://www.kyos.com'},
232
+ 'plotOptions': {'column': {'pointPadding': 0, 'borderWidth': 0}},
233
+ 'series': series,
234
+ }
235
+ # output chart to json
236
+ with open('Output/PlatformDisplay/' + output_filename + '_chart.json', 'w') as outfile:
237
+ json.dump(column_chart, outfile)
238
+
239
+
240
+ def make_bar_column_chart(
241
+ values,
242
+ values_names,
243
+ is_stacked=False,
244
+ x_axis=None,
245
+ title=' ',
246
+ y_axis_title='values',
247
+ output_filename='name',
248
+ unit_name='unit',
249
+ ):
250
+ """Build a bar column chart based on one or more value series. The chart will be displayed dynamically in the
251
+ Kyos Analytical Platform.
252
+
253
+ Args:
254
+ values (numpy.ndarray): y axis values
255
+ [shape = (n_rows, n_series)]
256
+
257
+ values_names (list): a list of string names for each series.
258
+ [len = n_series]
259
+
260
+ is_stacked (bool): indicator for chart type. basic column and stacked column chart supported
261
+ False: Basic column chart
262
+ True: Stacked column chart
263
+ x_axis (None|list): list of x-axis values
264
+ None: integer values will be used [1,2,3 .......]
265
+ list: user defined x axis names (e.g. dates)
266
+
267
+ title (string): title of the chart
268
+
269
+ y_axis_title (string): title of the y-axis
270
+
271
+ output_filename (string): beginning of the name of the output json file. It can be used to order how graphs are
272
+ displayed in the platform. Graph with start of the name "001_" will be displayed first.
273
+
274
+ unit_name (string): unit name of the values
275
+
276
+ Note:
277
+ The histogram graph is build using the "Highcharts" package. For more info refer to
278
+ [HighCharts](https://www.highcharts.com/demo/column-basic)
279
+
280
+ Example:
281
+ >>> make_bar_column_chart(values=np.zeros((2,2)), values_names=['series_1', 'series_2'],is_stacked=True,
282
+ >>> x_axis=['2019-01-01', '2019-01-02'], title='Daily Positions', y_axis_title='Positions',
283
+ >>> output_filename='001_option_value', unit_name='Lots')
284
+ """
285
+
286
+ if x_axis is None:
287
+ x_axis = []
288
+ y_axis_title = y_axis_title + ' (' + unit_name + ')'
289
+ # Check chart type and create plot options
290
+ plot_options = {}
291
+ if is_stacked:
292
+ plot_options = {'column': {'stacking': 'normal'}}
293
+ # covert series to list
294
+ series = []
295
+ n_series = values.shape[1]
296
+ for i in range(n_series):
297
+ series_i = values[:, i].tolist()
298
+ series.append({'name': values_names[i], 'data': series_i})
299
+
300
+ bar_chart = {
301
+ 'chart': {'type': 'column'},
302
+ 'title': {'text': title},
303
+ 'xAxis': {'categories': x_axis},
304
+ 'yAxis': {'min': 0, 'title': {'text': y_axis_title}},
305
+ 'tooltip': {
306
+ 'headerFormat': '<span style="font-size:10px">{point.key}</span><table>',
307
+ 'pointFormat': '<tr><td style="color:{series.color};padding:0">{series.name}: </td>'
308
+ + '<td style="padding:0"><b>{point.y:.1f} '
309
+ + unit_name
310
+ + '</b></td></tr>',
311
+ 'footerFormat': '</table>',
312
+ 'shared': 'true',
313
+ 'useHTML': 'true',
314
+ },
315
+ 'credits': {'text': 'Kyos Energy Consulting', 'href': 'http://www.kyos.com'},
316
+ 'plotOptions': plot_options,
317
+ 'series': series,
318
+ }
319
+
320
+ # output chart to json
321
+ with open('Output/PlatformDisplay/' + output_filename + '_chart.json', 'w') as outfile:
322
+ json.dump(bar_chart, outfile)
323
+
324
+
325
+ def make_basic_line_chart(
326
+ values,
327
+ values_names,
328
+ x_axis=None,
329
+ title=' ',
330
+ y_axis_title='values',
331
+ output_filename='name',
332
+ unit_name='unit',
333
+ ):
334
+ """Build a bar column chart based on one or more value series. The chart will be displayed dynamically in the
335
+ Kyos Analytical Platform.
336
+
337
+ Args:
338
+ values (numpy.ndarray): y axis values
339
+ [shape = (n_rows, n_series)]
340
+
341
+ values_names (list): a list of string names for each series.
342
+ [len = n_series]
343
+
344
+ x_axis (None|list): list of x-axis values
345
+ None: integer values will be used [1,2,3 .......]
346
+ list: user defined x axis names (e.g. dates)
347
+
348
+ title (string): title of the chart
349
+
350
+ y_axis_title (string): title of the y-axis
351
+
352
+ output_filename (string): beginning of the name of the output json file. It can be used to order how graphs are
353
+ displayed in the platform. Graph with start of the name "001_" will be displayed first.
354
+
355
+ unit_name (string): unit name of the values
356
+
357
+ Note:
358
+ The histogram graph is build using the "Highcharts" package. For more info refer to
359
+ [HighCharts](https://www.highcharts.com/demo/column-basic)
360
+
361
+ Example:
362
+ >>> make_basic_line_chart(values=np.zeros((2,2)), values_names=['series_1', 'series_2'],
363
+ >>> x_axis=['2019-01-01', '2019-01-02'], title='Daily Positions', y_axis_title=' ',
364
+ >>> output_filename='001_option_value', unit_name='Lots')
365
+ """
366
+
367
+ if x_axis is None:
368
+ x_axis = []
369
+ y_axis_title = y_axis_title + ' (' + unit_name + ')'
370
+ # covert series to list
371
+ series = []
372
+ n_series = values.shape[1]
373
+ for i in range(n_series):
374
+ series_i = values[:, i].tolist()
375
+ series.append({'name': values_names[i], 'data': series_i})
376
+
377
+ line_chart = {
378
+ 'title': {'text': title},
379
+ 'xAxis': {'categories': x_axis},
380
+ 'yAxis': {'title': {'text': y_axis_title}},
381
+ 'tooltip': {
382
+ 'headerFormat': '<span style="font-size:10px">{point.key}</span><table>',
383
+ 'pointFormat': '<tr><td style="color:{series.color};padding:0">{series.name}: </td>'
384
+ + '<td style="padding:0"><b>{point.y:.1f} '
385
+ + unit_name
386
+ + '</b></td></tr>',
387
+ 'footerFormat': '</table>',
388
+ 'shared': 'true',
389
+ 'useHTML': 'true',
390
+ },
391
+ 'credits': {'text': 'Kyos Energy Consulting', 'href': 'http://www.kyos.com'},
392
+ 'series': series,
393
+ }
394
+
395
+ # output chart to json
396
+ with open('Output/PlatformDisplay/' + output_filename + '_chart.json', 'w') as outfile:
397
+ json.dump(line_chart, outfile)