75

I have the following data set. I would like to use Python or Gnuplot to plot the data. The tuples are of the form (x, y). The Y-axis should be a log axis, that is, log(y). A scatter plot or line plot would be ideal.

How can this be done?

 [(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08), 
 (2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09), 
 (4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]
nbro
  • 15,395
  • 32
  • 113
  • 196
olliepower
  • 1,269
  • 2
  • 11
  • 17

6 Answers6

116

If I get your question correctly, you could do something like this.

>>> import matplotlib.pyplot as plt
>>> testList =[(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08), 
 (2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09), 
 (4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]
>>> from math import log
>>> testList2 = [(elem1, log(elem2)) for elem1, elem2 in testList]
>>> testList2
[(0, -16.617236475334405), (1, -17.67799605473062), (2, -18.691431541177973), (3, -18.9767093108359), (4, -19.420021520728017), (5, -19.298411635970396)]
>>> zip(*testList2)
[(0, 1, 2, 3, 4, 5), (-16.617236475334405, -17.67799605473062, -18.691431541177973, -18.9767093108359, -19.420021520728017, -19.298411635970396)]
>>> plt.scatter(*zip(*testList2))
>>> plt.show()

which would give you something like

enter image description here

Or as a line plot,

>>> plt.plot(*zip(*testList2))
>>> plt.show()

enter image description here

EDIT - If you want to add a title and labels for the axis, you could do something like

>>> plt.scatter(*zip(*testList2))
>>> plt.title('Random Figure')
>>> plt.xlabel('X-Axis')
>>> plt.ylabel('Y-Axis')
>>> plt.show()

which would give you

enter image description here

Sukrit Kalra
  • 33,167
  • 7
  • 69
  • 71
  • 1
    OP asked was unclear whether wanting log axis on y or wanting y-coordinates to be log(y_data). You could use `plt.semilogy()` instead of `plt.plot()`. – Bennett Brown Feb 21 '14 at 01:39
  • 7
    For those that don't know, the * reverses the zip -- unzip, if you will. – knockNrod Apr 08 '19 at 20:53
  • 3
    I'd never seen anything like this use of 'star'... which lead me to: "Where in the python documentation is * explained?" https://stackoverflow.com/questions/12555627/python-3-starred-expression-to-unpack-a-list – poleguy Mar 12 '22 at 00:25
  • 1
    @knockNrod: If "*the \* reverses the zip*", then why use `*zip(...)` which in this case is just the identity? – mins Jan 16 '23 at 12:12
30

In matplotlib it would be:

import matplotlib.pyplot as plt

data =  [(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08),
 (2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09),
 (4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]

x_val = [x[0] for x in data]
y_val = [x[1] for x in data]

print x_val
plt.plot(x_val,y_val)
plt.plot(x_val,y_val,'or')
plt.show()

which would produce:

enter image description here

K DawG
  • 13,287
  • 9
  • 35
  • 66
19

As others have answered, scatter() or plot() will generate the plot you want. I suggest two refinements to answers that are already here:

  1. Use numpy to create the x-coordinate list and y-coordinate list. Working with large data sets is faster in numpy than using the iteration in Python suggested in other answers.

  2. Use pyplot to apply the logarithmic scale rather than operating directly on the data, unless you actually want to have the logs.

    import matplotlib.pyplot as plt
    import numpy as np
    
    data = [(2, 10), (3, 100), (4, 1000), (5, 100000)]
    data_in_array = np.array(data)
    '''
    That looks like array([[     2,     10],
                           [     3,    100],
                           [     4,   1000],
                           [     5, 100000]])
    '''
    
    transposed = data_in_array.T
    '''
    That looks like array([[     2,      3,      4,      5],
                           [    10,    100,   1000, 100000]])
    '''    
    
    x, y = transposed 
    
    # Here is the OO method
    # You could also the state-based methods of pyplot
    fig, ax = plt.subplots(1,1) # gets a handle for the AxesSubplot object
    ax.plot(x, y, 'ro')
    ax.plot(x, y, 'b-')
    ax.set_yscale('log')
    fig.show()
    

result

I've also used ax.set_xlim(1, 6) and ax.set_ylim(.1, 1e6) to make it pretty.

I've used the object-oriented interface to matplotlib. Because it offers greater flexibility and explicit clarity by using names of the objects created, the OO interface is preferred over the interactive state-based interface.

Bennett Brown
  • 5,234
  • 1
  • 27
  • 35
  • What If I want to show the vertical line for each x-value like a very narrow bar (up to the height of y-value) such that the plot would look like a discrete and colored1-d histogram? – Rebel May 11 '20 at 00:02
  • Ash, matplotlib has a separate method for adding a bargraph to an axes, and you would call that instead of `plot`. Post this as a question rather than a comment to an answer to an unrelated question, unless maybe i'm misunderstanding why your question is related to this one. – Bennett Brown Jun 15 '20 at 04:54
19

You could also use zip

import matplotlib.pyplot as plt

l = [(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08),
     (2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09),
     (4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]

x, y = zip(*l)

plt.plot(x, y)
  • Isn't this exactly the same thing as the solution in the answer accepted 4 years prior to this answer? – natiiix Dec 14 '21 at 19:27
  • It's similar, but this answer is very succinct. It also isn't unnecessarily fancy since it doesn't use * where x,y suffice. Unfortunately it doesn't answer all parts of the question. It still gets my vote. – poleguy Mar 12 '22 at 00:29
2

With gnuplot using gplot.py

from gplot import *

l = [(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08), 
 (2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09), 
 (4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]

gplot.log('y')
gplot(*zip(*l))

enter image description here

0

Can also be done with Pandas.

import pandas as pd
data = [(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08), 
        (2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09), 
        (4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]

pd.DataFrame(data, columns=['l','v']).set_index('l').plot(kind='line');

enter image description here

Cam
  • 1,263
  • 13
  • 22