I have a lot of different files (10-20) that I read in x and y data from, then plot as a line.
At the moment I have the standard colors but I would like to use a colormap instead.
I have looked at many different examples but can't get the adjustment for my code right.
I would like the colour to change between each line (rather than along the line) using a colormap such as gist_rainbow i.e. a discrete colourmap
The image below is what I can currently achieve.
This is what I have attempted:
import pylab as py
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc, rcParams
numlines = 20
for i in np.linspace(0,1, numlines):
color1=plt.cm.RdYlBu(1)
color2=plt.cm.RdYlBu(2)
# Extract and plot data
data = np.genfromtxt('OUZ_QRZ_Lin_Disp_Curves')
OUZ_QRZ_per = data[:,1]
OUZ_QRZ_gvel = data[:,0]
plt.plot(OUZ_QRZ_per,OUZ_QRZ_gvel, '--', color=color1, label='OUZ-QRZ')
data = np.genfromtxt('PXZ_WCZ_Lin_Disp_Curves')
PXZ_WCZ_per = data[:,1]
PXZ_WCZ_gvel = data[:,0]
plt.plot(PXZ_WCZ_per,PXZ_WCZ_gvel, '--', color=color2, label='PXZ-WCZ')
# Lots more files will be plotted in the final code
py.grid(True)
plt.legend(loc="lower right",prop={'size':10})
plt.savefig('Test')
plt.show()
You could take a few different approaches. On your initial example you color each line specifically with a different color. That works fine if you are able to loop over the data/colors you want to plot. Manually assigning each color, like you do now, is a lot of work, even for 20 lines, but imagine if you have hundred or more. :)
Matplotlib also allows you to edit the default 'color cycle' with your own colors. Consider this example:
numlines = 10
data = np.random.randn(150, numlines).cumsum(axis=0)
plt.plot(data)
This gives the default behavior, and results in:
If you want to use a default Matplotlib colormap, you can use it to retrieve the colors values.
# pick a cmap
cmap = plt.cm.RdYlBu
# get the colors
# if you pass floats to a cmap, the range is from 0 to 1,
# if you pass integer, the range is from 0 to 255
rgba_colors = cmap(np.linspace(0,1,numlines))
# the colors need to be converted to hexadecimal format
hex_colors = [mpl.colors.rgb2hex(item[:3]) for item in rgba_colors.tolist()]
You can then assign the list of colors to the color cycle setting from Matplotlib.
mpl.rcParams['axes.color_cycle'] = hex_colors
Any plot made after this change will automatically cycle through these colors:
plt.plot(data)
Related
I've spent too much time looking into this, some tabs still open in my browser:
Link1 Link2 Link3 Link4
I'm supposed to be working!
Anyway, my problem is: I use someone else's scripts to produce lots of heat maps which I then have to review and sort/assign:
Here's an example of one:
HM sample
I need to be able to easily distinguish a 0.03 from a zero but as you can see they look virtually the same. Ideal solution would be: White(just zero's)-Yellow-Orange-Red or White(just zero's)-Orange-Red
The dev used 'YlOrRd' like so:
sns.heatmap(heat_map, annot=True, fmt=".2g", cmap="YlOrRd", linewidths=0.5,
linecolor='black', xticklabels=xticks, yticklabels=yticks
)
I've tried a bunch of the standard/default colour map options provided to no avail.
I don't have any real experience building colour maps and I don't want break something that's already working. Would anyone have any ideas?
Thanks
**I'm limited in what code/samples I can post due to it being work product.
An option is to take the colors from an existing colormap, replace the first one by white and create a new colormap from those manipulated values.
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
import matplotlib.colors
import seaborn as sns
# some data
a = np.array([0.,0.002,.005,.0099,0.01,.0101,.02,.04,.24,.42,.62,0.95,.999,1.])
data = np.random.choice(a, size=(12,12))
# create colormap. We take 101 values equally spaced between 0 and 1
# hence the first value 0, second value 0.01
c = np.linspace(0,1,101)
# For those values we store the colors from the "YlOrRd" map in an array
colors = plt.get_cmap("YlOrRd",101)(c)
# We replace the first row of that array, by white
colors[0,:] = np.array([1,1,1,1])
# We create a new colormap with the colors
cmap = matplotlib.colors.ListedColormap(colors)
# Plot the heatmap. The format is set to 4 decimal places
# to be able to disingush specifically the values ,.0099, .0100, .0101,
sns.heatmap(data, annot=True, fmt=".4f", cmap=cmap, vmin=0, vmax=1,
linewidths=0.5, linecolor='black')
plt.show()
I tried to make a plot showing many lines, but it is hard to tell them apart. They have different colors, but I would like to make it easy to show which line is which. A normal legend does not really work so well, since I have more than 10 lines.
The lines follow a logical sequence. I would like to (1) have their color automatically chosen from a colormaps (preferably one that has a smooth ordering, such as viridis or a rainbow). Then I would like (2) to have the tick marks next to the color bar to correspond to the index i for each line (or better a text label from an array of strings textlabels[i]).
Here's a minimal piece of code (with some gaps where I am not sure what to use). I hope this illustrates what I am trying.
import numpy as np
import matplotlib.pyplot as plt
# Genereate some values to plot on the x-axis
x = np.linspace(0,1,1000)
# Some code to select a (discrete version of) a rainbow/viridis color map
...
# Loop over lines that should appear in the plot
for i in range(0,9):
# Plot something (using straight lines with different slope as example)
plt.plot(i*x)
# Some code to plot a discrete color bar next
# to the plot with ticks showing the value of i
...
I currently have this. I would like the color bar to have the ticks with values of i, i.e. 0, 1, 2, ... next to it as tick marks.
Example figure of what I have now. It is hard to tell the lines apart now.
One gets a colormap via plt.get_cmap("name of cmap", number_of_colors).
This colormap can be used to compute the colors for the plots. It can also be used to generate a colorbar.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
n = 10 # how many lines to draw or number of discrete color levels
x = np.linspace(0,1,17)
cmap = plt.get_cmap("viridis", n)
for i in range(0,n):
plt.plot(i*x, color=cmap(i))
norm= matplotlib.colors.BoundaryNorm(np.arange(0,n+1)-0.5, n)
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
plt.colorbar(sm, ticks=np.arange(0,n))
plt.show()
Here is my question.
When I want use a lot of colormap, I could use
CMAP = ["summer_r", "brg_r", "Dark2", "prism", "PuOr_r", "afmhot_r", "terrain_r", "PuBuGn_r", "RdPu", \
"gist_ncar_r", "gist_yarg_r", "Dark2_r", "YlGnBu", "RdYlBu", "hot_r"]
## value was a 3-d array, the first dimension represent the amount of 2-d array with the value (0, 1).
## I just plot the value 1 for each value[i,:,:]
for i in range(0,len(CMAP),1):
plt.pcolor(xx,yy,value[i,:,:], cmap = CMAP[i])
And I can get this:
http://i8.tietuku.com/cdcdcd5f539c124b.png
But I can't clearly realize the each grid's color befor generating the figure.
Because some colormap which I add in CMAP may have the same start color. SO, some value[ i, :, :] grids will be hard to distinguish.
My idea
Using one colormap instead and split into single color for each value[ i, :, :]. So, each value grid has a different color.
For example:
## 1. cut the colormap, take "jet" for example
cMap = plt.cm.get_cmap("jet",lut=6)
http://i4.tietuku.com/be127c44e87a03fc.png
## 2. I havn't figured it out
## This is the fake code
CMAP = Func[one color -> colormap](cMap)
Update -2016-01-18
This is my code to set different cmap and loop, but it was a bit of rigid.
cmap1 = colors.ListedColormap(["w",'red'])
cmap2 = colors.ListedColormap(["w",'blue'])
cmap3 = colors.ListedColormap(["w",'yellow'])
CMAP = [cmap1,cmap2,cmap3]
Then, I can cope with my original attempt.
But I was wondering is there a smart way to generate the cmap1,cmap2,......?
The hard part of this is coming up with N distinctive colors. In practice, it's usually easiest to just grab random colors as long as N is small. If you'd prefer a bit nicer way of getting N distinct colors, have a look at how seaborn's husl_palette and hsl_palette are implemented. They choose N evenly spaced colors in HSL/HUSL space and convert it back to RGB.
At any rate, there are two parts to tying specific values to specific colors in matplotlib. One is the colormap and the other is the norm. The Normalize instance (the norm) handles transforming the data ranges into a 0-1 space for the colormap.
There's a function to make this use-case easier:matplotlib.colors.from_levels_and_colors. It returns a cmap and norm instance that you can pass in to imshow/pcolormesh/scatter/etc.
As a stand-alone example, let's generate data with a random number of unique integer values. We'll use random pastel colors instead of trying to do something fancy.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import from_levels_and_colors
nvals = np.random.randint(2, 20)
data = np.random.randint(0, nvals, (10, 10))
colors = np.random.random((nvals, 3))
# Make the colors pastels...
colors = colors / 2.5 + 0.55
levels = np.arange(nvals + 1) - 0.5
cmap, norm = from_levels_and_colors(levels, colors)
fig, ax = plt.subplots()
im = ax.imshow(data, interpolation='nearest', cmap=cmap, norm=norm)
fig.colorbar(im, ticks=np.arange(nvals))
plt.show()
Not the nicest looking color palette, but it's not awful. Here's another run:
Even with 17 values, we're still getting fairly distinct colors by choosing random values.
I have 3 vectors - x,y,vel each having some 8k values. I also have quite a few files containing these 3 vectors. All the files have different x,y,vel. I want to get multiple scatter plots with the following conditions:
Color coded according to the 3rd variable i.e vel.
Once the ranges have been set for the colors (for the data from the 1st file), they should remain constant for all the remaining files. i don't want a dynamically changing (color code changing with each new file).
Want to plot a colorbar.
I greatly appreciate all your thoughts!!
I have attached the code for a single file.
import numpy as np
import matplotlib.pyplot as plt
# Create Map
cm = plt.cm.get_cmap('RdYlBu')
x,y,vel = np.loadtxt('finaldata_temp.txt', skiprows=0, unpack=True)
vel = [cm(float(i)/(8000)) for i in xrange(8000)] # 8000 is the no. of values in each of x,y,vel vectors.
# 2D Plot
plt.scatter(x, y, s=27, c=vel, marker='o')
plt.axis('equal')
plt.savefig('testfig.png', dpi=300)
plt.show()
quit()
You will have to iterate over all your data files to get the maximum value for vel, I have added a few lines of code (that need to be adjusted to fit your case) that will do that.
Therefore, your colorbar line has been changed to use the max_vel, allowing you to get rid of that code using the fixed value of 8000.
Additionally, I took the liberty to remove the black edges around the points, because I find that they 'obfuscate' the color of the point.
Lastly, I have added adjusted your plot code to use an axis object, which is required to have a colorbar.
import numpy as np
import matplotlib.pyplot as plt
# This is needed to iterate over your data files
import glob
# Loop over all your data files to get the maximum value for 'vel'.
# You will have to adjust this for your code
"""max_vel = 0
for i in glob.glob(<your files>,'r') as fr:
# Iterate over all lines
if <vel value> > max_vel:
max_vel = <vel_value>"""
# Create Map
cm = plt.cm.get_cmap('RdYlBu')
x,y,vel = np.loadtxt('finaldata_temp.txt', skiprows=0, unpack=True)
# Plot the data
fig=plt.figure()
fig.patch.set_facecolor('white')
# Here we switch to an axis object
# Additionally, you can plot several of your files in the same figure using
# the subplot option.
ax=fig.add_subplot(111)
s = ax.scatter(x,y,c=vel,edgecolor=''))
# Here we assign the color bar to the axis object
cb = plt.colorbar(mappable=s,ax=ax,cmap=cm)
# Here we set the range of the color bar based on the maximum observed value
# NOTE: This line only changes the calculated color and not the display
# 'range' of the legend next to the plot, for that we need to switch to
# ColorbarBase (see second code snippet).
cb.setlim(0,max_vel)
cb.set_label('Value of \'vel\'')
plt.show()
Snippet, demonstrating ColorbarBase
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
cm = plt.cm.get_cmap('RdYlBu')
x = [1,5,10]
y = [2,6,9]
vel = [7,2,1]
# Plot the data
fig=plt.figure()
fig.patch.set_facecolor('white')
ax=fig.add_subplot(111)
s = ax.scatter(x,y,c=vel,edgecolor=''))
norm = mpl.colors.Normalize(vmin=0, vmax=10)
ax1 = fig.add_axes([0.95, 0.1, 0.01, 0.8])
cb = mpl.colorbar.ColorbarBase(ax1,norm=norm,cmap=cm,orientation='vertical')
cb.set_clim(vmin = 0, vmax = 10)
cb.set_label('Value of \'vel\'')
plt.show()
This produces the following plot
For more examples of what you can do with the colorbar, specifically the more flexible ColorbarBase, I would suggest that you check the documentation -> http://matplotlib.org/examples/api/colorbar_only.html
I've an array that includes decent observations, irrelevant observations (that I would like to mask out), and areas where there are no observations (that i would also like to mask out). I want to display this array as an image (using pylab.imshow) with two separate masks, where each mask is shown in a different colour.
I've found code for a single mask (here) in a certain colour, but nothing for two different masks:
masked_array = np.ma.array (a, mask=np.isnan(a))
cmap = matplotlib.cm.jet
cmap.set_bad('w',1.)
ax.imshow(masked_array, interpolation='nearest', cmap=cmap)
If possible, I'd like to avoid having to use a heavily distorted colour map but accept that that is an option.
You might simply replace values in you array with some fixed value depending on some conditions. For example, if you want to mask elements larger than 1 and smaller than -1:
val1, val2 = 0.5, 1
a[a<-1]= val1
a[a>1] = val2
ax.imshow(a, interpolation='nearest')
val1 and val2 can be modified to obtain colors you wish.
You can also set the colors explicitly, but it requires more work:
import matplotlib.pyplot as plt
from matplotlib import colors, cm
a = np.random.randn(10,10)
norm = colors.normalize()
cmap = cm.hsv
a_colors = cmap(norm(a))
col1 = colors.colorConverter.to_rgba('w')
col2 = colors.colorConverter.to_rgba('k')
a_colors[a<-0.1,:] = col1
a_colors[a>0.1,:] = col2
plt.imshow(a_colors, interpolation='nearest')
plt.show()
For me the simplest way is plotting directly the masks with imshow, passing different colormaps. Max and min of a colormap are used for True and False values:
mask1=np.isnan(a)
mask2=np.logical_not(mask1)
plt.imshow(mask1,cmap='gray')
plt.imshow(mask2,cmap='rainbow')
However this (and other approaches suggested) plot also False values overplotting previous plots. If you want to avoid plotting False values, it can be done by replacing them with np.nan, after converting the array to float (np.nan is of type float and cannot be contained in a boolean mask). nan values are not plotted:
mmm=mask.astype(np.float)
mmm[np.where(mmm==0)]=np.nan
#the substitution can be done also in one line with:
#mmm=np.where(mask,mask.astype(np.float),np.nan)
plt.imshow(mmm,cmap='rainbow',vmin=0,vmax=1)) #will use only the top color: red. vmin and vmax are needed if there are only one value (1.0=True) in the array.
plt.colorbar()
#repeat for other masks...
And i hope I am not going too much off topic, but same technique can be used to plot different part of the data with different colormaps, by replacing the plotting command with:
plt.imshow(mmm*data,cmap='rainbow')
In order to color some pixels red and others green, as appears in the the following image, I used the code below. (See code comments for details.)
import numpy as np #Used for holding and manipulating data
import numpy.random #Used to generate random data
import matplotlib as mpl #Used for controlling color
import matplotlib.colors #Used for controlling color as well
import matplotlib.pyplot as plt #Use for plotting
#Generate random data
a = np.random.random(size=(10,10))
#This 30% of the data will be red
am1 = a<0.3 #Find data to colour special
am1 = np.ma.masked_where(am1 == False, am1) #Mask the data we are not colouring
#This 10% of the data will be green
am2 = np.logical_and(a>=0.3,a<0.4) #Find data to colour special
am2 = np.ma.masked_where(am2 == False, am2) #Mask the data we are not colouring
#Colourmaps for each special colour to place. The left-hand colour (black) is
#not used because all black pixels are masked. The right-hand colour (red or
#green) is used because it represents the highest z-value of the mask matrices
cm1 = mpl.colors.ListedColormap(['black','red'])
cm2 = mpl.colors.ListedColormap(['black','green'])
fig = plt.figure() #Make a new figure
ax = fig.add_subplot(111) #Add subplot to that figure, get ax
#Plot the original data. We'll overlay the specially-coloured data
ax.imshow(a, aspect='auto', cmap='Greys', vmin=0, vmax=1)
#Plot the first mask. Values we wanted to colour (`a<0.3`) are masked, so they
#do not show up. The values that do show up are coloured using the `cm1` colour
#map. Since the range is constrained to `vmin=0, vmax=1` and a value of
#`cm2==True` corresponds to a 1, the top value of `cm1` is applied to all such
#pixels, thereby colouring them red.
ax.imshow(am1, aspect='auto', cmap=cm1, vmin=0, vmax=1);
ax.imshow(am2, aspect='auto', cmap=cm2, vmin=0, vmax=1);
plt.show()
I don't know what the values are in your array, but you could convert the masked areas so that the X values become RGB(A) values (tuples of (R,G,B,A)), in which case the cmap is ignored, according to the documentation at least.
• cmap: [ None | Colormap ]
A matplotlib.colors.Colormap instance, eg. cm.jet. If None, default to
rc image.cmap value. cmap is ignored when X has RGB(A) information