# Using an Arduino and Python to Plot/save Data

34,173

67

6

Published

## Introduction: Using an Arduino and Python to Plot/save Data

A quick and easy way to see (and then save) data taken using an Arduino onto your computer.

(Note: not the most robust method, but it works well enough)

Materials:
-  Arduino (I’m using an Uno)
-  Computer (I have a Dell, but it shouldn’t really matter if you are running Windows. Otherwise, you’ll need to make some minor edits to the Python code.)
-  Python, including the matplotlib, pyserial, and numpy extensions
https://pypi.python.org/pypi/pyserial (pyserial)
- Some sort of sensor/input device (I’m using an ADXL335 accelerometer)

## Step 1: Wiring the Circuit

This accelerometer is extremely simple to use. It is powered off of 5VDC and each output pin (X, Y, Z) gives an analog voltage from 0-3V depending on the measured acceleration. To power it, simply connect the 5V output pin and one of the GND pins of the Arduino to the Vin pin and GND pin on the accelerometer. The X, Y, and Z pins go to any three of the analog input pins on the Arduino (I used A1, A2, and A3).

You can leave the setup like this, but the analog pins on the Arduino range from 0-5V, while the accelerometer ranges from 0-3V. This means that you will only be using about half of the range of possible analog values and will have less precision in your measurements. Ideally, the ranges would be the same so the full range of analog values is available.

The Arduino range can be changed by connecting a new reference voltage to the AREF pin and signifying in the code that the analog reference is external (see step 2). I didn't care too much about precision, so I just used the 3.3V output on the Arduino as my reference voltage, but the 3V output on the accelerometer should work as well.

## Step 2: Arduino Code

The Arduino simply reads in the values on all three analog pins and sends them over serial to the computer. Tabs are added between the data to make it easier to read on the computer side.

The only setup required (other than declaring variables) is to create the serial connection at a baud rate of 9600 and declare the analog reference to be external, as mentioned earlier.

{{{

/*
This code reads in values on analog pins A1-A3 and sends the values
over serial. The outputs can be checked using the serial monitor.

created 03/18/14
*/
const int xpin = A3;                  // x-axis
const int ypin = A2;                  // y-axis
const int zpin = A1;                  // z-axis

void setup()
{
Serial.begin(9600);                 //setup serial connection
analogReference(EXTERNAL);          //set external reference point for analog pins
}

void loop()
{
Serial.print("\t");                 //send a "tab" over serial
Serial.print("\t");
Serial.println();                   //ends the line of serial communication

delay(100);
}

}}}

## Step 3: Python Code

The Python code reads the incoming serial data, and separates each line along the tabs, giving you separate values for the X, Y, and Z data. Some processing is done to put the values into their own variables.

To plot the variables, the “matplotlib” library is used to create an animated graph. This results in a reasonably accurate “live feed”, but large amounts of sensor activity will cause the graph to lag a bit.

Finally, the data is saved to a .txt file in a specified location. The data can then be read back when needed using the numpy.loadtxt() function (see next step for code). However, this file type is most easily read in Python, so if you want to open the data in a different program you’ll need to use a different write function. (ex. Use .csv file format to open data in Excel) Don't forget to change the file location to match your computer's directory.

See the code for more detailed comments (or Google or ask and I’ll do my best to explain or point you to an explanation)

{{{

'''
Reads in data over a serial connection and plots the results live. Before closing, the data is saved to a .txt file.
'''

import serial
import matplotlib.pyplot as plt
import numpy as np
import win32com.client

connected = False

#finds COM port that the Arduino is on (assumes only one Arduino is connected)
wmi = win32com.client.GetObject("winmgmts:")
for port in wmi.InstancesOf("Win32_SerialPort"):
#print port.Name #port.DeviceID, port.Name
if "Arduino" in port.Name:
comPort = port.DeviceID
print comPort, "is Arduino"

ser = serial.Serial(comPort, 9600) #sets up serial connection (make sure baud rate is correct - matches Arduino)

while not connected:
connected = True

plt.ion()                    #sets plot to animation mode

length = 500                 #determines length of data taking session (in data points)
x = [0]*length               #create empty variable of length of test
y = [0]*length
z = [0]*length

xline, = plt.plot(x)         #sets up future lines to be modified
yline, = plt.plot(y)
zline, = plt.plot(z)
plt.ylim(400,700)        #sets the y axis limits

for i in range(length):     #while you are taking data
data = ser.readline()    #reads until it gets a carriage return. MAKE SURE THERE IS A CARRIAGE RETURN OR IT READS FOREVER
sep = data.split()      #splits string into a list at the tabs
#print sep

x.append(int(sep[0]))   #add new value as int to current list
y.append(int(sep[1]))
z.append(int(sep[2]))

del x[0]
del y[0]
del z[0]

xline.set_xdata(np.arange(len(x))) #sets xdata to new list length
yline.set_xdata(np.arange(len(y)))
zline.set_xdata(np.arange(len(z)))

xline.set_ydata(x)                 #sets ydata to new list
yline.set_ydata(y)
zline.set_ydata(z)

plt.pause(0.001)                   #in seconds
plt.draw()                         #draws new plot

rows = zip(x, y, z)                  #combines lists together

row_arr = np.array(rows)               #creates array from list

ser.close() #closes serial connection (very important to do this! if you have an error partway through the code, type this into the cmd line to close the connection)

}}}

## Step 4: Results

This is just the most basic plot - you can easily add axes labels, legend, etc. using matplotlib (just Google for it). I simply rotated the X axis to +/-1g for this test. When it's running, the plot will update constantly to show live movement.

## Step 5: Reading Back the Data

To read back the data saved with numpy.savetxt(), you use numpy.loadtxt() and assign it to a variable. The variable can then be manipulated and re-plotted (in my case, I have the "markers" option set so I can see the individual data points).

{{{
'''
Reads and plots data from a .txt file
'''

import matplotlib.pyplot as plt
import numpy as np

#load values from file into "data"

#create empty lists for data to be sorted into
x = []
y = []
z = []

#for each line in data, sort it into the appropriate list
for dat in data:
x.append(dat[0])
y.append(dat[1])
z.append(dat[2])

#plot each list then show the plot
plt.plot(x, marker = 'o')
plt.plot(y, marker = 'o')
plt.plot(z, marker = 'o')
plt.show()

}}}

## Recommendations

• ### Arduino Class

70,822 Enrolled

## 6 Discussions

Ignore the previous post: Here is the problem with this (much appreciated to get me going) code: The Python and Arduino codes are NOT synchronized, so any one of the three different sets of data can be read by the Python code as the first set, depending on the timing. The solution is to reset the Arduino and uses a HANDSHAKE to synchronize the Aruino writes with the Python reads. This link shows you how: https://github.com/fortruce/fortruce.github.io/bla...

Beware, it is Python 2 (setting the DTR line is different in 3, amongst other things). With a proper handshake you can eliminate the "while not connected".

Ah-ha! The not so robust comment refers to the use of the plot object plt. As the code is written, data from previous runs is not destroyed on exiting the program, leading to funny behavior. This is cured by a plt.close() right after the for loop that does the plotting.

Thank you so much for this. I have just started learning Python, and was having a terrible time with the pyserial commands, which work, but only sort-of/some of the time for Arduino to Python communication. You say that this is not the most robust method, but it works reliably for me.

Hi Beaconsfield. I really hope this will also work by displaying data from a previous list while plotting a live feed over the top on the same graph! If it does I owe you a large drink.