|
5 | 5 | from numerix import absolute, arange, array, asarray, ones, divide,\ |
6 | 6 | transpose, log, log10, Float, Float32, ravel, zeros,\ |
7 | 7 | Int16, Int32, Int, Float64, ceil, indices, \ |
8 | | - shape, which, where, sqrt, asum |
| 8 | + shape, which, where, sqrt, asum, compress |
9 | 9 |
|
10 | 10 | import matplotlib.mlab |
11 | 11 | from artist import Artist |
|
27 | 27 | from lines import Line2D, lineStyles, lineMarkers |
28 | 28 |
|
29 | 29 | from matplotlib.mlab import meshgrid, detrend_none, detrend_linear, \ |
30 | | - window_none, window_hanning, linspace |
| 30 | + window_none, window_hanning, linspace, prctile |
31 | 31 | from matplotlib.numerix.mlab import flipud, amin, amax |
32 | 32 |
|
33 | 33 | from matplotlib import rcParams |
@@ -845,7 +845,154 @@ def bar(self, left, height, width=0.8, bottom=0, |
845 | 845 | self.autoscale_view() |
846 | 846 | return patches |
847 | 847 |
|
| 848 | + def boxplot(self, x, notch=0, sym='b+', vert=1, whis=1.5): |
| 849 | + """ |
| 850 | + boxplot(x, notch=0, sym='+', vert=1, whis=1.5) |
| 851 | +
|
| 852 | + Make a box and whisker plot for each column of x. |
| 853 | + The box extends from the lower to upper quartile values |
| 854 | + of the data, with a line at the median. The whiskers |
| 855 | + extend from the box to show the range of the data. Flier |
| 856 | + points are those past the end of the whiskers. |
| 857 | + |
| 858 | + notch = 0 (default) produces a rectangular box plot. |
| 859 | + notch = 1 will produce a notched box plot |
| 860 | + |
| 861 | + sym (default 'b+') is the default symbol for flier points. |
| 862 | + Enter an empty string ('') if you don't want to show fliers. |
| 863 | + |
| 864 | + vert = 1 (default) makes the boxes vertical. |
| 865 | + vert = 0 makes horizontal boxes. This seems goofy, but |
| 866 | + that's how Matlab did it. |
| 867 | + |
| 868 | + whis (default 1.5) defines the length of the whiskers as |
| 869 | + a function of the inner quartile range. They extend to the |
| 870 | + most extreme data point within ( whis*(75%-25%) ) data range. |
848 | 871 |
|
| 872 | + x is a Numeric array |
| 873 | + |
| 874 | + Returns a list of the lines added |
| 875 | + |
| 876 | + """ |
| 877 | + if not self._hold: self.cla() |
| 878 | + holdStatus = self._hold |
| 879 | + lines = [] |
| 880 | + x = asarray(x) |
| 881 | + |
| 882 | + # if we've got a vector, reshape it |
| 883 | + rank = len(x.shape) |
| 884 | + if 1 == rank: |
| 885 | + x.shape(-1, 1) |
| 886 | + |
| 887 | + row, col = x.shape |
| 888 | + |
| 889 | + # get some plot info |
| 890 | + num_plots = range(1, col + 1) |
| 891 | + box_width = col * min(0.15, 0.5/col) |
| 892 | + |
| 893 | + # loop through columns, adding each to plot |
| 894 | + self.hold(True) |
| 895 | + for i in num_plots: |
| 896 | + d = x[:,i-1] |
| 897 | + # get median and quartiles |
| 898 | + q1, med, q3 = prctile(d,[25,50,75]) |
| 899 | + # get high extreme |
| 900 | + iq = q3 - q1 |
| 901 | + hi_val = q3 + whis*iq |
| 902 | + wisk_hi = compress( d <= hi_val , d ) |
| 903 | + if len(wisk_hi) == 0: |
| 904 | + wisk_hi = q3 |
| 905 | + else: |
| 906 | + wisk_hi = max(wisk_hi) |
| 907 | + # get low extreme |
| 908 | + lo_val = q1 - whis*iq |
| 909 | + wisk_lo = compress( d >= lo_val, d ) |
| 910 | + if len(wisk_lo) == 0: |
| 911 | + wisk_lo = q1 |
| 912 | + else: |
| 913 | + wisk_lo = min(wisk_lo) |
| 914 | + # get fliers - if we are showing them |
| 915 | + flier_hi = [] |
| 916 | + flier_lo = [] |
| 917 | + flier_hi_x = [] |
| 918 | + flier_lo_x = [] |
| 919 | + if len(sym) != 0: |
| 920 | + flier_hi = compress( d > wisk_hi, d ) |
| 921 | + flier_lo = compress( d < wisk_lo, d ) |
| 922 | + flier_hi_x = ones(flier_hi.shape[0]) * i |
| 923 | + flier_lo_x = ones(flier_lo.shape[0]) * i |
| 924 | + |
| 925 | + # get x locations for fliers, whisker, whisker cap and box sides |
| 926 | + box_x_min = i - box_width * 0.5 |
| 927 | + box_x_max = i + box_width * 0.5 |
| 928 | + |
| 929 | + wisk_x = ones(2) * i |
| 930 | + |
| 931 | + cap_x_min = i - box_width * 0.25 |
| 932 | + cap_x_max = i + box_width * 0.25 |
| 933 | + cap_x = [cap_x_min, cap_x_max] |
| 934 | + |
| 935 | + # get y location for median |
| 936 | + med_y = [med, med] |
| 937 | + |
| 938 | + # calculate 'regular' plot |
| 939 | + if notch == 0: |
| 940 | + # make our box vectors |
| 941 | + box_x = [box_x_min, box_x_max, box_x_max, box_x_min, box_x_min ] |
| 942 | + box_y = [q1, q1, q3, q3, q1 ] |
| 943 | + # make our median line vectors |
| 944 | + med_x = [box_x_min, box_x_max] |
| 945 | + # calculate 'notch' plot |
| 946 | + else: |
| 947 | + notch_max = med + 1.57*iq/sqrt(row) |
| 948 | + notch_min = med - 1.57*iq/sqrt(row) |
| 949 | + if notch_max > q3: |
| 950 | + notch_max = q3 |
| 951 | + if notch_min < q1: |
| 952 | + notch_min = q1 |
| 953 | + # make our notched box vectors |
| 954 | + box_x = [box_x_min, box_x_max, box_x_max, cap_x_max, box_x_max, box_x_max, box_x_min, box_x_min, cap_x_min, box_x_min, box_x_min ] |
| 955 | + box_y = [q1, q1, notch_min, med, notch_max, q3, q3, notch_max, med, notch_min, q1] |
| 956 | + # make our median line vectors |
| 957 | + med_x = [cap_x_min, cap_x_max] |
| 958 | + med_y = [med, med] |
| 959 | + |
| 960 | + # make a vertical plot . . . |
| 961 | + if 1 == vert: |
| 962 | + l = self.plot(wisk_x, [q1, wisk_lo], 'b--', |
| 963 | + wisk_x, [q3, wisk_hi], 'b--', |
| 964 | + cap_x, [wisk_hi, wisk_hi], 'k-', |
| 965 | + cap_x, [wisk_lo, wisk_lo], 'k-', |
| 966 | + box_x, box_y, 'b-', |
| 967 | + med_x, med_y, 'r-', |
| 968 | + flier_hi_x, flier_hi, sym, |
| 969 | + flier_lo_x, flier_lo, sym ) |
| 970 | + lines.extend(l) |
| 971 | + # or perhaps a horizontal plot |
| 972 | + else: |
| 973 | + l = self.plot([q1, wisk_lo], wisk_x, 'b--', |
| 974 | + [q3, wisk_hi], wisk_x, 'b--', |
| 975 | + [wisk_hi, wisk_hi], cap_x, 'k-', |
| 976 | + [wisk_lo, wisk_lo], cap_x, 'k-', |
| 977 | + box_y, box_x, 'b-', |
| 978 | + med_y, med_x, 'r-', |
| 979 | + flier_hi, flier_hi_x, sym, |
| 980 | + flier_lo, flier_lo_x, sym ) |
| 981 | + lines.extend(l) |
| 982 | + |
| 983 | + |
| 984 | + # fix our axes/ticks up a little |
| 985 | + if 1 == vert: |
| 986 | + self.set_xlim([0.5, 0.5+col]) |
| 987 | + self.set_xticks(num_plots) |
| 988 | + else: |
| 989 | + self.set_ylim([0.5, 0.5+col]) |
| 990 | + self.set_yticks(num_plots) |
| 991 | + |
| 992 | + # reset hold status |
| 993 | + self.hold(holdStatus) |
| 994 | + |
| 995 | + return lines |
849 | 996 |
|
850 | 997 | def barh(self, x, y, height=0.8, left=0, |
851 | 998 | color='b', yerr=None, xerr=None, ecolor='k', capsize=3 |
|
0 commit comments