0

I want to color a log-log plot using an array of values in matplotlib. The array of values has the same shape as the data that is being plotted. I think what I want is best illustrated by the following example.

Here is the same concept, but plotted using the plt.scatter function:

y = np.empty([40, 2])
y[:, 0] = np.arange(40)
y[:,1] = y[:,0]**2
color = y[:,1]**3

plt.figure()
plt.scatter(y[:, 0], y[:,1], c=color, cmap='OrRd', norm=mpl.colors.LogNorm())
plt.xscale('log')
plt.yscale('log')
plt.colorbar()

The output of the above code is the following figure:

image

However, if I run the same code, using the plt.loglog function instead of plt.scatter, I get the following error:

ValueError: array([0.00000000e+00, 1.00000000e+00, 6.40000000e+01, 7.29000000e+02,
       4.09600000e+03, 1.56250000e+04, 4.66560000e+04, 1.17649000e+05,
       2.62144000e+05, 5.31441000e+05, 1.00000000e+06, 1.77156100e+06,
       2.98598400e+06, 4.82680900e+06, 7.52953600e+06, 1.13906250e+07,
       1.67772160e+07, 2.41375690e+07, 3.40122240e+07, 4.70458810e+07,
       6.40000000e+07, 8.57661210e+07, 1.13379904e+08, 1.48035889e+08,
       1.91102976e+08, 2.44140625e+08, 3.08915776e+08, 3.87420489e+08,
       4.81890304e+08, 5.94823321e+08, 7.29000000e+08, 8.87503681e+08,
       1.07374182e+09, 1.29146797e+09, 1.54480442e+09, 1.83826562e+09,
       2.17678234e+09, 2.56572641e+09, 3.01093638e+09, 3.51874376e+09]) is not a valid value for color

I understand that this means for some reason we cannot use vectors to color our line using plt.loglog. Is there a workaround for this so that I can have a continuous color change along my line in a log-log plot?

Thanks!!

Vitalizzare
  • 4,496
  • 7
  • 13
  • 32
  • I have submitted an answer, but I've received no feedback… Could you please tell me if my answer satisfies your needs or, at least, was useful in the solution of your problem? Thank you in advance. – gboffi Oct 22 '22 at 12:36
  • @gboffi sorry, yes your answer was exactly what I needed. Thanks so much! – Michael Ray Oct 23 '22 at 13:15

1 Answers1

0

These kind of things (manipulating individual segments of a curve) are usually done using a matplotlib.collections.LineCollection instance (see also the examples).

The code is commented, but if you need further explanation please comment under the answer and I will be notified.

enter image description here

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.collections import LineCollection
from matplotlib.colors import LogNorm

# Let's draw a parabola
x = np.linspace(1, 2, 101)
y = 2+(1-x)*(2-x)

# How do you build a line collection?
# ImportanceOfBeingErnest's answer is at
# https://stackoverflow.com/a/58880037/2749397
points = np.array([x, y]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
lc = LineCollection(
    segments,
    cmap='plasma', norm=LogNorm(), linewidth=4)

# Now we set the values that are going to be colormapped
# here just the ordinates
lc.set_array(y)

# We want loglog
fig, ax = plt.subplots()
ax.set_xscale('log')
ax.set_yscale('log')

# Let's plot our parabola with zero width, just to trigger the auto-scaling
plt.plot(x, y, lw=0)

# Add the line collection, the colorbar and finally display 
ax.add_collection(lc)
plt.colorbar(lc)
plt.show()
gboffi
  • 22,939
  • 8
  • 54
  • 85