~ubuntu-branches/ubuntu/trusty/qiime/trusty

« back to all changes in this revision

Viewing changes to tests/test_pycogent_backports/test_distribution_plots.py

  • Committer: Package Import Robot
  • Author(s): Andreas Tille
  • Date: 2013-06-17 18:28:26 UTC
  • mfrom: (9.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20130617182826-376az5ad080a0sfe
Tags: 1.7.0+dfsg-1
Upload preparations done for BioLinux to Debian

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/env python
2
 
__author__ = "Jai Rideout"
3
 
__copyright__ = "Copyright 2011, The QIIME Project"
4
 
__credits__ = ["Jai Rideout"]
 
2
__author__ = "Jai Ram Rideout"
 
3
__copyright__ = "Copyright 2007-2012, The Cogent Project"
 
4
__credits__ = ["Jai Ram Rideout"]
5
5
__license__ = "GPL"
6
 
__version__ = "1.5.0"
7
 
__maintainer__ = "Jai Rideout"
8
 
__email__ = "jr378@nau.edu"
9
 
__status__ = "Release"
 
6
__version__ = "1.5.3-dev"
 
7
__maintainer__ = "Jai Ram Rideout"
 
8
__email__ = "jai.rideout@gmail.com"
 
9
__status__ = "Production"
10
10
 
11
11
"""Tests public and private functions in the distribution_plots module."""
12
12
 
17
17
import matplotlib.colors as colors
18
18
from matplotlib.pyplot import boxplot
19
19
from numpy import array
20
 
from qiime.pycogent_backports.distribution_plots import _validate_input,\
21
 
    _get_distribution_markers, _validate_x_values, _create_plot,\
22
 
    _calc_data_point_locations, _set_axes_options, generate_box_plots,\
23
 
    generate_comparative_plots, _calc_data_point_ticks, _plot_bar_data,\
24
 
    _plot_scatter_data, _plot_box_data, _color_box_plot,\
25
 
    _create_standard_legend, _create_box_plot_legend
 
20
from qiime.pycogent_backports.distribution_plots import (_validate_input,
 
21
      _get_distribution_markers, _validate_x_values, _create_plot,
 
22
      _calc_data_point_locations, _set_axes_options, generate_box_plots,
 
23
      generate_comparative_plots, _calc_data_point_ticks, _plot_bar_data,
 
24
      _plot_scatter_data, _plot_box_data, _color_box_plot,
 
25
      _is_single_matplotlib_color, _create_legend, _set_figure_size)
26
26
from cogent.util.unit_test import TestCase, main
27
27
 
28
28
class DistributionPlotsTests(TestCase):
255
255
        self.assertEqual(len(result['caps']), 2)
256
256
 
257
257
    def test_plot_box_data_empty(self):
258
 
        """_plot_box_data() should not error when given empty list of data,
259
 
        but should not plot anything."""
 
258
        """Should ignore empty distribution."""
260
259
        fig, ax = _create_plot()
261
260
        result = _plot_box_data(ax, [], 'blue', 0.33, 55, 1.5, 'stdv')
262
 
        self.assertEqual(result.__class__.__name__, "dict")
263
 
        self.assertEqual(len(result['boxes']), 0)
264
 
        self.assertEqual(len(result['medians']), 0)
265
 
        self.assertEqual(len(result['whiskers']), 0)
266
 
        self.assertEqual(len(result['fliers']), 0)
267
 
        self.assertEqual(len(result['caps']), 0)
 
261
        self.assertTrue(result is None)
268
262
 
269
 
    def test_calc_data_point_locations_invalid_widths(self):
270
 
        """_calc_data_point_locations() should raise a ValueError
271
 
        exception when it encounters bad widths."""
272
 
        self.assertRaises(ValueError, _calc_data_point_locations, [1, 2, 3],
273
 
                3, 2, -2, 0.5)
274
 
        self.assertRaises(ValueError, _calc_data_point_locations, [1, 2, 3],
275
 
                3, 2, 2, -0.5)
 
263
    def test_calc_data_point_locations_invalid_x_values(self):
 
264
        """Should raise error when invalid x_values are encountered."""
 
265
        self.assertRaises(ValueError, _calc_data_point_locations, 3, [1, 10.5])
276
266
 
277
267
    def test_calc_data_point_locations_default_spacing(self):
278
 
        """_calc_data_point_locations() should return an array containing
279
 
        the x-axis locations for each data point, evenly spaced from 1..n."""
280
 
        locs = _calc_data_point_locations(None, 4, 2, 0.25, 0.5)
281
 
        self.assertEqual(locs, array([1.0, 2.0, 3.0, 4.0]))
 
268
        """Should return evenly-spaced x-axis locations."""
 
269
        locs = _calc_data_point_locations(4)
 
270
        self.assertEqual(locs, array([1, 2, 3, 4]))
282
271
 
283
272
    def test_calc_data_point_locations_custom_spacing(self):
284
 
        """_calc_data_point_locations() should return an array containing
285
 
        the x-axis locations for each data point, spaced according to a custom
286
 
        spacing scheme."""
287
 
        locs = _calc_data_point_locations([3, 4, 10, 12], 4, 2, 0.25, 0.75)
288
 
        self.assertEqual(locs, array([3.75, 5.0, 12.5, 15.0]))
 
273
        """Should return non-evenly-spaced x-axis locations."""
 
274
        # Scaling down from 3..12 to 1..4.
 
275
        locs = _calc_data_point_locations(4, [3, 4, 10, 12])
 
276
        self.assertFloatEqual(locs, array([1, 1.33333333, 3.33333333, 4]))
 
277
 
 
278
        # Sorted order shouldn't affect scaling.
 
279
        locs = _calc_data_point_locations(4, [4, 3, 12, 10])
 
280
        self.assertFloatEqual(locs, array([1.33333333, 1, 4, 3.33333333]))
 
281
 
 
282
        # Scaling up from 0.001..0.87 to 1..3.
 
283
        locs = _calc_data_point_locations(3, [0.001, 0.2543, 0.87])
 
284
        self.assertFloatEqual(locs, array([1, 1.58296893, 3]))
289
285
 
290
286
    def test_calc_data_point_ticks(self):
291
287
        """_calc_data_point_ticks() should return an array containing the
327
323
                          x_tick_labels=["T0", "T1", "T2"], y_min='car',
328
324
                          y_max=30)
329
325
 
330
 
    def test_create_standard_legend_invalid_input(self):
331
 
        """_create_standard_legend() should raise an exception when given a
332
 
        list of distribution examples that contains one or more null values, or
333
 
        if the lengths of the input lists don't match up."""
334
 
        fig, ax = _create_plot()
335
 
        self.assertRaises(ValueError, _create_standard_legend, [None, []], ax,
336
 
                ['^', '<'], 2, ['dist1', 'dist2'])
337
 
        self.assertRaises(ValueError, _create_standard_legend, [[], []], ax,
338
 
                ['^', '<', '>'], 2, ['dist1', 'dist2'])
339
 
        self.assertRaises(ValueError, _create_standard_legend, [[], []], ax,
340
 
                ['^', '<', '>'], 3, ['dist1', 'dist2', 'dist3'])
341
 
        self.assertRaises(ValueError, _create_standard_legend, [[], [], []],
342
 
                ax, ['^', '<', '>'], 3, ['dist1', 'dist2'])
343
 
 
344
 
    def test_create_box_plot_legend_invalid_input(self):
345
 
        """_create_box_plot_legend() should raise an exception when the lengths
346
 
        of the input lists don't match up."""
347
 
        fig, ax = _create_plot()
348
 
        self.assertRaises(ValueError, _create_box_plot_legend, [[], []], ax,
349
 
                ['b', 'm', 'r'], 2, ['dist1', 'dist2'])
350
 
        self.assertRaises(ValueError, _create_box_plot_legend, [[], []], ax,
351
 
                ['b', 'm', 'r'], 3, ['dist1', 'dist2', 'dist3'])
352
 
        self.assertRaises(ValueError, _create_box_plot_legend, [[], [], []],
353
 
                ax, ['b', 'm', 'r'], 3, ['dist1', 'dist2'])
354
 
 
355
 
    def test_create_box_plot_legend_valid_input(self):
 
326
    def test_create_legend(self):
356
327
        """_create_box_plot_legend() should create a legend on valid input."""
357
328
        fig, ax = _create_plot()
358
 
        _create_box_plot_legend([[], []], ax, ['b', 'r'], 2,
359
 
                ['dist1', 'dist2'])
 
329
        _create_legend(ax, ['b', 'r'], ['dist1', 'dist2'], 'colors')
 
330
        self.assertEqual(len(ax.get_legend().get_texts()), 2)
 
331
 
 
332
        fig, ax = _create_plot()
 
333
        _create_legend(ax, ['^', '<', '>'], ['dist1', 'dist2', 'dist3'],
 
334
                'symbols')
 
335
        self.assertEqual(len(ax.get_legend().get_texts()), 3)
 
336
 
 
337
    def test_create_legend_invalid_input(self):
 
338
        """Test raises error on bad input."""
 
339
        fig, ax = _create_plot()
 
340
        self.assertRaises(ValueError, _create_legend, ax,
 
341
                ['^', '<', '>'], ['dist1', 'dist2'], 'symbols')
 
342
        self.assertRaises(ValueError, _create_legend, ax, ['^', '<', '>'],
 
343
                ['dist1', 'dist2', 'dist3'], 'foo')
360
344
 
361
345
    def test_generate_box_plots(self):
362
346
        """generate_box_plots() should return a valid Figure object."""
370
354
        self.assertEqual(len(ax.get_xticklabels()), 3)
371
355
        self.assertFloatEqual(ax.get_xticks(), [1, 4, 10])
372
356
 
 
357
    def test_generate_box_plots_empty_distributions(self):
 
358
        """Test functions correctly with empty distributions."""
 
359
        fig = generate_box_plots([[1, 2, 3], [], [4, 5, 6]], [1, 4, 10],
 
360
                                 ["Data 1", "Data 2", "Data 3"], "Test",
 
361
                                 "x-axis label", "y-axis label")
 
362
        ax = fig.get_axes()[0]
 
363
        self.assertEqual(ax.get_title(), "Test")
 
364
        self.assertEqual(ax.get_xlabel(), "x-axis label")
 
365
        self.assertEqual(ax.get_ylabel(), "y-axis label")
 
366
        self.assertEqual(len(ax.get_xticklabels()), 3)
 
367
        self.assertFloatEqual(ax.get_xticks(), [1, 4, 10])
 
368
 
 
369
        # All distributions are empty.
 
370
        fig = generate_box_plots([[], [], []], [1, 4, 10],
 
371
                                 ["Data 1", "Data 2", "Data 3"], "Test",
 
372
                                 "x-axis label", "y-axis label")
 
373
        ax = fig.get_axes()[0]
 
374
        self.assertEqual(ax.get_title(), "Test")
 
375
        self.assertEqual(ax.get_xlabel(), "x-axis label")
 
376
        self.assertEqual(ax.get_ylabel(), "y-axis label")
 
377
        self.assertEqual(len(ax.get_xticklabels()), 3)
 
378
        self.assertFloatEqual(ax.get_xticks(), [1, 4, 10])
 
379
 
 
380
    def test_generate_box_plots_box_colors(self):
 
381
        """Test correctly handles coloring of box plots."""
 
382
        # Coloring works with all empty distributions.
 
383
        fig = generate_box_plots([[], [], []],
 
384
                                 box_colors=['blue', 'red', 'yellow'])
 
385
        ax = fig.get_axes()[0]
 
386
        self.assertEqual(len(ax.get_xticklabels()), 3)
 
387
 
 
388
        fig = generate_box_plots([[], [], []], box_colors='pink')
 
389
        ax = fig.get_axes()[0]
 
390
        self.assertEqual(len(ax.get_xticklabels()), 3)
 
391
 
 
392
        # Coloring works with some empty distributions.
 
393
        fig = generate_box_plots([[], [1, 2, 3.5], []],
 
394
                                 box_colors=['blue', 'red', 'yellow'])
 
395
        ax = fig.get_axes()[0]
 
396
        self.assertEqual(len(ax.get_xticklabels()), 3)
 
397
 
 
398
    def test_generate_box_plots_invalid_input(self):
 
399
        """Test correctly throws error on invalid input."""
 
400
        # Non-numeric entries in distribution.
 
401
        self.assertRaises(ValueError, generate_box_plots, [[1, 'foo', 3]])
 
402
 
 
403
        # Number of colors doesn't match number of distributions.
 
404
        self.assertRaises(ValueError, generate_box_plots, [[1, 2, 3], [],
 
405
                          [4, 5, 6]], box_colors=['blue', 'red'])
 
406
 
 
407
        # Invalid legend.
 
408
        self.assertRaises(ValueError, generate_box_plots, [[1, 2, 3]],
 
409
                          legend=('foo', 'bar', 'baz'))
 
410
 
373
411
    def test_generate_comparative_plots_bar(self):
374
 
        """generate_comparative_plots() should return a valid barchart Figure
375
 
        object."""
 
412
        """Should return a valid barchart Figure object."""
376
413
        fig = generate_comparative_plots('bar', self.ValidTypicalData,
377
414
                [1, 4, 10, 11], ["T0", "T1", "T2", "T3"],
378
415
                ["Infants", "Children", "Teens"], ['b', 'r', 'g'],
382
419
        self.assertEqual(ax.get_xlabel(), "x-axis label")
383
420
        self.assertEqual(ax.get_ylabel(), "y-axis label")
384
421
        self.assertEqual(len(ax.get_xticklabels()), 4)
385
 
        self.assertFloatEqual(ax.get_xticks(), [2.3, 7.4, 17.6, 19.3])
 
422
        self.assertFloatEqual(ax.get_xticks(),
 
423
                              [1.1125, 2.0125, 3.8125, 4.1125])
386
424
 
387
425
    def test_generate_comparative_plots_insufficient_colors(self):
388
426
        """generate_comparative_plots() should work even when there aren't
406
444
            sys.stdout = saved_stdout
407
445
 
408
446
    def test_generate_comparative_plots_scatter(self):
409
 
        """generate_comparative_plots() should return a valid scatterplot
410
 
        Figure object."""
 
447
        """Should return a valid scatterplot Figure object."""
411
448
        fig = generate_comparative_plots('scatter', self.ValidTypicalData,
412
449
                [1, 4, 10, 11], ["T0", "T1", "T2", "T3"],
413
450
                ["Infants", "Children", "Teens"], ['^', '>', '<'],
417
454
        self.assertEqual(ax.get_xlabel(), "x-axis label")
418
455
        self.assertEqual(ax.get_ylabel(), "y-axis label")
419
456
        self.assertEqual(len(ax.get_xticklabels()), 4)
420
 
        self.assertFloatEqual(ax.get_xticks(), [2.1, 7.2, 17.4, 19.1])
 
457
        self.assertFloatEqual(ax.get_xticks(), [1.075, 1.975, 3.775, 4.075])
421
458
 
422
459
    def test_generate_comparative_plots_insufficient_symbols(self):
423
460
        """generate_comparative_plots() should work even when there aren't
449
486
                "x-axis label", "y-axis label", "Test")
450
487
 
451
488
    def test_generate_comparative_plots_box(self):
452
 
        """generate_comparative_plots() should return a valid boxplot Figure
453
 
        object."""
 
489
        """Should return a valid boxplot Figure object."""
454
490
        fig = generate_comparative_plots('box', self.ValidTypicalData,
455
491
                [1, 4, 10, 11], ["T0", "T1", "T2", "T3"],
456
492
                ["Infants", "Children", "Teens"], ['b', 'g', 'y'],
460
496
        self.assertEqual(ax.get_xlabel(), "x-axis label")
461
497
        self.assertEqual(ax.get_ylabel(), "y-axis label")
462
498
        self.assertEqual(len(ax.get_xticklabels()), 4)
463
 
        self.assertFloatEqual(ax.get_xticks(), [2.1, 7.2, 17.4, 19.1])
 
499
        self.assertFloatEqual(ax.get_xticks(), [1.075, 1.975, 3.775, 4.075])
464
500
 
465
501
    def test_generate_comparative_plots_error(self):
466
502
        """generate_comparative_plots() should raise a ValueError for an
472
508
                "x-axis label", "y-axis label", "Test")
473
509
 
474
510
    def test_color_box_plot(self):
475
 
        """_color_box_plot() should not throw an exception when passed the
476
 
        proper input."""
477
 
        fig, ax = _create_plot()
478
 
        box_plot = boxplot(self.ValidTypicalBoxData)
479
 
        _color_box_plot(ax, box_plot, 'blue')
 
511
        """Should not throw an exception when passed the proper input."""
 
512
        fig, ax = _create_plot()
 
513
        box_plot = boxplot(self.ValidTypicalBoxData)
 
514
        _color_box_plot(ax, box_plot, ['blue', 'w', (1, 1, 0.9)])
 
515
 
 
516
        # Some colors are None.
 
517
        fig, ax = _create_plot()
 
518
        box_plot = boxplot(self.ValidTypicalBoxData)
 
519
        _color_box_plot(ax, box_plot, ['blue', None, (1, 1, 0.9)])
 
520
 
 
521
        # All colors are None.
 
522
        fig, ax = _create_plot()
 
523
        box_plot = boxplot(self.ValidTypicalBoxData)
 
524
        _color_box_plot(ax, box_plot, [None, None, None])
 
525
 
 
526
    def test_color_box_plot_invalid_input(self):
 
527
        """Should throw an exception on invalid input."""
 
528
        # Invalid color.
 
529
        fig, ax = _create_plot()
 
530
        box_plot = boxplot(self.ValidTypicalBoxData)
 
531
        self.assertRaises(ValueError, _color_box_plot, ax, box_plot,
 
532
                          ['red', 'foobarbaz', 'blue'])
 
533
 
 
534
        # Wrong number of colors.
 
535
        fig, ax = _create_plot()
 
536
        box_plot = boxplot(self.ValidTypicalBoxData)
 
537
        self.assertRaises(ValueError, _color_box_plot, ax, box_plot,
 
538
                          ['blue', (1, 1, 0.9)])
 
539
 
 
540
    def test_is_single_matplotlib_color(self):
 
541
        """Test correct identification of single versus multiple mpl colors."""
 
542
        self.assertTrue(_is_single_matplotlib_color('w'))
 
543
        self.assertTrue(_is_single_matplotlib_color('white'))
 
544
        self.assertTrue(_is_single_matplotlib_color([1, 1, 1]))
 
545
        self.assertTrue(_is_single_matplotlib_color([1, 1, 1, 1]))
 
546
        self.assertTrue(_is_single_matplotlib_color((1, 1, 1)))
 
547
        self.assertTrue(_is_single_matplotlib_color((1, 1, 1, 1)))
 
548
        self.assertTrue(_is_single_matplotlib_color((1.0, 1.0, 1.0, 1.0)))
 
549
        self.assertTrue(_is_single_matplotlib_color((1.0, 1, 1.0)))
 
550
        self.assertTrue(_is_single_matplotlib_color((2.0, 1, 1.0)))
 
551
 
 
552
        self.assertFalse(_is_single_matplotlib_color(['w', 'r']))
 
553
        self.assertFalse(_is_single_matplotlib_color(['w']))
 
554
        self.assertFalse(_is_single_matplotlib_color(('w',)))
 
555
        self.assertFalse(_is_single_matplotlib_color(((1.0, 1.0, 1),)))
 
556
        self.assertFalse(_is_single_matplotlib_color(((1.0, 1.0, 1),
 
557
                                                      (0.9, 0.9))))
 
558
 
 
559
    def test_set_figure_size(self):
 
560
        """Test setting a valid figure size."""
 
561
        fig, ax = _create_plot()
 
562
        _set_axes_options(ax, 'foo', 'x_foo', 'y_foo',
 
563
                          x_tick_labels=['foofoofoo', 'barbarbar'],
 
564
                          x_tick_labels_orientation='vertical')
 
565
        _set_figure_size(fig, 3, 4)
 
566
        self.assertFloatEqual(fig.get_size_inches(), (3, 4))
 
567
 
 
568
    def test_set_figure_size_defaults(self):
 
569
        """Test setting a figure size using matplotlib defaults."""
 
570
        fig, ax = _create_plot()
 
571
        _set_axes_options(ax, 'foo', 'x_foo', 'y_foo',
 
572
                          x_tick_labels=['foofoofoo', 'barbarbar'],
 
573
                          x_tick_labels_orientation='vertical')
 
574
        orig_fig_size = fig.get_size_inches()
 
575
        _set_figure_size(fig)
 
576
        self.assertFloatEqual(fig.get_size_inches(), orig_fig_size)
 
577
 
 
578
    def test_set_figure_size_invalid(self):
 
579
        """Test setting a figure size using invalid dimensions."""
 
580
        fig, ax = _create_plot()
 
581
        _set_axes_options(ax, 'foo', 'x_foo', 'y_foo',
 
582
                          x_tick_labels=['foofoofoo', 'barbarbar'],
 
583
                          x_tick_labels_orientation='vertical')
 
584
        orig_fig_size = fig.get_size_inches()
 
585
        _set_figure_size(fig, -1, 0)
 
586
        self.assertFloatEqual(fig.get_size_inches(), orig_fig_size)
 
587
 
 
588
    def test_set_figure_size_long_labels(self):
 
589
        """Test setting a figure size that has really long labels."""
 
590
        saved_stdout = sys.stdout
 
591
        try:
 
592
            out = StringIO()
 
593
            sys.stdout = out
 
594
 
 
595
            fig, ax = _create_plot()
 
596
            _set_axes_options(ax, 'foo', 'x_foo', 'y_foo',
 
597
                              x_tick_labels=['foofoofooooooooooooooooooooooooo'
 
598
                              'ooooooooooooooooooooooooooooooooooooooooooooooo'
 
599
                              'ooooooooooooooooooooo', 'barbarbar'],
 
600
                              x_tick_labels_orientation='vertical')
 
601
            _set_figure_size(fig, 3, 3)
 
602
            self.assertFloatEqual(fig.get_size_inches(), (3, 3))
 
603
            output = out.getvalue().strip()
 
604
            self.assertEqual(output,
 
605
            "Warning: could not automatically resize plot to make room for "
 
606
            "axes labels and plot title. This can happen if the labels or "
 
607
            "title are extremely long and the plot size is too small. Your "
 
608
            "plot may have its labels and/or title cut-off. To fix this, "
 
609
            "try increasing the plot's size (in inches) and try again.")
 
610
        finally:
 
611
            sys.stdout = saved_stdout
 
612
 
480
613
 
481
614
if __name__ == '__main__':
482
615
    main()