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