scatter plot with single pixel marker in matplotlib

user2532296 picture user2532296 · Sep 28, 2016 · Viewed 9.2k times · Source

I am trying to plot a large dataset with a scatter plot. I want to use matplotlib to plot it with single pixel marker. It seems to have been solved.

https://github.com/matplotlib/matplotlib/pull/695

But I cannot find a mention of how to get a single pixel marker.

My simplified dataset (data.csv)

Length,Time
78154393,139.324091
84016477,229.159305
84626159,219.727537
102021548,225.222662
106399706,221.022827
107945741,206.760239
109741689,200.153263
126270147,220.102802
207813132,181.67058
610704756,50.59529
623110004,50.533158
653383018,52.993885
659376270,53.536834
680682368,55.97628
717978082,59.043843

My code is below.

import pandas as pd
import os
import numpy
import matplotlib.pyplot as plt

inputfile='data.csv'
iplevel = pd.read_csv(inputfile)
base = os.path.splitext(inputfile)[0]

fig = plt.figure()
plt.yscale('log')
#plt.xscale('log')
plt.title(' My plot:  '+base)
plt.xlabel('x')
plt.ylabel('y')
plt.scatter(iplevel['Time'], iplevel['Length'],color='black',marker=',',lw=0,s=1)
fig.tight_layout()
fig.savefig(base+'_plot.png', dpi=fig.dpi)

You can see below that the points are not single pixel.

data_plot.png

Any help is appreciated

Answer

ImportanceOfBeingErnest picture ImportanceOfBeingErnest · Sep 29, 2016

The problem

I fear that the bugfix discussed at matplotlib git repository that you're citing is only valid for plt.plot() and not for plt.scatter()

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(4,2))
ax = fig.add_subplot(121)
ax2 = fig.add_subplot(122, sharex=ax, sharey=ax)
ax.plot([1, 2],[0.4,0.4],color='black',marker=',',lw=0, linestyle="")
ax.set_title("ax.plot")
ax2.scatter([1,2],[0.4,0.4],color='black',marker=',',lw=0, s=1)
ax2.set_title("ax.scatter")
ax.set_xlim(0,8)
ax.set_ylim(0,1)
fig.tight_layout()
print fig.dpi #prints 80 in my case
fig.savefig('plot.png', dpi=fig.dpi)

enter image description here

The solution: Setting the markersize

The solution is to use a usual "o" or "s" marker, but set the markersize to be exactly one pixel. Since the markersize is given in points, one would need to use the figure dpi to calculate the size of one pixel in points. This is 72./fig.dpi.

  • For aplot`, the markersize is directly

    ax.plot(..., marker="o", ms=72./fig.dpi)
    
  • For a scatter the markersize is given through the s argument, which is in square points,

    ax.scatter(..., marker='o', s=(72./fig.dpi)**2)
    

Complete example:

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(4,2))
ax = fig.add_subplot(121)
ax2 = fig.add_subplot(122, sharex=ax, sharey=ax)
ax.plot([1, 2],[0.4,0.4], marker='o',ms=72./fig.dpi, mew=0, 
        color='black', linestyle="", lw=0)
ax.set_title("ax.plot")
ax2.scatter([1,2],[0.4,0.4],color='black', marker='o', lw=0, s=(72./fig.dpi)**2)
ax2.set_title("ax.scatter")
ax.set_xlim(0,8)
ax.set_ylim(0,1)
fig.tight_layout()
fig.savefig('plot.png', dpi=fig.dpi)

enter image description here