Skip to content

Cleanup: sorted, dict iteration, array.{ndim,size}, ... #7549

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 22, 2016

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Dec 2, 2016

  • Use sorted whereever it improves readbility over list.sort.
  • Iterating over a dict doesn't require calling iterkeys.
  • Use ndarray.size/.ndim whereever appropriate.
  • Une N{...} unicode entities.

@tacaswell tacaswell added this to the 2.1 (next point release) milestone Dec 2, 2016
@anntzer anntzer changed the title Cleanup sorted Cleanup: sorted, dict iteration Dec 2, 2016
@anntzer anntzer changed the title Cleanup: sorted, dict iteration Cleanup: sorted, dict iteration, array.{ndim,size} Dec 2, 2016
@anntzer anntzer changed the title Cleanup: sorted, dict iteration, array.{ndim,size} Cleanup: sorted, dict iteration, array.{ndim,size}, ... Dec 2, 2016
@anntzer anntzer force-pushed the cleanup-sorted branch 3 times, most recently from d163a75 to bec79f4 Compare December 2, 2016 07:03
@QuLogic
Copy link
Member

QuLogic commented Dec 2, 2016

Do Unicode entities work in Python 2? I'm not seeing it in the Unicode howto.

@anntzer
Copy link
Contributor Author

anntzer commented Dec 2, 2016

Yes, see table at https://docs.python.org/2.7/reference/lexical_analysis.html#string-literals (or try it yourself :-)).

@anntzer anntzer force-pushed the cleanup-sorted branch 2 times, most recently from 9d0a612 to 5044c22 Compare December 3, 2016 00:08
@codecov-io
Copy link

codecov-io commented Dec 3, 2016

Current coverage is 61.90% (diff: 60.69%)

Merging #7549 into master will decrease coverage by <.01%

@@             master      #7549   diff @@
==========================================
  Files           173        173          
  Lines         56103      55917   -186   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
- Hits          34731      34614   -117   
+ Misses        21372      21303    -69   
  Partials          0          0          

Powered by Codecov. Last update 6223155...e809aaf

@anntzer anntzer force-pushed the cleanup-sorted branch 3 times, most recently from d5fe5e4 to d17d6b5 Compare December 3, 2016 21:45
Copy link
Contributor

@twmr twmr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't review the whole PR

line = fh.readline()
if not line:
break
for line in fh:
line = line.rstrip()
if len(line) == 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you could have also used 'if not line'

@@ -135,9 +135,8 @@ def plot_figure(style_label=""):
# Setup a list of all available styles, in alphabetical order but
# the `default` and `classic` ones, which will be forced resp. in
# first and second position.
style_list = list(plt.style.available) # *new* list: avoids side effects.
style_list = sorted(plt.style.available) # *new* list: avoids side effects.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove the comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both are fixed

Copy link
Member

@QuLogic QuLogic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a behemoth, but I think I managed to get through it all.


def values(self):
"""
Return values in order of sorted keys.
"""
return [self[k] for k in self.keys()]
return [self[k] for k in self]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does dropping .keys() and iterating over self correctly preserve the sorted order that the keys method from this subclass produces?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. But that also means that iteration on the dict itself (for k in rcparams) happens in a different order right now...

@@ -91,7 +91,7 @@ def _sanity_check(fh):
# do something else with the file.
pos = fh.tell()
try:
line = fh.readline()
line = next(fh)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not convinced this is clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that the outer loop may be using for line in fh first before passing the handle to the function at some point, and Py2 (not Py3) doesn't allow (raises an exception on) mixing for line in fh and fh.readline due to the fact that the former uses a readahead buffer (https://docs.python.org/2/library/stdtypes.html#file.next).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this is called before the iteration, and the next line is a seek, which should flush the readahead buffer anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the gain in legibility with .readline() doesn't compensate the brittleness of only being able to pass in a file with an empty readahead buffer.

@@ -232,20 +225,17 @@ def _parse_kern_pairs(fh):

"""

line = fh.readline()
line = next(fh)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one makes sense though; will need to remain next.

locs = [ti[1] for ti in tick_tups]
locs.sort()
locs = np.array(locs)
if len(locs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this condition is probably not necessary, but I guess it could also be anded onto line 955?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact it's probably needed, otherwise we may end up trying to get the first or last item of an empty array...

IMAGE_FORMAT = ['eps', 'jpg', 'png', 'ps', 'svg'] + ['bmp'] # , 'raw', 'rgb']
IMAGE_FORMAT.sort()
IMAGE_FORMAT_DEFAULT = 'png'
IMAGE_FORMAT = sorted(['eps', 'jpg', 'png', 'ps', 'svg'] + ['bmp']) # , 'raw', 'rgb']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just put 'bmp' at the front?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but I'll keep the sorted which makes the intent clear and should be cheap.

@@ -1652,55 +1638,48 @@ def pstoeps(tmpfile, bbox=None, rotated=False):
bbox_info, rotate = None, None

epsfile = tmpfile + '.eps'
with io.open(epsfile, 'wb') as epsh:
with io.open(epsfile, 'wb') as epsh, io.open(tmpfile, 'rb') as tmph:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we even need io. when it's binary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between io.open and open in Py2?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is one in binary mode, is there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess...
On the other hand there seems to be an awful lot use of temporary files in backend_ps, most of which could probably just get rewritten using pipes to communicate via the subprocesses' standard streams.
Another great cleanup project :-)

@@ -331,8 +328,7 @@ def _get_grid_bbox(self, renderer):

Only include those in the range (0,0) to (maxRow, maxCol)"""
boxes = [self._cells[pos].get_window_extent(renderer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the value is actually used here, it might make sense to use items() below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup

@@ -186,8 +186,8 @@ def set_params(self, **kwargs):
self.den = int(kwargs.pop("nbins"))

if kwargs:
raise ValueError("Following keys are not processed: %s" % \
", ".join([str(k) for k in kwargs.keys()]))
raise ValueError("Following keys are not processed: %s"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to remove this whole thing in #7545.

p0, p1 = edges[edgei]
p0, p1 = min(self.tunit_edges(),
key=lambda edge: proj3d.line2d_seg_dist(
edge[0], edge[1], (xd, yd)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to break after edge[1], but that's minor.

tis = (vecw[0] >= 0) * (vecw[0] <= 1) * (vecw[1] >= 0) * (vecw[1] <= 1)
if np.sometrue(tis):
tis = vecw[1] < 1
tis = (vecw[0] >= 0) & (vecw[0] <= 1) & (vecw[1] >= 0) & (vecw[1] <= 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're editing the line already, can you reorder it so that it looks like an implied and?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -28,7 +28,7 @@ def terminate(self):
def poll_draw(self):

def call_back():
while 1:
while True:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot this be while self.pipe.poll(): (and remove if not self.pipe.poll(): break below)?

while 1:

if len(remaining) == 0:
while True:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while args:?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup

if not self.figure.canvas.is_saving():
artists = [a for a in artists
if not a.get_animated() or a in self.images]
artists = sorted(artists, key=lambda artist: artist.get_zorder())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is not attrgetter faster than lambda?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt it matters but sure.

spec = datad[cmapname]
spec_reversed = _reverse_cmap_spec(spec)
datad[cmapname + '_r'] = spec_reversed
for cmapname, spec in list(six.iteritems(datad)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

list is redundant

Copy link
Contributor Author

@anntzer anntzer Dec 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No because we're modifying the dict at the same time; sidestepped the issue using update.

@@ -350,8 +346,7 @@ def contains(self, mouseevent):
renderer = self.figure._cachedRenderer
if renderer is not None:
boxes = [self._cells[pos].get_window_extent(renderer)
for pos in six.iterkeys(self._cells)
if pos[0] >= 0 and pos[1] >= 0]
for pos in self._cells if pos[0] >= 0 and pos[1] >= 0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I knew I should have commented the first time, but here's another one that could use items.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@NelleV
Copy link
Member

NelleV commented Dec 19, 2016

Can you rebase this PR?

@NelleV NelleV changed the title Cleanup: sorted, dict iteration, array.{ndim,size}, ... [MRG+1] Cleanup: sorted, dict iteration, array.{ndim,size}, ... Dec 19, 2016
style_list.sort()
style_list.insert(0, u'default')
style_list.insert(1, u'classic')
style_list = ['default', 'classic'] + sorted(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

line = fh.readline()
if not line:
break
for line in fh:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@anntzer
Copy link
Contributor Author

anntzer commented Dec 20, 2016

After Christmas break, probably.

@anntzer
Copy link
Contributor Author

anntzer commented Dec 21, 2016

Actually it wasn't that bad.

@QuLogic QuLogic changed the title [MRG+1] Cleanup: sorted, dict iteration, array.{ndim,size}, ... Cleanup: sorted, dict iteration, array.{ndim,size}, ... Dec 22, 2016
@QuLogic QuLogic merged commit 7131876 into matplotlib:master Dec 22, 2016
@anntzer anntzer deleted the cleanup-sorted branch December 23, 2016 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants