Skip to content

Implemented __copy__ in Colormap #8314

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

Closed
wants to merge 9 commits into from
Closed

Implemented __copy__ in Colormap #8314

wants to merge 9 commits into from

Conversation

vidursatija
Copy link
Contributor

I haven't tried executing. Only implemented copy in the Colormap class.
Issue #8299

@vidursatija
Copy link
Contributor Author

@phobson The code was kind of convoluted but the implementation wasn't that difficult

newCMapObj = cls.__new__(cls)
newCMapObj.__dict__.update(self.__dict__)
if self._isinit:
newCMapObj._lut = np.copy(self._lut)
Copy link
Member

Choose a reason for hiding this comment

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

Please use spaces instead of tabs

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'll update it

@tacaswell
Copy link
Member

Can you also add a test for this?

"""Create new object with the same class and update attributes
If object is initialized, copy the elements of _lut list
"""
cls = self.__class__
Copy link
Member

Choose a reason for hiding this comment

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

Is this really the best way to do this? It seems to be dropping down to a low layer of python.

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 low layer of python is presumably faster than the normal python code. Another way of doing this would be creating a normal Colormap object and manually copying each attribute.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How should I implement a test?

Copy link
Member

Choose a reason for hiding this comment

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

Get a color map, use it (cm([-1, 0, .5, 1, np.nan, np.inf]), copy it, use set_bad, set_over, set_under on one or both of them, use them both and check that the colors come back as expected.

Copy link
Member

Choose a reason for hiding this comment

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

I would not expect this to be much faster. If you think it is can you bench mark it?

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 will bench mark it and implement the tests. I'll post the results soon.

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 have bench marked the 2 functions.
The following code is used:

import matplotlib.pyplot as plt
import time

cm = plt.cm.Reds

start = time.time()
cm2 = cm.copy_1()     #Using low level python
end1 = time.time()
cm3 = cm.copy_2()     #Copying the attributes manually
end2 = time.time()
print("Method 1 :" + str(end1-start))
print("Method 2 :" + str(end2-end1))

I get the following output:
Method 1 :1.8358230590820312e-05
Method 2 :2.6941299438476562e-05

I can definitely say that using low level python functions would lead to a simpler, faster code, which might be a little difficult to understand by seeing it.

Test

I've used the copy_1 function to copy the object.

import numpy as np
import matplotlib.pyplot as plt

cm = plt.cm.Reds
cm([-1, 0, .5, np.nan, np.inf])

cm.set_bad('y')
cm2 = cm.copy_1()
cm2.set_bad('b')
print(cm._rgba_bad)
print(cm2._rgba_bad)

cm.set_under('y')
cm2.set_under('r')
print(cm._rgba_under)
print(cm2._rgba_under)

cm.set_over('c')
cm2.set_over('m')
print(cm._rgba_over)
print(cm2._rgba_over)

Output is as follows:
(0.75, 0.75, 0.0, 1)
(0.0, 0.0, 1.0, 1)
(0.75, 0.75, 0.0, 1)
(1.0, 0.0, 0.0, 1)
(0.0, 0.75, 0.75, 1)
(0.75, 0.0, 0.75, 1)

As we can see, using the function on both Colormaps doesn't change the other

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My last commit (3ece4cb) has used lower level python to implement copy. The code has also used spaces instead of tabs

@tacaswell
Copy link
Member

Timing a single execution like that is not reliable, those are differences in the us range, which can easily be fluctuations due to OS level scheduling, etc. I suggest using something like %timeit which will run each version many times and average them.

Before this change, that test would have passed (as the issue is that the _lut object was shared between them). You need to either look at _lut or test using the color map as I suggested above.

@vidursatija
Copy link
Contributor Author

The code used for benchmark is as follows :

import matplotlib.pyplot as plt
import timeit

cm = plt.cm.Reds

print(timeit.timeit(cm.copy_1))
print(timeit.timeit(cm.copy_2))

We get the following output :
2.1411431600026845
5.9614591380013735

The lower level python copy function works faster.

Test

The code used for test is as follows

import numpy as np
import matplotlib.pyplot as plt

cm = plt.cm.Reds
cm([-1, 0, .5, np.nan, np.inf])

cm.set_bad('y')
cm2 = cm.copy_1()
cm2.set_bad('b')

cm.set_under('k')
cm2.set_under('r')

cm.set_over('c')
cm2.set_over('m')

print(np.array_equal(cm._lut, cm2._lut))

We get the following output:
False

The test is succesful. The array _lut is not shared and the values are copied.

I'm sorry for the mistake in the previous test

@tacaswell
Copy link
Member

Can you put that test in the lib/matplotlib/tests/test_colors.py so it is run by the CI?

@vidursatija
Copy link
Contributor Author

While putting the test, should I use the numpy testing utility?

@vidursatija
Copy link
Contributor Author

I've used the numpy testing utility to implement the test

@vidursatija
Copy link
Contributor Author

The Travis CI build is failing due to some other reason. It passes the copy test. There are no indentation problems.

@vidursatija
Copy link
Contributor Author

@phobson please can you review this PR

Copy link
Member

@phobson phobson left a comment

Choose a reason for hiding this comment

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

This looks good to me, but some it is a bit over my head. @tacaswell should have the final word.

@vidursatija
Copy link
Contributor Author

@tacaswell please review it

cm2.set_under('r')
cm.set_over('c')
cm2.set_over('m')
assert_equal(np.array_equal(cm._lut, cm2._lut), False)
Copy link
Member

Choose a reason for hiding this comment

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

I am not a huge fan of this test, I would prefer

assert_array_equal(cm(data), expected1)
assert_array_equal(cm2(data), expected2)

As that is the thing thing we actually care about (not the details of the internal state). If we change how the color mapping works internally, this test might not cover what we think it covers.

@tacaswell
Copy link
Member

Can you please squash all of these commits into one commit with commit message that explains what is being fixed and why?

@tacaswell tacaswell added this to the 2.0.1 (next bug fix release) milestone Mar 23, 2017
@vidursatija
Copy link
Contributor Author

I deleted the old repository. I forked and solved the issue. That is one commit. For that we'll have to close this pull request and create a new one.

@vidursatija
Copy link
Contributor Author

I'm having problems. I deleted the forked repository. I still have the changed files but I can't merge them here. Should I create a new pull request and merge all of it in a single commit?

@NelleV
Copy link
Member

NelleV commented Mar 24, 2017

Closing in favor of #8375

@NelleV NelleV closed this Mar 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants