I have been trying to do a simple heatmap with pcolormesh and I run into this weird effect with some sizes, which add empty white columns. If I create a 10x30, as below, it works perfectly.
from matplotlib import pyplot as plt
import numpy as np
d = []
for x in range(10):
d.append([])
for y in range(30):
d[-1].append(y)
plt.pcolormesh(np.array(d))
plt.show()
But, if I try with a 10x37:
from matplotlib import pyplot as plt
import numpy as np
d = []
for x in range(10):
d.append([])
for y in range(34):
d[-1].append(y)
plt.pcolormesh(np.array(d))
plt.show()
I got those weird white columns at the end. This seems to hold for a couple of values (10x11 fails, but 10x12 works... I wasn't able to discerna pattern.
Is there any way to remove them, maybe forcing the final size of the heatmap?
In terms of axes limits and aspect ratio, pcolormesh acts less like an image, and more like a line plot. If you want to show the elements of an array as pixels, you can use imshow. Alternatively, you can set the x-limits of your pcolormesh plot. Consider the following example:
from matplotlib import pyplot as plt
import numpy as np
d1 = []
d2 = []
for x in range(10):
d1.append([])
d2.append([])
for y in range(30):
d1[-1].append(y+x)
for y in range(37):
d2[-1].append(y+x)
fig, axes = plt.subplots(ncols=4, figsize=(10,4))
# your first two examples
axes[0].pcolormesh(np.array(d1), cmap=plt.cm.coolwarm)
axes[1].pcolormesh(np.array(d2), cmap=plt.cm.coolwarm)
# let's reset the x-lims on this
axes[2].pcolormesh(np.array(d2), cmap=plt.cm.coolwarm)
axes[2].set_ylim(bottom=0, top=d2.shape[0])
axes[2].set_xlim(left=0, right=d2.shape[1])
# or more concisely (thanks Joe):
axes[2].axis('tight')
# and use imshow here
axes[3].imshow(np.array(d2), cmap=plt.cm.coolwarm)
and that gives us:
Related
Lets say I've 2 arrays
x = [1,2,3,4,5,6,7]
y = [1,2,2,2,3,4,5]
its scatter plot looks like this
what I want to do is that I want my x axis to look like this in the plot
0,4,8
as a result of which values of y in each piece of x should come closer .
The similar behavior I've seen is bar plots where this is called clustering , how do I do the same in case of scatter plot , or is there any other plot I should be using ?
I hope my question is clear/understandable .
All the help is appreciated
With you plot, try this, before you display the plot.
plt.xticks([0,4,8]))
or
import numpy as np
plt.xticks(np.arange(0, 8+1, step=4))
Then to change the scale you can try something like this,
plt.xticks([0,4,8]))
plt.rcParams["figure.figsize"] = (10,5)
I got this with my example,
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 30)
y = np.sin(x)
plt.xticks([0,4,8])
plt.rcParams["figure.figsize"] = (7,3)
plt.plot(x, y, 'o', color='black')
output
I think what you are looking for is close to swarmplots and stripplots in Seaborn. However, Seaborn's swarmplot and stripplot are purely categorical on one of the axes, which means that they wouldn't preserve the relative x-axis order of your elements inside each category.
One way to do what you want would be to increase the space in your x-axis between categories ([0,4,8]) and modify your xticks accordingly.
Below is an example of this where I assign the data to 3 different categories: [-2,2[, [2,6[, [6,10[. And each bar is dil_k away from its directly neighboring bars.
import matplotlib.pyplot as plt
import numpy as np
#Generating data
x= np.random.choice(8,size=(100))
y= np.random.choice(8,size=(100))
dil_k=20
#Creating the spacing between categories
x[np.logical_and(x<6, x>=2)]+=dil_k
x[np.logical_and(x<10, x>=6)]+=2*dil_k
#Plotting
ax=plt.scatter(x,y)
#Modifying axes accordingly
plt.xticks([0,2,22,24,26,46,48,50],[0,2,2,4,6,6,8,10])
plt.show()
And the output gives:
Alternatively, if you don't care about keeping the order of your elements along the x-axis inside each category, then you can use swarmplot directly.
The code can be seen below:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
#Generating data
x= np.random.choice(8,size=(100))
y= np.random.choice(8,size=(100))
#Creating the spacing between categories
x[np.logical_and(x<2,x>=-2)]=0
x[np.logical_and(x<6, x>=2)]=4
x[np.logical_and(x<10, x>=6)]=8
#Plotting
sns.swarmplot(x=x,y=y)
plt.show()
And the output gives:
I have written following code,
import numpy as np
import matplotlib.pyplot as plt
x=np.random.randint(0,10,[1,5])
y=np.random.randint(0,10,[1,5])
x.sort(),y.sort()
fig, ax=plt.subplots(figsize=(10,10))
ax.plot(x,y)
ax.set( title="random data plot", xlabel="x",ylabel="y")
I am getting a blank figure.
Same code prints chart if I manually assign below value to x and y and not use random function.
x=[1,2,3,4]
y=[11,22,33,44]
Am I missing something or doing something wrong.
x=np.random.randint(0,10,[1,5]) returns an array if you specify the shape as [1,5]. Either you would want x=np.random.randint(0,10,[1,5])[0] or x=np.random.randint(0,10,size = 5). See: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.random.randint.html
Matplotlib doesn't plot markers by default, only a line. As per #Can comment, matplotlib then interprets your (1, 5) array as 5 different datasets each with 1 point, so there is no line as there is no second point.
If you add a marker to your plot function then you can see the data is actually being plotted, just probably not as you wish:
import matplotlib.pyplot as plt
import numpy as np
x=np.random.randint(0,10,[1,5])
y=np.random.randint(0,10,[1,5])
x.sort(),y.sort()
fig, ax=plt.subplots(figsize=(10,10))
ax.plot(x,y, marker='.') # <<< marker for each point added here
ax.set( title="random data plot", xlabel="x",ylabel="y")
My program produces two arrays and I have to plot one of them in the X axis and the other one on the Y axis (the latter are taken from the row of a matrix).
The problem is that I have to repeat this operation for a number of times (I am running a loop) but all the graphs should be on the same plot. Every time the dots should be of a different colour. Then I should save the file.
I have tried with
for row in range(6):
plt.plot(betaArray, WabArray[row], 'ro')
plt.show()
but this only shows one plot each for every iteration and always of the same colour.
You could try something like this:
import numpy as np
import matplotlib.pylab as plt
import matplotlib as mpl
x = [1,2,3,4]
y_mat = np.array([[1,2,3,4], [5,6,7,8]])
n, _ = y_mat.shape
colors = mpl.cm.rainbow(np.linspace(0, 1, n))
fig, ax = plt.subplots()
for color, y in zip(colors, y_mat):
ax.scatter(x, y, color=color)
plt.show()
This creates n colors from the rainbow color map and uses scatter to plot the points in the respective color. You may want to switch to a different color map or even choose the colors manually.
This is the result:
I am plotting 20 different lines on a single plot using matplotlib. I use a for loop for plotting and label every line with its key and then use the legend function
for key in dict.keys():
plot(x,dict[key], label = key)
graph.legend()
But using this way, the graph repeats a lot of colors in the legend. Is there any way to ensure a unique color is assigned to each line using matplotlib and over 20 lines?
thanks
The answer to your question is related to two other SO questions.
The answer to How to pick a new color for each plotted line within a figure in matplotlib? explains how to define the default list of colors that is cycled through to pick the next color to plot. This is done with the Axes.set_color_cycle method.
You want to get the correct list of colors though, and this is most easily done using a color map, as is explained in the answer to this question: Create a color generator from given colormap in matplotlib. There a color map takes a value from 0 to 1 and returns a color.
So for your 20 lines, you want to cycle from 0 to 1 in steps of 1/20. Specifically you want to cycle form 0 to 19/20, because 1 maps back to 0.
This is done in this example:
import matplotlib.pyplot as plt
import numpy as np
NUM_COLORS = 20
cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_prop_cycle(color=[cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
ax.plot(np.arange(10)*(i+1))
fig.savefig('moreColors.png')
plt.show()
This is the resulting figure:
Alternative, better (debatable) solution
There is an alternative way that uses a ScalarMappable object to convert a range of values to colors. The advantage of this method is that you can use a non-linear Normalization to convert from line index to actual color. The following code produces the same exact result:
import matplotlib.pyplot as plt
import matplotlib.cm as mplcm
import matplotlib.colors as colors
import numpy as np
NUM_COLORS = 20
cm = plt.get_cmap('gist_rainbow')
cNorm = colors.Normalize(vmin=0, vmax=NUM_COLORS-1)
scalarMap = mplcm.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = fig.add_subplot(111)
# old way:
#ax.set_prop_cycle(color=[cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
# new way:
ax.set_prop_cycle(color=[scalarMap.to_rgba(i) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
ax.plot(np.arange(10)*(i+1))
fig.savefig('moreColors.png')
plt.show()
I had a plot with 12 lines, and I found it hard to distinguish lines with similar colours when I tried Yann's technique. My lines also appeared in pairs, so I used the same colour for the two lines in each pair, and used two different line widths. You could also vary the line style to get more combinations.
You could use set_prop_cycle(), but I just modified the line objects after calling plot().
Here is Yann's example with three different line widths:
import matplotlib.pyplot as plt
import numpy as np
NUM_COLORS = 20
cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
lines = ax.plot(np.arange(10)*(i+1))
lines[0].set_color(cm(i//3*3.0/NUM_COLORS))
lines[0].set_linewidth(i%3 + 1)
fig.savefig('moreColors.png')
plt.show()
Here's the same example with different line styles. Of course you could combine the two if you wanted.
import matplotlib.pyplot as plt
import numpy as np
NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)
cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
lines = ax.plot(np.arange(10)*(i+1))
lines[0].set_color(cm(i//NUM_STYLES*float(NUM_STYLES)/NUM_COLORS))
lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])
fig.savefig('moreColors.png')
plt.show()
To build off of Don Kirkby's answer, if you're willing to install/use seaborn, then you can have colors computed for you:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)
sns.reset_orig() # get default matplotlib styles back
clrs = sns.color_palette('husl', n_colors=NUM_COLORS) # a list of RGB tuples
fig, ax = plt.subplots(1)
for i in range(NUM_COLORS):
lines = ax.plot(np.arange(10)*(i+1))
lines[0].set_color(clrs[i])
lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])
fig.savefig('moreColors.png')
plt.show()
Aside from being able to use seaborn's various color palettes, you can get a list of RGB tuples that can be used/manipulated later on if need be. Obviously, you could compute something similar using matplotlib's colormaps, but I find this to be handy.
These answers seemed more complicated than needed. If you are looping through a list to plot lines, then just enumerate on the list and assig color to some point on the colormap. Say you are looping through all the columns from a pandas dataframe:
fig, ax = plt.subplots()
cm = plt.get_cmap('gist_rainbow')
for count, col in enumerate(df.columns):
ax.plot(df[col], label = col, linewidth = 2, color = cm(count*20))
This works because cm is just an iterable dictionary of color numerics. Multiplying those by some factor gets you further along in the colormap (more difference in color).
I have separate arrays of x and y coordinates, and a z-array of corresponding values. I wish to make a plot that has squares at each x and y coordinate that have colours set from the z array - something similar to this. I have searched quite hard on google to find how I can do this, but to no avail. The matplotlib.pyplot.scatter function needs the color array scaled from 0-1, so I can't see how that could be used in this circumstance. Any help is much appreciated.
Thanks Andrew. I see how that works now. The thing is my z-array is just one column of numbers. Since they are not in any sensible order, it would be difficult to just re-shape the array into 2D to use pcolor.
I have come up with a much better solution using a for loop to append rectangle patches to a patch collection, then assign a colour map to the whole collection and plot.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
import matplotlib.patches as mpatches
fig = plt.figure(figsize=(9,5))
ax = plt.axes([0.1,0.1,0.7,0.7])
cmap = matplotlib.cm.jet
patches = []
data=np.array([4.5,8.6,2.4,9.6,11.3])
data_id_nos=np.array([5,6,9,8,7])
x_coords=np.array([3.12,2.6,2.08,1.56,1.04])
y_coords=np.array([6.76,6.24,5.72,5.20,4.68])
coord_id_nos=np.array([7,9,6,5,8])
for i in range(len(data_id_nos)):
coords=(x_coords[np.where(coord_id_nos == data_id_nos[i])],y_coords[np.where(coord_id_nos == data_id_nos[i])])
art = mpatches.Rectangle(coords,0.50,0.50,ec="none")
patches.append(art)
#create collection of patches for IFU position
IFU1 = PatchCollection(patches, cmap=cmap)
#set the colours = data values
IFU1.set_array(np.array(data))
ax.add_collection(IFU1)
plt.axis('scaled')
plt.xlabel('x (arcsecs)')
plt.ylabel('y (arcsecs)')
I guess you want pcolor, as shown here.
You need to do something like this
x = np.arange(10)
y = np.arange(10)
z = np.zeros([10,10])
z[1,5] = 10
z[2,7] = 20
z[3,9] = 30
pcolor(x,y,z)
with this precise code the last point will be off the axis, but it should give you the idea.