Skip to content

Commit b2ae560

Browse files
committed
Refactor utility functions into "util.py"
1 parent 176bbdb commit b2ae560

File tree

2 files changed

+105
-100
lines changed

2 files changed

+105
-100
lines changed

grafana_pandas_datasource/service.py

Lines changed: 3 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
from flask import Flask, request, jsonify, abort
2525
from flask_cors import CORS, cross_origin
2626
import pandas as pd
27-
import numpy as np
27+
28+
from grafana_pandas_datasource.util import dataframe_to_response, dataframe_to_json_table, annotations_to_response
29+
2830

2931
app = Flask(__name__)
3032

@@ -87,105 +89,6 @@ def find_metrics():
8789
return jsonify(list(metric_finders[finder](target)))
8890

8991

90-
def dataframe_to_response(target, df, freq=None):
91-
response = []
92-
93-
if df.empty:
94-
return response
95-
96-
if freq is not None:
97-
orig_tz = df.index.tz
98-
df = df.tz_convert('UTC').resample(rule=freq, label='right', closed='right').mean().tz_convert(orig_tz)
99-
100-
if isinstance(df, pd.Series):
101-
response.append(_series_to_response(df, target))
102-
elif isinstance(df, pd.DataFrame):
103-
for col in df:
104-
response.append(_series_to_response(df[col], target))
105-
else:
106-
abort(404, Exception('Received object is not a dataframe or series.'))
107-
108-
return response
109-
110-
111-
def dataframe_to_json_table(target, df):
112-
response = []
113-
114-
if df.empty:
115-
return response
116-
117-
if isinstance(df, pd.DataFrame):
118-
response.append({'type': 'table',
119-
'columns': df.columns.map(lambda col: {"text": col}).tolist(),
120-
'rows': df.where(pd.notnull(df), None).values.tolist()})
121-
else:
122-
abort(404, Exception('Received object is not a dataframe.'))
123-
124-
return response
125-
126-
127-
def annotations_to_response(target, df):
128-
response = []
129-
130-
# Single series with DatetimeIndex and values as text
131-
if isinstance(df, pd.Series):
132-
for timestamp, value in df.iteritems():
133-
response.append({
134-
"annotation": target, # The original annotation sent from Grafana.
135-
"time": timestamp.value // 10 ** 6, # Time since UNIX Epoch in milliseconds. (required)
136-
"title": value, # The title for the annotation tooltip. (required)
137-
#"tags": tags, # Tags for the annotation. (optional)
138-
#"text": text # Text for the annotation. (optional)
139-
})
140-
# Dataframe with annotation text/tags for each entry
141-
elif isinstance(df, pd.DataFrame):
142-
for timestamp, row in df.iterrows():
143-
annotation = {
144-
"annotation": target, # The original annotation sent from Grafana.
145-
"time": timestamp.value // 10 ** 6, # Time since UNIX Epoch in milliseconds. (required)
146-
"title": row.get('title', ''), # The title for the annotation tooltip. (required)
147-
}
148-
149-
if 'text' in row:
150-
annotation['text'] = str(row.get('text'))
151-
if 'tags' in row:
152-
annotation['tags'] = str(row.get('tags'))
153-
154-
response.append(annotation)
155-
else:
156-
abort(404, Exception('Received object is not a dataframe or series.'))
157-
158-
return response
159-
160-
161-
def _series_to_annotations(df, target):
162-
if df.empty:
163-
return {'target': '%s' % (target),
164-
'datapoints': []}
165-
166-
sorted_df = df.dropna().sort_index()
167-
timestamps = (sorted_df.index.astype(pd.np.int64) // 10 ** 6).values.tolist()
168-
values = sorted_df.values.tolist()
169-
170-
return {'target': '%s' % (df.name),
171-
'datapoints': list(zip(values, timestamps))}
172-
173-
174-
def _series_to_response(df, target):
175-
if df.empty:
176-
return {'target': '%s' % (target),
177-
'datapoints': []}
178-
179-
sorted_df = df.dropna().sort_index()
180-
181-
timestamps = (sorted_df.index.astype(np.int64) // 10 ** 6).values.tolist()
182-
183-
values = sorted_df.values.tolist()
184-
185-
return {'target': '%s' % (df.name),
186-
'datapoints': list(zip(values, timestamps))}
187-
188-
18992
@app.route('/query', methods=methods)
19093
@cross_origin(max_age=600)
19194
def query_metrics():

grafana_pandas_datasource/util.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import numpy as np
2+
import pandas as pd
3+
from werkzeug.exceptions import abort
4+
5+
6+
def dataframe_to_response(target, df, freq=None):
7+
response = []
8+
9+
if df.empty:
10+
return response
11+
12+
if freq is not None:
13+
orig_tz = df.index.tz
14+
df = df.tz_convert('UTC').resample(rule=freq, label='right', closed='right').mean().tz_convert(orig_tz)
15+
16+
if isinstance(df, pd.Series):
17+
response.append(_series_to_response(df, target))
18+
elif isinstance(df, pd.DataFrame):
19+
for col in df:
20+
response.append(_series_to_response(df[col], target))
21+
else:
22+
abort(404, Exception('Received object is not a dataframe or series.'))
23+
24+
return response
25+
26+
27+
def dataframe_to_json_table(target, df):
28+
response = []
29+
30+
if df.empty:
31+
return response
32+
33+
if isinstance(df, pd.DataFrame):
34+
response.append({'type': 'table',
35+
'columns': df.columns.map(lambda col: {"text": col}).tolist(),
36+
'rows': df.where(pd.notnull(df), None).values.tolist()})
37+
else:
38+
abort(404, Exception('Received object is not a dataframe.'))
39+
40+
return response
41+
42+
43+
def annotations_to_response(target, df):
44+
response = []
45+
46+
# Single series with DatetimeIndex and values as text
47+
if isinstance(df, pd.Series):
48+
for timestamp, value in df.iteritems():
49+
response.append({
50+
"annotation": target, # The original annotation sent from Grafana.
51+
"time": timestamp.value // 10 ** 6, # Time since UNIX Epoch in milliseconds. (required)
52+
"title": value, # The title for the annotation tooltip. (required)
53+
#"tags": tags, # Tags for the annotation. (optional)
54+
#"text": text # Text for the annotation. (optional)
55+
})
56+
# Dataframe with annotation text/tags for each entry
57+
elif isinstance(df, pd.DataFrame):
58+
for timestamp, row in df.iterrows():
59+
annotation = {
60+
"annotation": target, # The original annotation sent from Grafana.
61+
"time": timestamp.value // 10 ** 6, # Time since UNIX Epoch in milliseconds. (required)
62+
"title": row.get('title', ''), # The title for the annotation tooltip. (required)
63+
}
64+
65+
if 'text' in row:
66+
annotation['text'] = str(row.get('text'))
67+
if 'tags' in row:
68+
annotation['tags'] = str(row.get('tags'))
69+
70+
response.append(annotation)
71+
else:
72+
abort(404, Exception('Received object is not a dataframe or series.'))
73+
74+
return response
75+
76+
77+
def _series_to_annotations(df, target):
78+
if df.empty:
79+
return {'target': '%s' % (target),
80+
'datapoints': []}
81+
82+
sorted_df = df.dropna().sort_index()
83+
timestamps = (sorted_df.index.astype(pd.np.int64) // 10 ** 6).values.tolist()
84+
values = sorted_df.values.tolist()
85+
86+
return {'target': '%s' % (df.name),
87+
'datapoints': list(zip(values, timestamps))}
88+
89+
90+
def _series_to_response(df, target):
91+
if df.empty:
92+
return {'target': '%s' % (target),
93+
'datapoints': []}
94+
95+
sorted_df = df.dropna().sort_index()
96+
97+
timestamps = (sorted_df.index.astype(np.int64) // 10 ** 6).values.tolist()
98+
99+
values = sorted_df.values.tolist()
100+
101+
return {'target': '%s' % (df.name),
102+
'datapoints': list(zip(values, timestamps))}

0 commit comments

Comments
 (0)