Using a Colormap with lineplot in matplotlib - python

I'm very new to python and matplotlib, and I want to create a plot with different colored lines. I know I have to use a colormap, but I'm not sure how. So I have a for loop:
for i in range(len(params)):
centers,fN = graph.createHistogram(values = NHI[i])
for j in range(len(centers)):
if params[i]!=fidVal:
vals[j] = (np.log10(origfNHI[j]/fN[j]))/(fidVal-params[i])
plt.plot(centers,vals)
I want to give each line different colors based on the difference between the value of params[i] and fidVal. If fidVal - params[i] is a negative large number, I want the line to be very red, and if it is a negative small number, I want it to be not as red. Similarly if fidVal - params[i] is positive, I want it to be blue based on that value. Finally, I want the colors to be mapped on a colorbar which would be displayed on the plot.
Alternatively, is there a way I can specify the rgb color of a line when I use plt.plot()? Like, could I say plt.plot(centers,vals,Color(0,0,0))?
What code should I use to solve this problem?

I will answer about the colormap. You can use the karg color for specify an rgb color with a tuple... It's well explained in the documentation.
"In addition, you can specify colors in many weird and wonderful ways, including full names ('green'), hex strings ('#008000'), RGB or RGBA tuples ((0,1,0,1)) or grayscale intensities as a string ('0.8'). Of these, the string specifications can be used in place of a fmt group, but the tuple forms can be used only as kwargs."
Here you have a very simple example:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,1,1000)
n=50
for i in range(1,n):
y = i/float(n)*x**2
plt.plot(x,y,color=(i/float(n),(i/float(n))**4,(i/float(n))**2))
ax = plt.gca()
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
plt.show()

Related

Matplotlib 'cmap' vs 'c' issue

I want to plot some impedance values and task and code are both simple. xhertz_df is a pandas dataframe and after conversion to a numpy array xhertz[0]is the real part, xhertz[1]the imaginary part and xhertz[3]represents the time between measurements.
def xhertz_plot(xhertz_df):
ax = plt.gca()
xhertz = xhertz_df.T.to_numpy()
ax.plot(xhertz[3], xhertz[0], 'green')
ax.plot(xhertz[3], xhertz[1], 'blue')
ax.scatter(xhertz[3], xhertz[0], cmap ='green')
ax.scatter(xhertz[3], xhertz[1], cmap ='blue')
ax.set_xlabel('Time Passed (in Minutes)')
plt.show()
I'm confused as to what can go wrong with this code as it seems so simple. Yet I get this result:
The upper line and points is a mix of blue and green even though it should be just green. The lower line that should be only blue has orange (?!) points. What is going on here?
Edit:
I found the problem: I used cmap instead of just c for the scatter plot. But to someone with expertise in both concepts: Why did I get the result shown above? E.g. where did the orange come from?
As stated in the docs for Axes.scatter:
A Colormap instance or registered colormap name. cmap is only used if c is an array of floats.
Since you did not provide a list of floats for the arg c, matplotlib ignored your cmap and instead used the first and second default colors (blue, then orange).
If you just want a single color, note the docs for the c argument:
If you wish to specify a single color for all points prefer the color keyword argument.
Alternatively, you can just use Axes.plot with o for the marker style, instead of scatter, e.g. ax.plot(x, y, 'o', color='green') or equivalently ax.plot(x, y, 'og'). This is more typical for simple plots; you can use - or o to explicitly set a line plot or marker plot.
Note that cmap is generally intended to be used if you want a different color for each point, like if you wanted to color the points to represent another dimension of data. In that case c would represent that third dimension of data, norm would scale the data, and cmap would be what colors are mapped to that data. See the scatter demo 2 from matplotlib for an example of how that argument is usually used.

How to style/format point markers in Plotly 3D scatterplot?

I am unsure how to customize scatterplot marker styles in Plotly scatterplots.
Specifically, I have a column predictions that is 0 or 1 (1 represents an unexpected value) and even though I used the symbol parameter in px.scatter_3d to indicate the unexpected value through varying point shape (diamond for 1 and circle for 0), the difference is very subtle and I want it to be more dramatic. I was envisioning something like below (doesn't need to be exactly this), but something along the lines of the diamond shaped points have a different outline colors or an additional shape/bubble around it. How would I do this?
Additionally, I have a set column which can take on one of two values, set A or set B. I used the color parameter inside px.scatter_3d and made that equal to set so the points are colored according to which set it came from. While it is doing what I asked, I don't want the colors to be blue and red, but any two colors I specify. How would I be able to this (let's say I want the colors to be blue and orange instead)? Thank you so much!
Here is the code I used:
fig = px.scatter_3d(X_combined, x='x', y='y', z='z',
color='set', symbol='predictions', opacity=0.7)
fig.update_traces(marker=dict(size=12,
line=dict(width=5,
color='Black')),
selector=dict(mode='markers'))
You can use multiple go.Scatter3d() statements and gather them in a list to format each and every segment or extreme values more or less exactly as you'd like. This can be a bit more demanding than using px.scatter_3d(), but it will give you more control. The following plot is produced by the snippet below:
Plot:
Code:
import plotly.graph_objects as go
import numpy as np
import pandas as pd
# sample data
t = np.linspace(0, 10, 50)
x, y, z = np.cos(t), np.sin(t), t
# plotly data
data=[go.Scatter3d(x=[x[2]], y=[y[2]], z=[z[2]],mode='markers', marker=dict(size=20), opacity=0.8),
go.Scatter3d(x=[x[26]], y=[y[26]], z=[z[26]],mode='markers', marker=dict(size=30), opacity=0.3),
go.Scatter3d(x=x, y=y, z=z,mode='markers')]
fig = go.Figure(data)
fig.show()
How you identify the different segmens, whether it be max or min values will be entirely up to you. Anyway, I hope this approach will be useful!

Matplotlib cmap only showing grey

I'm plot with matplotlib on python using 'tab20' color map with the following code:
colors=[str(float(year-1980)/(2017-1980)) for i in years];
fig,ax = plt.subplots()
ax.scatter(Topic[:,0],Topic[:,1],c=colors,cmap='tab20')
but the plot I get is completely grey. What could be the reason?
By passing a list of strings to c in your ax.scatter call, you're telling matplotlib to treat them as color format strings. Since the strings look like they represent floats, it treats them as grayscale values. If you pass a list of floats instead, it should use the colormap correctly:
colors = [float((year-1980)/(2017-1980)) for year in years]
See the docs for more details, in particular:
cmap : Colormap, optional, default: None
A Colormap instance or registered name. cmap is only used if c is an
array of floats.
(Also, you don't need the ; after your first line.)
Solved by using
colors=[cm.RdYlBu(float(year-1980)/(2017-1980)) for i in years];
because I need to convert the float number to the colormap I wanted to use.

How to control the cell size of a pyplot pcolor heatmap?

I have a pair of lists of numbers representing points in a 2-D space, and I want to represent the y/x ratios for these points as a 1-dimensional heatmap, with a diverging color map centered around 1, or the logs of my ratios, with a diverging color map centered around 0.
How do I do that?
My current attempt (borrowing somewhat from Heatmap in matplotlib with pcolor?):
from matplotlib import numpy as np
import matplotlib.pyplot as plt
# There must be a better way to generate arrays of random values
x_values = [np.random.random() for _ in range(10)]
y_values = [np.random.random() for _ in range(10)]
labels = list("abcdefghij")
ratios = np.asarray(y_values) / np.asarray(x_values)
axis = plt.gca()
# I transpose the array to get the points arranged vertically
heatmap = axis.pcolor(np.log2([ratios]).T, cmap=plt.cm.PuOr)
# Put labels left of the colour cells
axis.set_yticks(np.arange(len(labels)) + 0.5, minor=False)
# (Not sure I get the label order correct...)
axis.set_yticklabels(labels)
# I don't want ticks on the x-axis: this has no meaning here
axis.set_xticks([])
plt.show()
Some points I'm not satisfied with:
The coloured cells I obtain are horizontally-elongated rectangles. I would like to control the width of these cells and obtain a column of cells.
I would like to add a legend for the color map. heatmap.colorbar = plt.colorbar() fails with RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).
One important point:
matplotlib/pyplot always leaves me confused: there seems to be a lot of ways to do things and I get lost in the documentation. I never know what would be the "clean" way to do what I want: I welcome suggestions of reading material that would help me clarify my very approximative understanding of these things.
Just 2 more lines:
axis.set_aspect('equal') # X scale matches Y scale
plt.colorbar(mappable=heatmap) # Tells plt where it should find the color info.
Can't answer your final question very well. Part of it is due to we have two branches of doing things in matplotlib: the axis way (axis.do_something...) and the MATLAB clone way plt.some_plot_method. Unfortunately we can't change that, and it is a good feature for people to migrate into matplotlib. As far as the "Clean way" is concerned, I prefer to use whatever produces the shorter code. I guess that is inline with Python motto: Simple is better than complex and Readability counts.

Matplotlib : quiver and imshow superimposed, how can I set two colorbars?

I have a figure that consists of an image displayed by imshow(), a contour and a vector field set by quiver(). I have colored the vector field based on another scalar quantity. On the right of my figure, I have made a colorbar(). This colorbar() represents the values displayed by imshow() (which can be positive and negative in my case). I'd like to know how I could setup another colorbar which would be based on the values of the scalar quantity upon which the color of the vectors is based. Does anyone know how to do that?
Here is an example of the image I've been able to make. Notice that the colors of the vectors go from blue to red. According to the current colorbar, blue means negative. However I know that the quantity represented by the color of the vector is always positive.
Simply call colorbar twice, right after each plotting call. Pylab will create a new colorbar matching to the latest plot. Note that, as in your example, the quiver values range from 0,1 while the imshow takes negative values. For clarity (not shown in this example), I would use different colormaps to distinguish the two types of plots.
import numpy as np
import pylab as plt
# Create some sample data
dx = np.linspace(0,1,20)
X,Y = np.meshgrid(dx,dx)
Z = X**2 - Y
Z2 = X
plt.imshow(Z)
plt.colorbar()
plt.quiver(X,Y,Z2,width=.01,linewidth=1)
plt.colorbar()
plt.show()
Running quiver doesn't necessarily return the type of mappable object that colorbar() requires. I think it might be because I explicitly "have colored the vector field based on another scalar quantity" like Heimdall says they did. Therefore, Hooked's answer didn't work for me.
I had to create my own mappable for the color bar to read. I did this by using Normalize from matplotlib.colors on the data that I wanted to use to color my quiver vectors (which I'll call C, which is an array of the same shape as X, Y, U, and V.)
My quiver call looks like this:
import matplotlib.pyplot as pl
import matplotlib.cm as cm
import matplotlib.colors as mcolors
import matplotlib.colorbar as mcolorbar
pl.figure()
nz = mcolors.Normalize()
nz.autoscale(C)
pl.quiver(X, Y, U, V, color=cm.jet(nz(C)))
cax,_ = mcolorbar.make_axes(pl.gca())
cb = mcolorbar.ColorbarBase(cax, cmap=cm.jet, norm=nz)
cb.set_label('color data meaning')
Giving any other arguments to the colorbar function gave me a variety of errors.

Categories

Resources