TwoSlopeNorm in Matplotlib not working as expected - python

I am trying to create a plot with a diverging colour map which is not symmetric around zero
In this example, the DivergingNorm function is used and produces what I want...
I am using a later version of Matplotlib however (3.5.1) and when I use the suggested code in the link above, I get the following image...
import numpy as np
import matplotlib.pyplot as plt
data = np.random.random((10,10))
data = 10 * (data - 0.8)
fig, ax = plt.subplots()
im = ax.imshow(data, norm=matplotlib.colors.TwoSlopeNorm(0), cmap=plt.cm.seismic, interpolation='none')
fig.colorbar(im)
plt.show()
... which is clearly not right.
Does anyone know how I can reproduce this behaviour from DivergingNorm from older Matplotlib verions? I can't find a solution to this anywhere even though the older behaviour of 'DivergingNorm' is exactly what I want.
I get the same wrong behaviour using this example ---> https://stackoverflow.com/a/69707735/6288682
I should get this...
... but actually get...
Thanks!

Related

formatting to group of bars using matplotlib

I am trying to learn python mainly for plotting. Here is my sample code:
import numpy as np
import matplotlib.pyplot as plt
a=[[1,2,3,4],[2,3,4,5],[3,4,5,6]]
x=np.arange(len(a[0]))
width=0.2
fig, ax = plt.subplots(figsize=(8,6))
patterns=['/','\\','*']
for bar in a:
ax.bar(x,bar,width,edgecolor='black',color='lightgray', hatch=patterns.pop(0))
x=x+width
plt.show()
Now the problem is that, I need black edge colour for all bars as well as given hatch patter. However, the formatting is applied to first set of bars only. Here is my output. (I am using python3).
What's missing here or what's wrong? I have looked around but did not find any fix.
Update:
I have tried different options :python2, python3 and pdf/png. Here are results
python2 png --fine
python3 png -- shown above
python2 pdf -- see
python3 pdf -- see
I have also tried 'backend' as matplotlib.use('Agg'). I have update my matplotlib version (2.1.0).
There is a current issue in matplotlib 2.1 that only the first bar's edgecolor is applied. The same for the hatch, see this issue. Also see this question.
It may be that you are using matplotlib 2.1 for python3 but not for python2, hence in python2 it works for you. If I run your code in python 2 with matplotlib 2.1 I get the same undesired behaviour.
The issue will be fixed, once matplotlib 2.1.1 is released.
In the meantime, a workaround is to set the edgecolor and hatch on the individual bars:
import numpy as np
import matplotlib.pyplot as plt
a=[[1,2,3,4],[2,3,4,5],[3,4,5,6]]
x=np.arange(len(a[0]))
width=0.2
fig, ax = plt.subplots(figsize=(8,6))
patterns=['/','\\','*']
for y in a:
bars = ax.bar(x,y,width,color='lightgray')
hatch= patterns.pop(0)
for bar in bars:
bar.set_edgecolor("black")
bar.set_hatch(hatch)
x=x+width
plt.show()
It looks something's wrong with edgecolor tuple's alpha value. Set it to 1 will solve the problem.

Matplotlib: how do I know which colormap is being used?

I played around with colormaps, trying many of them, trying to make my own, both in matplotlib and seaborn.
However now I would like to know which colormap I am using. How can I do that? Is there a command like matplotlib.whichColormap ?
Usually there would be no need to find out the colormap you are using because you define that yourself. I.e. when calling
plt.imshow(..., cmap="viridis")
you already know that you are using "viridis".
If you still feel it would be useful to get that information from an existing ScalarMappable, you may use get_cmap() and it's name attribute:
import matplotlib.pyplot as plt
import numpy as np
a = np.random.rand(4,5)
fig, ax = plt.subplots()
im = ax.imshow(a, cmap="viridis")
cm = im.get_cmap()
print(cm.name) # prints viridis

Saving Python SymPy figures with a specific resolution/pixel density

I am wondering if there is a way to change the pixel density/resolution of sympy plots. For example, let's consider the simple code snippet below:
import sympy as syp
x = syp.Symbol('x')
miles_to_km = x * 1.609344
miles_to_km.evalf()
graph = syp.plot(miles_to_km, show=False)
graph.save('./figures/miles_to_km.png')
graph.show()
Notes:
When I tried using graph.savefig, I got an AttributeError: 'Plot' object has no attribute 'saveimage' I stumbled upon the saveimage method in some online resource, and it sounded like that this was the common approach -- I guess the API changed?
graph.save('./figures/miles_to_km.png', dpi=300) produces a type error: TypeError: save() got an unexpected keyword argument 'dpi'
Using the dpi attribute in plot does not throw any error but doesn't affect the image quality either: graph = syp.plot(miles_to_km, dpi=300, show=False)
I also tried using the matplotlib backend:
plt.figure()
graph = syp.plot(miles_to_km, show=False)
#graph.save('./figures/miles_to_km.png')
plt.savefig('./figures/miles_to_km.png')
graph.show()
where plt = matplotlib.pyplot. However, the canvas is blank. Also relevant info may be that I am running it in an IPython notebook with %matplotlib inline enabled.
I am using SymPy v. 0.7.6
the backend workaround below shows the plot in the IPython notebook, but it also produces a white canvas (as png)
graph = syp.plot(miles_to_km, show=False)
backend = graph.backend(graph)
backend.fig.savefig('ch01_2.png', dpi=300)
backend.show()
EDIT and Solution:
Thanks to Cody Piersall's answer the issue is now resolved. I updated to IPython 4.0 (Jupyter notebook) and plotted it as follows
graph = syp.plot(miles_to_km, show=False)
backend = graph.backend(graph)
backend.process_series()
backend.fig.savefig('miles_to_km.png', dpi=300)
backend.show()
This problem has been fixed, you can now simply use this:
graph = sympy.plot(f, show = False)
graph.save('fig.png')
Unfortunately, it doesn't seem to allow for the selection of a dpi.
Assuming you are using the matplotlib backend, which is the default if you have matplotlib installed, you just have to import matplotlib.pyplot and use pyplot.savefig.
This works because sympy uses matplotlib to do its plotting, and since matplotlib is stateful, it knows which plot you're working with.
Here is your example, but using savefig to save to a png.
import sympy as syp
x = syp.Symbol('x')
miles_to_km = x * 1.609344
miles_to_km.evalf()
graph = syp.plot(miles_to_km, show=False)
# Does not work in IPython Notebook, but works in a script.
import matplotlib.pyplot as plt
plt.savefig('./figures/miles_to_km.png', dpi=300)
If you are in an IPython notebook, the above will not work, but you can still save them with a specified dpi. You just have to be a little tricky about it.
# works in IPython Notebook
backend = graph.backend(graph)
ackend.fig.savefig('300.png', dpi=300)
backend.fig.savefig('20.png', dpi=20)

How do I set the aspect ratio for a plot in Python with Spyder?

I'm brand new to Python, I just switched from Matlab. The distro is Anaconda 2.1.0 and I'm using the Spyder IDE that came with it.
I'm trying to make a scatter plot with equal ratios on the x and y axes, so that this code prints a square figure with the vertices of a regular hexagon plotted inside.
import numpy
import cmath
import matplotlib
coeff = [1,0,0,0,0,0,-1]
x = numpy.roots(coeff)
zeroplot = plot(real(x),imag(x), 'ro')
plt.gca(aspect='equal')
plt.show()
But plt.gca(aspect='equal') returns a blank figure with axes [0,1,0,1], and plt.show() returns nothing.
I think the main problem is that plt.gca(aspect='equal') doesn't just grab the current axis and set its aspect ratio. From the documentation, (help(plt.gca)) it appears to create a new axis if the current one doesn't have the correct aspect ratio, so the immediate fix for this should be to replace plt.gca(aspect='equal') with:
ax = plt.gca()
ax.set_aspect('equal')
I should also mention that I had a little bit of trouble getting your code running because you're using pylab to automatically load numpy and matplotlib functions: I had to change my version to:
import numpy
import cmath
from matplotlib import pyplot as plt
coeff = [1,0,0,0,0,0,-1]
x = numpy.roots(coeff)
zeroplot = plt.plot(numpy.real(x), numpy.imag(x), 'ro')
ax = plt.gca()
ax.set_aspect('equal')
plt.show()
People who are already comfortable with Python don't generally use Pylab, from my experience. In future you might find it hard to get help on things if people don't realise that you're using Pylab or aren't familiar with how it works. I'd recommend disabling it and trying to get used to accessing the functions you need through their respective modules (e.g. using numpy.real instead of just real)

Combining mayavi and matplotlib in the same figure

I will be making animations. In each frame I want to contain both a mayavi plot obtained with
mlab.pipeline.iso_surface(source, some other superfluous args)
and a matplotlib plot obtained using simply
pylab.plot(args)
I have scripts to do both separately, but have no idea how to go about combining them into one figure. I want the end product to be one script which contains the code from both the scripts that I currently have.
AFAIK, there is no direct way because the backends used are so different. It does not seem possible to add matplotlib axes to mayavi.figure or vice versa.
However, there is a "kind of a way" by using the the mlab.screenshot.
import mayavi.mlab as mlab
import matplotlib.pyplot as plt
# create and capture a mlab object
mlab.test_plot3d()
img = mlab.screenshot()
mlab.close()
# create a pyplot
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax1.plot([0,1], [1,0], 'r')
# add the screen capture
ax2 = fig.add_subplot(122)
ax2.imshow(img)
ax2.set_axis_off()
This is not necessarily the nicest possible way of doing things, and you may bump into resolution problems, as well (check the size of the mayavi window). However, it gets the job done in most cases.
Adding to the answer by DrV which helped me a great deal, you can work with the mlab figure to set resolution before screenshot such as with batch plotting:
mfig = mlab.figure(size=(1024, 1024))
src = mlab.pipeline.scalar_field(field_3d_numpy_array)
mlab.pipeline.iso_surface(src)
iso_surface_plot = mlab.screenshot(figure=mfig, mode='rgba', antialiased=True)
mlab.clf(mfig)
mlab.close()
# Then later in a matplotlib fig:
plt.imshow(iso_surface_plot)

Categories

Resources