Multiple plots on pdf with matplotlib - python

I've been fighting with pyplot for few days now. I want to return a pdf report with 4 samples on each page. 4 inline subplots for each: text with the name and some statistics, and 3 graphs of values vs time. I found a tutorial online and tried it (see below) but it gives nothing. the pdf is empty. I can't find where it is wrong.
Thank you in advance !
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
t=[n*5 for n in range(len(ratio))]
y_list_ratio=[[x*100/l[3]for x in l[2]]for l in hit_ratio]
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
pp = PdfPages('multipage.pdf')
# Generate the pages
nb_plots = len(hit_ratio)
nb_plots_per_page = 4
nb_pages = int(numpy.ceil(nb_plots / float(nb_plots_per_page)))
grid_size = (nb_plots_per_page, 4)
for i, elt in enumerate(hit_ratio):
# Create a figure instance (ie. a new page) if needed
if i % nb_plots_per_page == 0:
plt = plt.figure(figsize=(8.27, 11.69), dpi=100)
# Plot stuffs !
plt.subplot2grid(grid_size, (i % nb_plots_per_page, 0))
plt.text(0.5,0.5,"Puit Hauteur_pic Digitonine\n"+ \
str(elt[-1])+" "+str(elt[5])+" "+str(elt[6]),horizontalalignment='center',verticalalignment='center', bbox=props)
plt.subplot2grid(grid_size, (i % nb_plots_per_page, 1))
plt.plot(t,hit_norm[i][0])
plt.subplot2grid(grid_size, (i % nb_plots_per_page, 2))
plt.plot(t,y_list_ratio[i])
plt.subplot2grid(grid_size, (i % nb_plots_per_page, 3))
plt.plot(t,elt[7])
plt.plot(t,elt[8])
# Close the page if needed
if (i + 1) % nb_plots_per_page == 0 or (i + 1) == nb_plots:
fig2.tight_layout()
pp.savefig(fig2)
# Write the PDF document to the disk
pp.close()

Since you don't have any answers yet, I have an alternate suggestion:
Try ReportLab.
from reportlab.lib import colors, utils
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter, landscape
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Image, PageBreak, KeepTogether
from reportlab.lib.styles import ParagraphStyle as PS
from reportlab.lib.enums import TA_CENTER
from reportlab.platypus.paragraph import Paragraph
landscape_pic_width = 8
letter_pic_width = 6
....
def get_image(path, width=1*inch):
#'''returns an image for adding to report'''
img = utils.ImageReader(path)
iw, ih = img.getSize()
aspect = ih / float(iw)
return Image(path, width=width, height=(width * aspect))
def plot_stuff():
#whatever you want to plot, finish with saving the figure
elements = [] #this is a list that will contain the items to be included in the report
report_title = str(report_title)
c_table = Table(Conditions_Table_data)
c_table.setStyle(TableStyle([('ALIGN', (0,0),(-1,-1),'CENTER'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0),(-1,-1), 2, colors.blueviolet), ('SIZE', (0,0),(-1,-1), 10), ('SPAN',(-3,3),(-1,3))]))
#tells it how to format the table
#puts in the logo, the assigned report title, the entered report title, the conditions table, and the setup picture
elements.append(get_image(logo_picture, width = 9*inch))
elements.append(Paragraph(document_title, PS(name='Heading1', spaceAfter = 22, fontName = 'Times-Bold', fontSize = 18, alignment = TA_CENTER)))
#you can append items to the list "elements" with a for loop.
doc = SimpleDocTemplate(path_plus_title + ".pdf", pagesize=landscape(letter))
#creates the report. Will throw an error if the report exists and is already open. Otherwise, will generate a report
#this WILL overwrite an existing report with the same name. Timestamps being forced into the data file names help.
doc.build(elements)
There's definitely sections missing from this code...but these are the items I import ("inch", for instance, is a value for sizing that you multiply by the number of inches you want for that dimension)
You basically build a list of the items that go into your report pdf in the order they go in. For each element, there's some style setting that takes place. You can include text (Paragraphs), tables (it's a "list of lists" with each list being a row), and images.

Related

How to tile matplotlib figures evenly on screen?

Does matplotlib offer a feature to spread multiple figures evenly on the screen? Or does anyone know of a toolbox that is able to achieve this? I'm getting tired of doing this by hand.
import matplotlib.pyplot as plt
for i in range(5):
plt.figure()
plt.show()
This creates five figures that are staying on top of each other. To check what is on figure 1, I have to move the other 4 figures to the side.
On MacOS, I could use the Ctrl+↓ shortcut just to get a glimpse on all the figures. Alternatively, I could write the plots to files and inspect the images in a gallery. But I wondered if there is a custom window manager for matplotlib out there that possibly offers some more flexibility.
In Matlab, I got used to tools such as spreadfigure or autoArrangeFigures.
You can control the position of the plot window using the figure manager like so:
import matplotlib.pyplot as plt
start_x, start_y, dx, dy = (0, 0, 640, 550)
for i in range(5):
if i%3 == 0:
x = start_x
y = start_y + (dy * (i//3) )
plt.figure()
mngr = plt.get_current_fig_manager()
mngr.window.setGeometry(x, y, dx, dy)
x += dx
plt.show()
This will result in five graphs shown beside each other like so:
Hopefully, this is what you're looking for!
It appears that matplotlib does not offer such a feature out-of-the-box. In addition, there is no "backend-agnostic" way to control the figure geometry, as discussed here.
I therefore wrote tile_figures() to implement this mini-feature extending Anwarvic's suggestion by some tiling logic and a simple backend abstraction. It currently supports only Qt- or Tk-backends, but it certainly can be extended to other backends as well.
Happy tiling!
Usage
tile_figures(cols=3, rows=2, screen_rect=None, tile_offsets=None)
# You may have to adjust the available screen area and a tile offset
# for nice results. This works well for my MacOS.
tile_figure(screen_rect=(0,22,1440,740), tile_offsets=(0,22))
# Run a test with 10 figures. Note that you cannot switch the backend dynamically.
# It's best to set mpl.use(<backend>) at the very beginning of your script.
# https://matplotlib.org/faq/usage_faq.html#what-is-a-backend
test(n_figs=10, backend="Qt5Agg", screen_rect=(0,22,1440,750), tile_offsets=(0,22))
Result
Implementation
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def screen_geometry(monitor=0):
try:
from screeninfo import get_monitors
sizes = [(s.x, s.y, s.width, s.height) for s in get_monitors()]
return sizes[monitor]
except ModuleNotFoundError:
default = (0, 0, 900, 600)
print("screen_geometry: module screeninfo is no available.")
print("Returning default: %s" % (default,))
return default
def set_figure_geometry(fig, backend, x, y, w, h):
if backend in ("Qt5Agg", "Qt4Agg"):
fig.canvas.manager.window.setGeometry(x, y, w, h)
#fig.canvas.manager.window.statusBar().setVisible(False)
#fig.canvas.toolbar.setVisible(True)
elif backend in ("TkAgg",):
fig.canvas.manager.window.wm_geometry("%dx%d+%d+%d" % (w,h,x,y))
else:
print("This backend is not supported yet.")
print("Set the backend with matplotlib.use(<name>).")
return
def tile_figures(cols=3, rows=2, screen_rect=None, tile_offsets=None):
"""
Tile figures. If more than cols*rows figures are present, cols and
rows are adjusted. For now, a Qt- or Tk-backend is required.
import matplotlib
matplotlib.use('Qt5Agg')
matplotlib.use('TkAgg')
Arguments:
cols, rows: Number of cols, rows shown. Will be adjusted if the
number of figures is larger than cols*rows.
screen_rect: A 4-tuple specifying the geometry (x,y,w,h) of the
screen area used for tiling (in pixels). If None, the
system's screen is queried using the screeninfo module.
tile_offsets: A 2-tuple specifying the offsets in x- and y- direction.
Can be used to compensate the title bar height.
"""
assert(isinstance(cols, int) and cols>0)
assert(isinstance(rows, int) and rows>0)
assert(screen_rect is None or len(screen_rect)==4)
backend = mpl.get_backend()
if screen_rect is None:
screen_rect = screen_geometry()
if tile_offsets is None:
tile_offsets = (0,0)
sx, sy, sw, sh = screen_rect
sx += tile_offsets[0]
sy += tile_offsets[1]
fig_ids = plt.get_fignums()
# Adjust tiles if necessary.
tile_aspect = cols/rows
while len(fig_ids) > cols*rows:
cols += 1
rows = max(np.round(cols/tile_aspect), rows)
# Apply geometry per figure.
w = int(sw/cols)
h = int(sh/rows)
for i, num in enumerate(fig_ids):
fig = plt.figure(num)
x = (i%cols) *(w+tile_offsets[0])+sx
y = (i//cols)*(h+tile_offsets[1])+sy
set_figure_geometry(fig, backend, x, y, w, h)
def test(n_figs=10, backend="Qt5Agg", **kwargs):
mpl.use(backend)
plt.close("all")
for i in range(n_figs):
plt.figure()
tile_figures(**kwargs)
plt.show()
The tile-offset in y-direction is best chosen as the height of the title bar. On my MacOS it is 22. This value can be queried programmatically using for example Qt.
from PyQt5 import QtWidgets as qtw
enum = qtw.QStyle.PM_TitleBarHeight
style = qtw.QApplication.style()
tile_offset_y = style.pixelMetric(enum)

Wrong order of frames creating GIF animation from PNG files

I'm saving a GIF file from multiple PNG files I create inside a loop. I'm not able to save the PNG's with the right name, because when translated to GIF I get the wrong order of the frames.
The following code is exactly what I need but with the order of the frames messed up. Thanks a lot, I'm new to python.
# basic animated mod 39 wheel in python
import glob
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
plt.close()
plt.rcParams.update({
"lines.color": "white",
"patch.edgecolor": "white",
"text.color": "lightgray",
"axes.facecolor": "black",
"axes.edgecolor": "lightgray",
"axes.labelcolor": "white",
"xtick.color": "white",
"ytick.color": "white",
"grid.color": "lightgray",
"figure.facecolor": "black",
"figure.edgecolor": "black",
"savefig.facecolor": "black",
"savefig.edgecolor": "black"})
plt.xlabel('real axis')
plt.ylabel('imaginary axis')
plt.title('events constellation')
plt.xlim(-4, 4)
plt.ylim(-4, 4)
plt.gca().set_aspect('equal', adjustable='box')
#for fullscreen plt.draw just reinforces de rendering?
#plt.draw()
#mng = plt.get_current_fig_manager()
#mng.full_screen_toggle()
for n in range(1,40):
cnums = 3 * np.exp(1j * 2 * np.pi * (1/39) * n)
x = cnums.real
y = cnums.imag
plt.scatter(x, y , label="event", marker="o", color="blue", s=250)
#plt.pause(1)
plt.savefig(f'/outpng/img{n}.png',dpi=100)
# filepaths
fp_in = "/outpng/*.png"
fp_out = "/outpng/image.gif"
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
img, *imgs = [Image.open(f) for f in sorted(glob.glob(fp_in))]
img.save(fp=fp_out, format='GIF', append_images=imgs,
save_all=True, duration=600, loop=0)
If I understand correctly, you have:
lst_files = glob.glob(fp_in)
>>> ['/outpng/img28.png', '/outpng/img4.png', '/outpng/img20.png', '/outpng/img32.png', '/outpng/img36.png', '/outpng/img11.png', '/outpng/img1.png', '/outpng/img9.png', '/outpng/img24.png', '/outpng/img35.png', '/outpng/img7.png', '/outpng/img12.png',]
And you want to have the files 'in order' (presumable the number is the order of the images). You can do this using:
import re
def get_number(file_name):
m = re.findall('img([0-9]*)\.', file_name)[0]
return int(m)
lst_files = ['/outpng/img28.png', '/outpng/img4.png', '/outpng/img20.png', '/outpng/img32.png', '/outpng/img36.png', '/outpng/img11.png', '/outpng/img1.png', '/outpng/img9.png', '/outpng/img24.png', '/outpng/img35.png', '/outpng/img7.png', '/outpng/img12.png']
lst_numbers = [get_number(i) for i in lst_files]
lst_number_files = sorted(list(zip(lst_numbers, lst_files)))
lst_files_sorted = [i[1] for i in lst_number_files]
How this works:
you find the number in the string (using re.findall) which fits 'imgX.' where X is your number
you match the numbers to the file names
you sort the files based on the number
you flatten the list to only contain the file names
Now you can use this list to make your GIF:
img, *imgs = [Image.open(f) for f in lst_files_sorted]

matplotlib: how to define lines with text and mark lines joints?

I am trying to recreate the following:
Any comments will be appreciated. I want to imitate this picture actually, but I have 3 problems:
How to get known the joints of two lines and the turning points of a line? Could these specific points be calculated from analytical calculations? or matplotlib could find out them?
How can I draw the dashed vertical line segment just below the line joint?
How to paste text to the segments of the lines? Could matplotlib determine the convenient location to write text attached to the lines ? or I should determine the location myself ?
For example, I can only draw such kind as below, far less than required. Please help me to improve my picture.
My own picture, which need improvements:
Code so far with detail code as below:
# -*- coding: utf-8 -*
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import math
from pylab import *
c = 2.998*10**10
hp = 6.626*10**-27
hb = 1.055*10**-27
kb = 1.381*10**-16
g = 6.673*10**-8
me = 9.109*10**-28
mp = 1.673*10**-24
q = 4.803*10**-10
sigT = 6.652*10**-25
p = 2.5
E52 = 1000
epsB_r = 0.01
epse_r = 0.1
D28 = 1
n1 = 1.0
nu15 = 2*10**(-3)
r014 = 1
g42 = 5
delt12 =1
g4 = g42*10**2
E0 = E52*10**52
eta = g4
N0 = E0/(g4*mp*c**2)
p_td = 24*3600
p_txd = 3**(1./3)*2**(-4./3)*10**(52./3)*pi**(-1./3)*mp**(-1./3)*c**(-5./3)/p_td
txd = p_txd*n1**(-1./3)*eta**(-8./3)*E52**(1./3)
p_Fmax_r1 = 2**(1./2)*3**(-1)*pi**(-1./2)*me*mp**(1./2)*c**3*sigT*q**(-1)*p_txd**(-3./2)*10**(-56)
Fmax_r1 = lambda t : p_Fmax_r1*N0*eta**6*E52**(-1./2)*n1*epsB_r**(1./2)*D28**(-2)*t**(3./2)
p_Fmax_r2 = 2**(1./2)*3**(-1)*pi**(-1./2)*me*mp**(1./2)*c**3*sigT*q**(-1)*p_txd**(34./35)*10**(-56)
Fmax_r2 = lambda t : p_Fmax_r2*N0*epsB_r**(1./2)*D28**(-2)*t**(-34./35)*eta**(-62./105)*n1**(37./210)*E52**(34./105)
p_nuc_r1 = 2**(-13./2)*3**2*me*mp**(-3./2)*c**(-2)*sigT**(-2)*pi**(-1./2)*q*p_td**(-2)
p_nuc_r2 = 2**(-13./2)*3**2*pi**(-1./2)*me*mp**(-3./2)*c**(-2)*sigT**(-2)*q*p_txd**(-74./35)*p_td**(-2)
nuc_r1 = lambda t : p_nuc_r1*eta**(-4)*epsB_r**(-3./2)*n1**(-3./2)*t**(-2)
nuc_r2 = lambda t : p_nuc_r2*eta**(172./105)*t**(4./35)*n1**(-167./210)*epsB_r**(-3./2)*E52**(-74./105)
p_num_r1 = 2**(11./2)*7**(-2)*mp**(5./2)*me**(-3)*pi**(-1./2)*q*p_txd**(-6)
p_num_r2 = 2**(11./2)*7**(-2)*mp**(5./2)*me**(-3)*pi**(-1./2)*q*p_txd**(54./35)
num_r1 = lambda t : p_num_r1*eta**18*((p-2)/(p-1))**2*epse_r**2*epsB_r**(1./2)*n1**(5./2)*t**6*E52**(-2)
num_r2 = lambda t : p_num_r2*((p-2)/(p-1))**2*n1**(-1./70)*eta**(-74./35)*E52**(18./35)*t**(-54./35)*epse_r**2*epsB_r**(1./2)
def num_r_(t):
return num_r1(t) if t<txd else num_r2(t)
num_r = np.vectorize(num_r_)
def nuc_r_(t):
return nuc_r1(t) if t<txd else nuc_r2(t)
nuc_r = np.vectorize(nuc_r_)
def Fmax_r_(t):
return Fmax_r1(t) if t<txd else Fmax_r2(t)
Fmax_r = np.vectorize(Fmax_r_)
i= np.arange(-5,-2,0.05)
t = 10**i
dnum = [math.log10(mmm) for mmm in num_r(t)]
dnuc = [math.log10(j) for j in nuc_r(t)]
nu_obs = [math.log(nu15*10**15,10) for a in i]
plt.figure('God Bless: Observable Limit')
plt.title(r'$\nu_{obs}$ and $\nu_c$ and $\nu_m$''\nComparation')
plt.xlabel('Time: log t')
plt.ylabel(r'log $\nu$')
plt.axvline(math.log10(txd))
plt.plot(i,nu_obs,'--',linewidth=2,label=r'$\nu_{obs}$')
plt.plot(i,dnum,'-.',linewidth=2,label=r'$\nu_m$')
plt.plot(i,dnuc,linewidth=2,label=r'$\nu_c$')
plt.savefig("test4.eps", dpi=120,bbox_inches='tight')
plt.legend()
plt.show()
I just find a solution, not certain whether there would be some better solution.
I took reference here: Annotate some points
I assumed the solution like this :
1, We can calculate the joint point coordination of lines.
2, If we want to plot a segment of a vertical line, i.e. the segment below the joint point, we can choose two points to draw a short line. That does work!
3, Maybe we can only to find a location of the illustrative text, and attach the text to that place.
I add such phrases :
plot([math.log10(txd),math.log10(txd)],[4,math.log10(nuc_r(txd))], color ='blue', linewidth=2.5, linestyle="--")
scatter([math.log10(txd),],[math.log10(nuc_r(txd))], 50, color ='blue')
annotate(r'$sin(\frac{2\pi}{3})=\frac{\sqrt{3}}{2}$',
xy=(math.log10(txd), math.log10(nuc_r(txd))), xycoords='data',
xytext=(+10, +30), textcoords='offset points', fontsize=16,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
And got the result as :
A Better One

Matplotlib Table's Font Size

Working with Matplotlib in Python (2.7.9). I have to plot a table in a subplot (in this case subplot name is tab) but I can't seem to find a way to change the font size of the table (http://imgur.com/0Ttvzee - bottom left). Antman is happy about the results, I am not.
This is the code I've been using.
EDIT: Added full code
def stat_chart(self):
DN = self.diff
ij = self.ij_list
mcont = self.mcont
ocont = self.ocont
ucont = self.ucont
dist = self.widths
clon = '%1.2f' %self.mclon
clat = '%1.2f' %self.mclat
clonlat = "{0}/{1}".format(clon,clat)
area = self.area
perim = self.perimeter
mdist = np.array(self.widths)
mdist = mdist[:,0]*10
mdist = np.mean(mdist)
pstat = self.polygon_status
if pstat == 1:
status = "Overestimation"
else:
status = "Underestimation"
# Setting up the plot (2x2) and subplots
fig = plt.figure()
gs = gridspec.GridSpec(2,2,width_ratios=[2,1],height_ratios=[4,1])
main = plt.subplot(gs[0,0])
polyf = plt.subplot(gs[0,1])
tab = plt.subplot(gs[1,0])
leg = plt.subplot(gs[1,1])
tab.set_xticks([])
leg.set_xticks([])
tab.set_yticks([])
leg.set_yticks([])
tab.set_frame_on(False)
leg.set_frame_on(False)
# Main image on the top left
main.imshow(DN[::-1],cmap='winter')
x1,x2,y1,y2 = np.min(ij[:,1])-15,np.max(ij[:,1])+15,np.min(ij[:,0])-15,np.max(ij[:,0])+15
main.axvspan(x1,x2,ymin=1-((y1-320)/float(len(DN)-320)),ymax=1-((y2-320)/float(len(DN)-320)),color='red',alpha=0.3)
main.axis([0,760,0,800])
# Polygon image on the top right
polyf.imshow(DN,cmap='winter')
polyf.axis([x1,x2,y2,y1])
polyf.plot(mcont[:,1],mcont[:,0],'ro',markersize=4)
polyf.plot(ocont[:,1],ocont[:,0],'yo',markersize=4)
polyf.plot(ucont[:,1],ucont[:,0],'go',markersize=4)
for n,en in enumerate(dist):
polyf.plot([en[2],en[4]],[en[1],en[3]],color='grey',alpha=0.3)
# Legend on the bottom right
mc = mlines.Line2D([],[],color='red',marker='o')
oc = mlines.Line2D([],[],color='yellow',marker='o')
uc = mlines.Line2D([],[],color='green',marker='o')
ed = mlines.Line2D([],[],color='black',alpha=0.5)
pos_p = mpatches.Patch(color='lightgreen')
neg_p = mpatches.Patch(color='royalblue')
leg.legend([mc,oc,uc,ed,pos_p,neg_p],("Model Cont.","Osisaf Cont.","Unknown Cont.","Dist. Mdl to Osi", \
'Model Overestimate','Model Underestimate'),loc='center')
# Statistics table on the bottom left
stats = [[clonlat+' degrees' ,'%1.4E km^2' %area,'%1.4E km' %perim,'%1.4f km' %mdist,status]]
columns = ('Center Lon/Lat','Area','Perimeter','Mean Width','Status')
rows = ['TODOpolyname']
cwid = [0.1,0.1,0.1,0.1,0.1,0.1]
the_table = tab.table(cellText=stats,colWidths=cwid,rowLabels=rows,colLabels=columns,loc='center')
table_props = the_table.properties()
table_cells = table_props['child_artists']
for cell in table_cells: cell.set_height(0.5)
plt.show()
return
EDIT2: Eventually (un)solved plotting text instead of table. Good enough.
I had a similar issue in changing the fontsize. Try the following
the_table.auto_set_font_size(False)
the_table.set_fontsize(5.5)
Worked for me.
According to the docs, table has a kwarg called fontsize, a float value for the size in points.
In your example from above, for a fontsize of 5 points you would use:
the_table =tab.table(cellText=stats,colWidths=cwid,rowLabels=rows,colLabels=columns,loc='center',fontsize=5)
If you require greater control, you can pass a FontManager instance to the cell.set_text_props() method as described in this example. That would enable you to set the family, spacing, style etc, in addition to the size.
EDIT: Playing around with Matplotlib's example, it seems that just passing fontsize to the table has no effect. However, importing
from matplotlib.font_manager import FontProperties
and then looping through the cells and running
cell.set_text_props(fontproperties=FontProperties(size = 5))
does have the desired effect. It is unclear why the documented kwarg fontsize does not work in this (or apparently in your) case.

matplotlib: Have axis maintaining ratio

I am new to matplotlib, and I have a very simple (I'm guessing) question.
I have some data that need to be represented in a rectangle of 50x70 "units" (they're feet, actually representing a room) but I don't seem to be able to get matplotlib drawing a rectangle with the same scale on both axis and keeping the 50x70 "dimensions" at the same time.
I've tried the following:
import json
import matplotlib
import os
import sys
import traceback
import matplotlib.pyplot as plt
DATA_FILE = os.path.join(os.path.expanduser("~"), "results.json")
FLOOR_DIMENSIONS = (50, 70)
if __name__ == "__main__":
if len(sys.argv) > 1:
DATA_FILE = os.path.abspath(sys.argv[0])
print "Gonna see what happens with file %s" % DATA_FILE
try:
with open(DATA_FILE, 'r') as f:
result_dict = json.load(f)
except (IOError, OSError, ValueError), e:
print "Received %s %s when trying to parse json from %s\n"\
"Showing traceback: %s" % (type(e), e, DATA_FILE, traceback.format_exc())
result_dict = {}
for d_mac in result_dict:
data = result_dict[d_mac]
if len(data) < 3:
continue
x_s = list(d['x'] for d in data)
y_s = list(d['y'] for d in data)
plt.scatter(x_s, y_s, marker='o', c=numpy.random.rand(5,1), s=15)
plt.xlim([0, FLOOR_DIMENSIONS[0]])
plt.ylim([0, FLOOR_DIMENSIONS[1]])
#plt.axis('equal')
plt.show()
sys.exit(0)
Doing that, I get:
Which draws my data inside an square, changing the X-Y scale (X is 50 points, and Y is 70, therefor Y shows "shrunk")
Another option I tried was uncommenting the line saying plt.axis('equal'), but that "cuts" the Y axis (doesn't start in 0 and finishes in 70, but starts in 15 and ends in 55, probably because there's no data with y < 15 and y > 55)
But I don't want that either, I want the "canvas" starting in Y=0 and ending in Y=70, and if there's no data just show an empty space.
What I need is to draw something like this:
which I got by manually re-sizing the window where the plot was rendered :-D
Thank you in advance!
Add plt.axis('scaled').
edit: axis('image') may be better for your needs.
More axis settings can be found in the documentation.
import matplotlib.pyplot as plt
import numpy as np
xs = np.arange(50)
ys = (np.random.random(50)*70) + 15
plt.scatter(xs,ys)
plt.axis('image')
plt.axis([0, 50, 0, 70])
plt.show()
gives:
In the updated example I know the ys actually has a maximum of ~85, the offset was just to demonstrate proper axis enforcement.

Categories

Resources