La fonction input avec un fichier txt ou csv

Bonjour à tous,

Mon code génère plusieurs points à partir d'une source de 4 points dans une emprise définie et me récupère les coordonnées x,y dans un fichier CSV.
Je voudrais généraliser ce code en demandant avec la fonction input les paramètres du programme, à savoir :

  • les 4 coordonnées sources
  • l'emprise du projet (x,y) et (A,B).

Pour le moment, les 4 coordonnées sources sont dans un fichier texte et l'emprise du projet est dans un fichier texte.

Voila le code :

import matplotlib.pyplot


def equdroite(x0, y0, x1, y1):
    a = y1 - y0
    b = x0 - x1
    c = -(b * y0 + a * x0)
    #     print("verif00:",sign(x0,y0,a,b,c),sign(x1,y1,a,b,c))
    return a, b, c


def inside(Poly, p):
    for P in Poly:
        a, b, c, s, x, y = P[0], P[1], P[2], P[3], pp[0], pp[1]
        if s * sign(x, y, a, b, c) < 0:
            #             print("outside:",a,b,c,s,x,y)
            return False
    return True


def sign(x, y, a, b, c):
    return a * x + b * y + c


# Les 4 coordonnées sources
(x, y) = ([325010, 325015, 325015, 325010], [2077560, 2077560, 2077555, 2077555])
# x = [325010, 325015, 325015, 325010, 325010]
# y = [2077560, 2077560, 2077555, 2077555, 2077560]
sg = 5
# L'emprise du projet
(A, B) = ([324989.345, 324987.133, 324987.502, 325037.452, 325035.977, 324989.345],
          [2077586.246, 2077553.622, 2077537.955, 2077537.402, 2077589.933, 2077586.246])
# A = [324989.345,  324987.133,  324980,  325037.452,  325035.977,  324989.345]
# B = [2077586.246, 2077553.622, 2077800, 2077537.402, 2077589.933, 2077586.246]
# avgA,avgB=sum(A)/len(A),sum(B)/len(B)
# # print ("avg:",avgA,avgB)
# A=[x-avgA for x in A]
# B=[x-avgB for x in B]
# x=[x-avgA for x in x]
# y=[x-avgB for x in y]
nc = len(A) - 1
E = []
for p0 in range(nc):
    p1 = (p0 + 1) % nc
    p2 = (p0 + int(nc / 2)) % nc
    a, b, c = equdroite(A[p0], B[p0], A[p1], B[p1])
    s = sign(A[p2], B[p2], a, b, c)
    #     print("inloop:",p0,a,b,c,s)
    E.append([a, b, c, s, p0, p1])
# print("E:",E)
for p in range(nc):
    for C in E:
        if p != C[4] and p != C[5]:
            a, b, c, s, xp, yp = C[0], C[1], C[2], C[3], A[p], B[p]
            v = sign(xp, yp, a, b, c)
            if s * v < 0:
                #             print("outside:",a,b,c,s,xp,yp)
                print("OUPS!", s, v)
matplotlib.pyplot.plot(A, B)
matplotlib.pyplot.scatter(x, y, color="r")
matplotlib.pyplot.axis("equal")
matplotlib.pyplot.grid()

phg = (int(min(A) / sg) * sg, int(min(B) / sg) * sg)
pbd = (int(max(A) / sg + 1) * sg, int(max(B) / sg + 1) * sg)
nrow = int((pbd[0] - phg[0]) / sg) + 1
ncol = int((pbd[1] - phg[1]) / sg) + 1
# print(phg)
# print(nrow,ncol)
prouge = []
for row in range(nrow):
    for col in range(ncol):
        pp = (phg[0] + sg * row, phg[1] + sg * col)
        if inside(E, pp):
            prouge.append(pp)
xrouge = [ppp[0] for ppp in prouge]
yrouge = [ppp[1] for ppp in prouge]
matplotlib.pyplot.scatter(xrouge, yrouge, color="g")
matplotlib.pyplot.scatter(x, y, color="r")
with open("coordout.csv", "w") as f:
    print("X;Y", file=f)
    for xrouge, yrouge in prouge:
        print(f"{xrouge};{yrouge}", file=f)

matplotlib.pyplot.show()

D'avance merci

13 réponses

  1. Modérateur

    Bonjour

    A priori le code devrait ressembler à ceci :

    from tkinter import filedialog
    
    def prompt_filename(title="Sélectionner le fichier source"):
        return filedialog.askopenfilename(
            initialdir="/", title="Sélectionner le fichier source",
            filetypes=(
                ("Fichier texte", "*.txt"),
                ("Fichier csv", "*.csv")
            )
        )
    
    def read_coords(f_coords):
        coords = list()
        for line in f_coords:
            print(line.strip())
            # ...
        return coords
    
    def read_emprise(f_emprise):
        emprise = ...
        for line in f_emprise:
            print(line.strip())
            # ...
        return emprise
    
    filename_coords = prompt_filename("Sélectionner le fichier de coordonnées")
    with open(filename_coords, "r") as f_coords:
        coords = read_coords(f_coords)
    
    filename_emprise = prompt_filename("Sélectionner le fichier de l'emprise")
    with open(filename_emprise, "r") as f_coords:
        coords = read_emprise(f_coords)
    
    # ...

    Bonne chance

    1
    1. Contributeur

      bonjour, tu te demandes comment lire des données dans un fichier?

      0
      1. Bonjour yb_be c'est à peu près cela. J'aimerais, en exécutant le code, voir la fonction input qui me demande de saisir le fichier du fichier texte contenant les 4 coordonnées, ainsi que celui de l'emprise du projet, puis qu'il continue l'exécution du code.

        Merci

        0
        1.  Bonjour voila le code que je voudrais inserer cependant j'arrive pas bien faire.

          Ou c'est pas la bonne methode , je suis perdu 

          # Les 4 coordonnées sources
          filename = filedialog.askopenfilename(initialdir="/", title="selectionner le fichier source",
                                                filetypes=(("fichier texte", "*.txt"), ("fichier csv", "*.csv")))
          
          (x, y) = filename
          # x = [325010, 325015, 325015, 325010, 325010]
          # y = [2077560, 2077560, 2077555, 2077555, 2077560]
          sg = 5
          0
          1. Contributeur

            Il manque pas un import dans ton code?  Il est complet?

            As-tu déjà fait un essai de lecture d'un fichier, avec un nom de fichier mis en dur dans le code?

            0
        2. Tous les import sont faits et je pense que le code est complet.

          Quand j'ajoute la fonction os.popen(filename) le fichier s'ouvre .

          Je reçois l'erreur:

          TypeError: read expected 2 arguments, got 1

          Le code complet:

          import os
          from tkinter import filedialog
          
          import matplotlib.pyplot
          
          
          def equdroite(x0, y0, x1, y1):
              a = y1 - y0
              b = x0 - x1
              c = -(b * y0 + a * x0)
              #     print("verif00:",sign(x0,y0,a,b,c),sign(x1,y1,a,b,c))
              return a, b, c
          
          
          def inside(Poly, p):
              for P in Poly:
                  a, b, c, s, x, y = P[0], P[1], P[2], P[3], pp[0], pp[1]
                  if s * sign(x, y, a, b, c) < 0:
                      #             print("outside:",a,b,c,s,x,y)
                      return False
              return True
          
          
          def sign(x, y, a, b, c):
              return a * x + b * y + c
          
          
          # Les 4 coordonnées sources
          filename = filedialog.askopenfilename(initialdir="/", title="selectionner le fichier source",
                                                filetypes=(("fichier texte", "*.txt"), ("fichier csv", "*.csv")))
          
          (x, y) = filename
          # x = [325010, 325015, 325015, 325010, 325010]
          # y = [2077560, 2077560, 2077555, 2077555, 2077560]
          sg = 5
          # L'emprise du projet
          (A, B) = ([324989.345, 324987.133, 324987.502, 325037.452, 325035.977, 324989.345],
                    [2077586.246, 2077553.622, 2077537.955, 2077537.402, 2077589.933, 2077586.246])
          # A = [324989.345,  324987.133,  324980,  325037.452,  325035.977,  324989.345]
          # B = [2077586.246, 2077553.622, 2077800, 2077537.402, 2077589.933, 2077586.246]
          # avgA,avgB=sum(A)/len(A),sum(B)/len(B)
          # # print ("avg:",avgA,avgB)
          # A=[x-avgA for x in A]
          # B=[x-avgB for x in B]
          # x=[x-avgA for x in x]
          # y=[x-avgB for x in y]
          nc = len(A) - 1
          E = []
          for p0 in range(nc):
              p1 = (p0 + 1) % nc
              p2 = (p0 + int(nc / 2)) % nc
              a, b, c = equdroite(A[p0], B[p0], A[p1], B[p1])
              s = sign(A[p2], B[p2], a, b, c)
              #     print("inloop:",p0,a,b,c,s)
              E.append([a, b, c, s, p0, p1])
          # print("E:",E)
          for p in range(nc):
              for C in E:
                  if p != C[4] and p != C[5]:
                      a, b, c, s, xp, yp = C[0], C[1], C[2], C[3], A[p], B[p]
                      v = sign(xp, yp, a, b, c)
                      if s * v < 0:
                          #             print("outside:",a,b,c,s,xp,yp)
                          print("OUPS!", s, v)
          matplotlib.pyplot.plot(A, B)
          matplotlib.pyplot.scatter(x, y, color="r")
          matplotlib.pyplot.axis("equal")
          matplotlib.pyplot.grid()
          
          phg = (int(min(A) / sg) * sg, int(min(B) / sg) * sg)
          pbd = (int(max(A) / sg + 1) * sg, int(max(B) / sg + 1) * sg)
          nrow = int((pbd[0] - phg[0]) / sg) + 1
          ncol = int((pbd[1] - phg[1]) / sg) + 1
          # print(phg)
          # print(nrow,ncol)
          prouge = []
          for row in range(nrow):
              for col in range(ncol):
                  pp = (phg[0] + sg * row, phg[1] + sg * col)
                  if inside(E, pp):
                      prouge.append(pp)
          xrouge = [ppp[0] for ppp in prouge]
          yrouge = [ppp[1] for ppp in prouge]
          matplotlib.pyplot.scatter(xrouge, yrouge, color="g")
          matplotlib.pyplot.scatter(x, y, color="r")
          with open("coordout.csv", "w") as f:
              print("X;Y", file=f)
              for xrouge, yrouge in prouge:
                  print(f"{xrouge};{yrouge}", file=f)
          
          matplotlib.pyplot.show()
          0
          1. Contributeur

            montre-nous alors le code avec ce read().

            0
        3. Bonjour,

          filename est le nom du fichier que tu sélectionnes avec la boite de dialogue askopenfilename

          donc (x,y) = filename c'est bizarre

          C'est comme si on faisait (x,y) = 'toto.txt'

          0
          1. tu confonds le nom du fichier et son contenu.....

            0
            1. Bonjour sans doute, franchement je suis bloqué.

              Yg_be je pas compris votre demande.

              0
              1. Contributeur

                montre-nous le code complet qui te donne l'erreur "TypeError: read expected 2 arguments, got 1".

                0
              2. @yg_be

                a mon avis c'est ça:

                (x,y) = filename = filedialog.askopenfilename(...)

                donc voir ma réponse de 13h36 ci-dessous

                0
            2. Bonjour,

              J'espère que tu as bien compris que filename = filedialog.askopenfilename(...)

              te rend le nom du fichier que tu as choisi dans la boite de dialogue ? ???

              Donc une fois que tu as ce nom, il faut ouvrir le fichier en lecture (mais pas avec os.popen)

              et y lire les 2 valeurs de x et y

              Tu sais faire ça, au moins ?

              Sinon, tu peux jeter un œil ici:

              https://pythonforge.com/lire-ou-ecrire-dans-un-fichier-avec-python/

              0
              1. Bonsoir voila ce que j'ai fais comme code mais hélas.

                J'obtient l'erreur: 

                 (x, y) = contenu
                ValueError: too many values to unpack (expected 2)
                325010, 325015, 325015, 325010 2077560, 2077560, 2077555, 2077555

                # Les 4 coordonnées sources
                Coordsources = filedialog.askopenfilename(initialdir="/", title="selectionner le fichier",
                                                          filetypes=(("fichier texte", "*.txt"), ("fichier csv", "*.csv")))
                # print(Coordsources)
                (z) = open(Coordsources, "r")
                contenu = z.read()
                print(contenu)
                (x, y) = contenu
                z.close()
                
                0
                1. Bonsoir, tu tentes de faire

                  >>> x, y = 'blablabla, bla, bla, bla'
                  Traceback (most recent call last):
                    File "<stdin>", line 1, in <module>
                  ValueError: too many values to unpack (expected 2)

                  Forcément, ça ne fonctionne pas.

                  Ton fichier contient une chaîne de  liste de valeurs, du dois donc :

                  - Séparer chaque valeurs de ce str par la virgule pour en obtenir une liste de str

                  - Convertir chacune de ces valeurs en entier

                  Faire cela est aisé.

                  0
              2. Bonjour,

                Non seulement il faut convertir en entier, mais il faut aussi qu'il n'y ait que 2 valeurs dans la liste:

                x,y = (10,20,30)
                ValueError: too many values to unpack (expected 2) : trop de valeurs a récupérer (2 attendues)
                0
                1. Bonsoir à tous,

                  Merci pour vos réactions. Mamiemando, votre code #19 répond à mes attente, il fonctionne très bien.

                  Cependant j'ai aussi trouvé cet code qui marche aussi en faisant des input :

                  x = [int(x) for x in input().split()]

                  J'ai encore une question.

                  Peut-on copier les valeurs de l'emprise pour ensuite les coller dans le fichier "coordout.csv" à l'emplacement "P1" de la feuille?

                  0
                  1. Modérateur

                    Bonjour LALO_5656,

                    Ta question #20 mériterait une nouvelle discussion car c'est un nouveau sujet. Dans les faits, ta question revient à mettre à jour un fichier CSV.

                    C'est un problème qui a déjà été posé sur le forum (par exemple ici, en utilisant pandas). Dans ton cas, inutile de sortir l'artillerie lourde, tu peux le faire "à la main". Il faut charger en mémoire le fichier csv (comme le fait par exemple la fonction read_coords dans #19), mettre à jour cette structure de données (dans ce que j'ai proposé, une liste), puis réécrire le fichier avec la ou les valeur(s) corrigée(s) à partir de cette structure de données.

                    Je n'ai pas compris ce que tu appelais les coordonnées P1 (je suppose que c'est le premier point listé dans le fichier ?). Idéalement il faudrait que tu donnes dans la discussion que tu vas ouvrir le fichier de départ et le fichier que tu aimerais obtenir.

                    Voici à quoi ça pourrait ressembler :

                    points.csv

                    0.0;2.2
                    2.2;5.5
                    5.5;6.6
                    6.6;0.0

                    script.py

                    import csv
                    
                    def read_points(f):
                        reader = csv.reader(f, delimiter=';')
                        return [[float(x) for x in point] for point in reader]
                    
                    def write_points(f, points): 
                        writer = csv.writer(f, delimiter=';')
                        for point in points:
                            writer.writerow(point)
                    
                    # Lecture des points
                    with open("points.csv") as f:
                        points = read_points(f)
                    
                    assert len(points) > 0
                    
                    # Correction du premier point
                    points[0] = [-1.1, -1.2]
                    
                    # Ecriture du fichier de points (on peut utiliser ou non le même fichier)
                    with open("points.csv", "w") as f:
                        write_points(f, points)

                    Résultat :

                    (mando@silk) (~) $ cat points.csv 
                    0.0;2.2
                    2.2;5.5
                    5.5;6.6
                    6.6;0.0
                    
                    (mando@silk) (~) $ python3 script.py 
                    
                    (mando@silk) (~) $ cat points.csv 
                    -1.1;-1.2
                    2.2;5.5
                    5.5;6.6
                    6.6;0.0

                    Bonne chance

                    0