1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module for the plotting of data.
24
25 The numerical graph data handled in these functions consists of a 4 dimensional list or array object. The first dimension corresponds to different graphs. The second corresponds the different data sets within a single each graph. The third corresponds to the data series (i.e. each data point). The forth is a list of the information about each point, it is a list where the first element is the X value, the second is the Y value, the third is the optional dX or dY error, and the forth is the optional dY error when X errors are present (the third position is then dx).
26 """
27
28
29
30 from lib.errors import RelaxError
31 from pipe_control.mol_res_spin import spin_loop
32 from specific_analyses.api import return_api
33
34
35 -def assemble_data(spin_id=None, x_data_name=None, y_data_name=None, plot_data=None):
36 """Return all the xy data, along with the graph type and names for the graph sets.
37
38 @keyword spin_id: The spin ID string for restricting the graph to.
39 @type spin_id: str
40 @keyword x_data_name: The category of the X-axis data.
41 @type x_data_name: str
42 @keyword y_data_name: The category of the Y-axis data.
43 @type y_data_name: str
44 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
45 @type plot_data: str
46 @return: The 4D graph numerical data structure, the graph type (i.e. on of 'xy', 'xydy', or 'xydxdy'), and the labels for the graph sets.
47 @rtype: list of lists of lists of float, str, and list of str
48 """
49
50
51 data_list = False
52 data_dict = False
53
54
55 x_type = get_data_type(data_name=x_data_name)
56 y_type = get_data_type(data_name=y_data_name)
57
58
59 graph_type = classify_graph_2D(x_data_name=x_data_name, y_data_name=y_data_name, x_type=x_type, y_type=y_type)
60
61
62 if graph_type == 'seq-value':
63 data, set_labels, x_err_flag, y_err_flag = assemble_data_seq_value(spin_id=spin_id, x_data_name=x_data_name, y_data_name=y_data_name, plot_data=plot_data)
64 elif graph_type == 'value-value':
65 data, set_labels, x_err_flag, y_err_flag = assemble_data_scatter(spin_id=spin_id, x_data_name=x_data_name, y_data_name=y_data_name, plot_data=plot_data)
66 elif graph_type == 'seq-series':
67 data, set_labels, x_err_flag, y_err_flag = assemble_data_seq_series(spin_id=spin_id, x_data_name=x_data_name, y_data_name=y_data_name, plot_data=plot_data, x_type=x_type, y_type=y_type)
68 elif graph_type == 'series-series':
69 data, set_labels, x_err_flag, y_err_flag = assemble_data_series_series(spin_id=spin_id, x_data_name=x_data_name, y_data_name=y_data_name, plot_data=plot_data, x_type=x_type, y_type=y_type)
70 else:
71 raise RelaxError("Unknown graph type '%s'." % graph_type)
72
73
74 graph_type = 'X,Y'
75 if x_err_flag:
76 graph_type = graph_type + ',dX'
77 if y_err_flag:
78 graph_type = graph_type + ',dY'
79
80
81 return data, set_labels, graph_type
82
83
85 """Assemble the graph data for scatter type data of one value verses another.
86
87 For such data, only a single graph and set will be produced.
88
89
90 @keyword spin_id: The spin ID string for restricting the graph to.
91 @type spin_id: str
92 @keyword x_data_name: The name of the X-data or variable to plot.
93 @type x_data_name: str
94 @keyword y_data_name: The name of the Y-data or variable to plot.
95 @type y_data_name: str
96 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
97 @type plot_data: str
98 @return: The graph data, set labels, and flags for errors in the X and Y dimensions.
99 @rtype: list of lists of lists of numbers, list of str, bool, bool
100 """
101
102
103 return assemble_data_seq_value(x_data_name=x_data_name, y_data_name=y_data_name, plot_data=plot_data)
104
105
106 -def assemble_data_seq_series(spin_id=None, x_data_name=None, y_data_name=None, plot_data='value', x_type=None, y_type=None):
107 """Assemble the graph data for residue or spin sequence verses verses list or dictionary data.
108
109 For such data, one graph will be produced. There will be one data set in this graph per series.
110
111
112 @keyword spin_id: The spin ID string for restricting the graph to.
113 @type spin_id: str
114 @keyword x_data_name: The name of the X-data or variable to plot.
115 @type x_data_name: str
116 @keyword y_data_name: The name of the Y-data or variable to plot.
117 @type y_data_name: str
118 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
119 @type plot_data: str
120 @keyword x_type: The type of X-data to plot.
121 @type x_type: type object
122 @keyword y_type: The type of Y-data to plot.
123 @type y_type: type object
124 @return: The graph data, set labels, and flags for errors in the X and Y dimensions.
125 @rtype: list of lists of lists of numbers, list of str, bool, bool
126 """
127
128
129 data = [[]]
130 set_labels = []
131 x_err_flag = False
132 y_err_flag = False
133
134
135 if x_data_name in ['res_num', 'spin_num']:
136 seq_axis = 'x'
137 series_type = y_type
138 else:
139 seq_axis = 'y'
140 series_type = x_type
141
142
143 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True, skip_desel=True):
144
145 if seq_axis == 'x':
146 val, err = fetch_1D_data(plot_data=plot_data, data_name=y_data_name, spin=spin, res_num=res_num)
147 else:
148 val, err = fetch_1D_data(plot_data=plot_data, data_name=x_data_name, spin=spin, res_num=res_num)
149
150
151 if val == None:
152 continue
153
154
155 if series_type == dict:
156 keys = list(val.keys())
157
158
159 for j in range(len(val)):
160
161 if series_type == list:
162 elem = j
163 else:
164 elem = keys[j]
165
166
167 if elem not in set_labels:
168 data[0].append([])
169 set_labels.append(elem)
170
171
172 set_labels.sort()
173
174
175 if plot_data == 'sim':
176 points = cdp.sim_number
177 else:
178 points = 1
179
180
181 spin_index = 0
182 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True, skip_desel=True):
183
184 for i in range(points):
185
186 x_val, x_err = fetch_1D_data(plot_data=plot_data, data_name=x_data_name, spin=spin, res_num=res_num, sim_num=i)
187 y_val, y_err = fetch_1D_data(plot_data=plot_data, data_name=y_data_name, spin=spin, res_num=res_num, sim_num=i)
188
189
190 if seq_axis == 'x':
191 series_val = y_val
192 else:
193 series_val = x_val
194
195
196 if x_val == None or y_val == None:
197 continue
198
199
200 if x_err != None:
201 x_err_flag = True
202 if y_err != None:
203 y_err_flag = True
204
205
206 if series_type == dict:
207 keys = list(series_val.keys())
208
209
210 for j in range(len(series_val)):
211
212 if series_type == list:
213 index = set_labels.index(j)
214 elem = index
215 else:
216 index = set_labels.index(keys[j])
217 elem = set_labels[set_labels.index(keys[j])]
218
219
220 if seq_axis == 'x':
221 data[0][index].append([x_val, y_val[elem]])
222 else:
223 data[0][index].append([x_val[elem], y_val])
224 if x_err_flag:
225 data[0][index][-1].append(x_err[elem])
226 if y_err_flag:
227 data[0][index][-1].append(y_err[elem])
228
229
230 spin_index += 1
231
232
233 return data, set_labels, x_err_flag, y_err_flag
234
235
237 """Assemble the graph data for residue or spin sequence verses values.
238
239 For such data, only a single graph and set will be produced.
240
241
242 @keyword spin_id: The spin ID string for restricting the graph to.
243 @type spin_id: str
244 @keyword x_data_name: The name of the X-data or variable to plot.
245 @type x_data_name: str
246 @keyword y_data_name: The name of the Y-data or variable to plot.
247 @type y_data_name: str
248 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
249 @type plot_data: str
250 @return: The graph data, set labels, and flags for errors in the X and Y dimensions.
251 @rtype: list of lists of lists of numbers, list of str, bool, bool
252 """
253
254
255 data = [[[]]]
256 set_labels = []
257 x_err_flag = False
258 y_err_flag = False
259
260
261 spin_names = []
262 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True, skip_desel=True):
263
264 if spin.name not in spin_names:
265 spin_names.append(spin.name)
266
267
268 set_count = len(spin_names)
269
270
271 if set_count > 1:
272
273 for i in range(set_count-1):
274 data[0].append([])
275
276
277 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True, skip_desel=True):
278 label = "%s spins" % spin.name
279 if label not in set_labels:
280 set_labels.append(label)
281
282
283 if plot_data == 'sim':
284 points = cdp.sim_number
285 else:
286 points = 1
287
288
289 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True, skip_desel=True):
290
291 set_index = spin_names.index(spin.name)
292
293
294 for i in range(points):
295
296 x_val, x_err = fetch_1D_data(plot_data=plot_data, data_name=x_data_name, spin=spin, res_num=res_num, sim_num=i)
297 y_val, y_err = fetch_1D_data(plot_data=plot_data, data_name=y_data_name, spin=spin, res_num=res_num, sim_num=i)
298
299
300 if x_val == None or y_val == None:
301 continue
302
303
304 if x_err != None:
305 x_err_flag = True
306 if y_err != None:
307 y_err_flag = True
308
309
310 data[0][set_index].append([x_val, y_val])
311 if x_err_flag:
312 data[0][set_index][-1].append(x_err)
313 if y_err_flag:
314 data[0][set_index][-1].append(y_err)
315
316
317 return data, set_labels, x_err_flag, y_err_flag
318
319
321 """Assemble the graph data for curves of list or dictionary data verses list or dictionary data.
322
323 For such data, one graph will be produced. There will be one data set in this graph per spin.
324
325
326 @keyword spin_id: The spin ID string for restricting the graph to.
327 @type spin_id: str
328 @keyword x_data_name: The name of the X-data or variable to plot.
329 @type x_data_name: str
330 @keyword y_data_name: The name of the Y-data or variable to plot.
331 @type y_data_name: str
332 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
333 @type plot_data: str
334 @keyword x_type: The type of X-data to plot.
335 @type x_type: type object
336 @keyword y_type: The type of Y-data to plot.
337 @type y_type: type object
338 @return: The graph data, set labels, and flags for errors in the X and Y dimensions.
339 @rtype: list of lists of lists of numbers, list of str, bool, bool
340 """
341
342
343 data = [[]]
344 set_labels = []
345 x_err_flag = False
346 y_err_flag = False
347
348
349 if x_type != y_type:
350 raise RelaxError("The X data type '%s' and Y data type '%s' do not match." % (x_type, y_type))
351
352
353 keys_for_values = None
354 base_values = []
355 if x_type == dict:
356 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True, skip_desel=True):
357
358 x_val, x_err = fetch_1D_data(plot_data=plot_data, data_name=x_data_name, spin=spin, res_num=res_num)
359 y_val, y_err = fetch_1D_data(plot_data=plot_data, data_name=y_data_name, spin=spin, res_num=res_num)
360
361
362 if x_val == None or y_val == None:
363 continue
364
365
366 x_keys = list(x_val.keys())
367 y_keys = list(y_val.keys())
368
369
370 if x_keys[0] in y_keys:
371 continue
372
373
374 if x_keys[0] in y_val.values():
375 keys_for_values = 'x'
376 for key in x_keys:
377 if key not in base_values:
378 base_values.append(key)
379
380
381 elif y_keys[0] in x_val.values():
382 keys_for_values = 'y'
383 for key in y_keys:
384 if key not in base_values:
385 base_values.append(key)
386
387
388 if plot_data == 'sim':
389 points = cdp.sim_number
390 else:
391 points = 1
392
393
394 spin_index = 0
395 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True, skip_desel=True):
396
397 data[0].append([])
398 set_labels.append("Spin %s" % id)
399
400
401 for i in range(points):
402
403 x_val, x_err = fetch_1D_data(plot_data=plot_data, data_name=x_data_name, spin=spin, res_num=res_num, sim_num=i)
404 y_val, y_err = fetch_1D_data(plot_data=plot_data, data_name=y_data_name, spin=spin, res_num=res_num, sim_num=i)
405
406
407 if keys_for_values == None:
408 base_values = x_val
409
410
411 if x_val == None or y_val == None:
412 continue
413
414
415 if x_err != None:
416 x_err_flag = True
417 if y_err != None:
418 y_err_flag = True
419
420
421 if keys_for_values == None and len(x_val) != len(y_val):
422 raise RelaxError("The series data %s does not have the same number of elements as %s." % (x_val, y_val))
423
424
425 if x_type == dict:
426 keys = list(x_val.keys())
427
428
429 for j in range(len(base_values)):
430
431 if x_type == list:
432 elem = j
433 else:
434 elem = keys[j]
435
436
437 if keys_for_values == None:
438 data[0][spin_index].append([x_val[elem], y_val[elem]])
439 if x_err_flag:
440 data[0][spin_index][-1].append(x_err[elem])
441 if y_err_flag:
442 data[0][spin_index][-1].append(y_err[elem])
443
444
445 elif keys_for_values == 'x':
446 data[0][spin_index].append([x_val[base_values[j]], base_values[j]])
447 if x_err_flag:
448 data[0][spin_index][-1].append(x_err[base_values[j]])
449 if y_err_flag:
450 raise RelaxError("Y errors are not possible when the Y values are keys.")
451
452
453 elif keys_for_values == 'y':
454 data[0][spin_index].append([base_values[j], y_val[base_values[j]]])
455 if x_err_flag:
456 raise RelaxError("X errors are not possible when the X values are keys.")
457 if y_err_flag:
458 data[0][spin_index][-1].append(y_err[base_values[j]])
459
460
461 data[0][spin_index].sort()
462
463
464 spin_index += 1
465
466
467 return data, set_labels, x_err_flag, y_err_flag
468
469
471 """Determine the type of graph to produce.
472
473 The graph type can be one of:
474
475 - 'seq-value', the residue or spin sequence verses the parameter value.
476 - 'seq-series', the residue or spin sequence verses the parameter value.
477 - 'value-value', a scatter plot of one value verses another.
478 - 'value-series', a curve of one value verses a list or dictionary of data.
479 - 'series-series', curves of list or dictionary data verses list or dictionary data.
480
481 @keyword x_data_name: The name of the X-data or variable to plot.
482 @type x_data_name: str
483 @keyword y_data_name: The name of the Y-data or variable to plot.
484 @type y_data_name: str
485 @keyword x_type: The type of X-data to plot.
486 @type x_type: type object
487 @keyword y_type: The type of Y-data to plot.
488 @type y_type: type object
489 @return: The graph type.
490 @rtype: str
491 """
492
493
494 if x_data_name == y_data_name == 'res_num':
495 raise RelaxError("The X and Y-axes can not both be based on residue numbers.")
496 if x_data_name == y_data_name == 'spin_num':
497 raise RelaxError("The X and Y-axes can not both be based on residue numbers.")
498
499
500 x_series = False
501 y_series = False
502 if x_type == list or x_type == dict:
503 x_series = True
504 if y_type == list or y_type == dict:
505 y_series = True
506
507
508 if x_data_name in ['res_num', 'spin_num'] and not y_series:
509 return 'seq-value'
510 if x_data_name in ['res_num', 'spin_num'] and y_series:
511 return 'seq-series'
512 if y_data_name in ['res_num', 'spin_num'] and not x_series:
513 return 'seq-value'
514 if y_data_name in ['res_num', 'spin_num'] and x_series:
515 return 'seq-series'
516
517
518 if not x_series and not y_series:
519 return 'value-value'
520
521
522 if not x_series and y_series:
523 return 'value-series'
524 if x_series and not y_series:
525 return 'value-series'
526
527
528 if x_series and y_series:
529 return 'series-series'
530
531
532 return 'unknown'
533
534
535 -def fetch_1D_data(plot_data=None, data_name=None, spin=None, res_num=None, sim_num=None):
536 """Return the value and error for the corresponding axis.
537
538 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
539 @type plot_data: str
540 @keyword data_name: The name of the data or variable to plot.
541 @type data_name: str
542 @keyword spin: The spin container to fetch the values from.
543 @type spin: SpinContainer instance
544 @keyword res_num: The residue number for the given spin.
545 @type res_num: int
546 @keyword sim_num: The simulation number if simulation data is to be returned.
547 @type sim_num: int
548 @return: The value and error when available.
549 @rtype: int or float, None or float
550 """
551
552
553 return_value, return_conversion_factor = get_functions(data_name=data_name)
554
555
556 if data_name == 'res_num':
557 val, err = res_num, None
558
559
560 elif data_name == 'spin_num':
561 val, err = spin.num, None
562
563
564 else:
565
566 if plot_data == 'sim':
567 val, err = return_value(spin, data_name, sim=sim_num)
568 else:
569 val, err = return_value(spin, data_name)
570
571
572 if isinstance(val, list):
573 for i in range(len(val)):
574 val[i] = val[i] / return_conversion_factor(data_name)
575 if err != None:
576 err[i] = err[i] / return_conversion_factor(data_name)
577 elif isinstance(val, dict):
578 for key in val.keys():
579 val[key] = val[key] / return_conversion_factor(data_name)
580 if err != None:
581 err[key] = err[key] / return_conversion_factor(data_name)
582 elif val != None and err != None:
583 val = val / return_conversion_factor(data_name)
584 err = err / return_conversion_factor(data_name)
585 elif val != None:
586 val = val / return_conversion_factor(data_name)
587 elif err != None:
588 err = err / return_conversion_factor(data_name)
589
590
591 if data_name not in ['res_num', 'spin_num'] and plot_data == 'error':
592 val = err
593 err = None
594
595
596 if plot_data == 'sim':
597 err = None
598
599
600 return val, err
601
602
604 """Determine the specific functions for the given data type.
605
606 @keyword data_name: The name of the data or variable to plot.
607 @type data_name: str
608 @return: The analysis specific return_value, return_conversion_factor, and data_type methods.
609 @rtype: tuple of methods or None
610 """
611
612
613 if data_name in ['res_num', 'spin_num']:
614 return None, None
615
616
617 else:
618 api = return_api()
619 return api.return_value, api.return_conversion_factor
620
621
623 """Determine the type for the given data.
624
625 @keyword data_name: The name of the data or variable to plot.
626 @type data_name: str
627 @return: The data type.
628 @rtype: Python type
629 """
630
631
632 if data_name in ['res_num', 'spin_num']:
633 return int
634
635
636 api = return_api()
637 return api.data_type(data_name)
638