[Risolto] pgfcalendar, contatore ed err. dimension too large

  • Creatore
    Topic
  • #89630
    Liverpool
    Partecipante
      Up
      0
      Down
      ::


      Vorrei realizzare una linea del tempo con TikZ, perciò ho bisogno di scalare le date in modo tale che rientrino nella linea in maniera proporzionale. Ho scelto di usare il pacchetto [tt]pgfcalendar[/tt] che permette di convertire una data in numero intero e pone il risultato in un contatore. Questo numero va poi diviso per un coefficiente che fa corrispondere al valore 1 la data più alta ammissibile e, nelle mie intenzioni, il risultato va moltiplicato per la lunghezza della linea in modo da ottenere l’ascissa del suo estremo destro.
      Finora ho scritto questo codice nel quale vi invito a prendere per buoni i numeri:
      `\documentclass{article}
      \usepackage{tikz}
      \usepackage{pgfcalendar}
      \newcount\datax % è il contatore che conserva il numero di giorni che intercorrono da \datamin
      \newcount\datamin % è il contatore che conserva la data più piccola
      \pgfcalendardatetojulian{1920-01-01}{\datamin} % scrive in \datax il numero di giorni da \datamin
      \newcommand\tfdata[1]{
      \pgfcalendardatetojulian{#1}{\datax}
      \advance\datax -\datamin\relax
      }
      \begin{document}
      \tfdata{2013-12-01} % è la data più alta. Mi aspetto che dia 1 in un intervallo tra 0 e 1
      \begin{tikzpicture}
      \draw (\datax/34303,0) — (-90:1mm);
      \end{tikzpicture}
      \end{document}`
      ma ottengo l’errore di dimensione troppo grande per TikZ.
      Come posso fare per scalare l’intervallo 1/1/1920 -> 1/12/2013 in [0,1]?

      Lo so che con i contatori sono scarso 🙁

      Grazie

    Visualizzazione 6 filoni di risposte
    • Autore
      Risposte
      • #89631
        OldClaudio
        Partecipante
          Up
          0
          Down
          ::


          Be’ i contatori contengono numeri interi e le divisioni danno un quoziente intero. quindi se la differenza di giorni fra il 2013-12-01 e il 1920-01-01 è minore di 34303 il risultato della divisione datax/34303 vale 0, mentre se questa differenza è uguale o maggior dà epr risultato un numero inttero maggiore o uguale a 1. Dunqe non è così che si fanno i conti per avere un risultato fratto nell’intervallo 0–1.

          I contatori possono contenere un valore intero il cui valore assoluto non può superare 2^{31}-1 (cioè una parola di 32 bit con 31 bit che valgono 1; si tratta di un numero molto grande, un paio di miliardi, quindi è difficile che la differenza di giorni fra quelle due date sia così grande.

          Se però \pgfcalendardatetojulian ti restituisce un numero fratto (inteso cune la misura di una lunghezza in punti, il suo valore assoluto massimo può arrivare a 16383,99999; perciò questo spiegherebbe perché hai una dimensione troppo grande. Quello che segue, la divisione per 34303 porta poi agli inconvenienti che ti ho detto. Ma il giorno giulianp è dato da un numero intero, generalmente molto grande, quindi questa ipotesi che sto facendo, è priva di fondamento. Ti mostra solo il modo di ragionare.

          Leggi bene la documentazione di pgfcalendar; non la leggo io per te. Ti dico solo che è tutto spiegato nel §57 alla pagina 509 del manuale di PGF che puoi leggere, come al solito, dando in un terminale il comando texdoc pgfcalendar.

          Se usi il pacchetto calc, forse riesci ad ottenere il valore fratto; se vuoi fare i conti con una versione moderna di pdflatex (che possa lavorare in modalità estesa, come puoi verificare all’inizio di un qualunque file .log che è stato generato dalla compilazione di qualunque documento), lo puoi fare; leggi con il comando texdoc etex la documentazione della modialità estesa, e in particolare leggi il paragrafo intitolato Expressions.

        • #89632
          Liverpool
          Partecipante
            Up
            0
            Down
            ::


            Ho risolto attivando la libreria [tt]fpu[/tt] di TikZ e utilizzando questo codice:
            `\newcount\datax
            \newcount\datamin
            \newcount\deltadata
            \pgfcalendardatetojulian{1920-01-01}{\datamin}
            \pgfcalendardatetojulian{2013-12-01}{\deltadata}
            \advance\deltadata -\datamin\relax
            \newcommand\tfdata[1]{
            \pgfcalendardatetojulian{#1}{\datax}
            \advance\datax -\datamin\relax
            \pgfkeys{/pgf/fpu=true,pgf/fpu/output format=fixed}
            \pgfmathparse{\datax/\deltadata}
            \pgfmathresult
            \pgfkeys{/pgf/fpu=false}
            }`

            Grazie

          • #89633
            OldClaudio
            Partecipante
              Up
              0
              Down
              ::


              Non c’è dubbio che usando la libreria floating point di pgf tu possa calcolare il valore che ti aspetti in un intervallo fra 0 e 1.

              A me sembra che si ammazzi una zanzara con un cannone; le indicazioni che ti avevo invitato a usare porterebbero ad un codice di questo genere ([tt]\strp@pt[/tt] è una macro interna di LaTeX che serve per eliminare l’indicazione `pt’ dal valore di una lunghezza in punti;[tt]\p@[/tt] è una dimensione interna di LaTeX che vale 1pt):`
              \documentclass{article}
              \usepackage{tikz}
              \usepackage{pgfcalendar}
              \newcount\datax % è il contatore che conserva il numero di giorni che intercorrono da \datamin
              \newcount\datamin % è il contatore che conserva la data più piccola
              \newcount\deltadata % è il contaotre che contiene la differenza delle date
              \pgfcalendardatetojulian{1920-01-01}{\datamin} % scrive in \datax il numero di giorni da \datamin

              \newcommand\tfdata[1]{%
              \pgfcalendardatetojulian{#1}{\datax}
              \advance\datax -\datamin\relax
              }
              \newcommand\calcdeltadata[1]{%
              \pgfcalendardatetojulian{#1}{\deltadata}
              \advance\deltadata -\datamin\relax
              }
              \calcdeltadata{2013-12-01} % è la data più alta; mi aspetto un rapporto in un intervallo tra 0 e 1

              \makeatletter
              \newcommand\rapportodate[2]{% calcolo del rapporto fra le differenze di 2 date giuliane
              \strip@pt\dimexpr\p@*#1/#2\relax
              }

              \makeatother
              \begin{document}

              \tfdata{2010-12-01}
              \begin{tikzpicture}
              \draw (\rapportodate{\datax}{\deltadata},0) — (-90:1mm);
              \end{tikzpicture}
              \end{document}`

              ho aggiunto solo un contatore e due macro solo per scrivere più pulito; se ne potrebbe fare a meno ma il codice sarebbe più contorto e a distanza di tempo diventerebbe incomprensibile.

              Con il valore di data di 2010-12-01 si ottiene un valore fratto di circa 0,9; con la data massima si ottiene 1. e non ci sono overflow di nessun genere né numerici né dimensionali.

              L’operazione \dimexpr/ è descritta col nome di “scaling” nel paragrafo Expressions del documento etex. Il tutto è calcolato nei registri interni del processore senza ricorrere a sviluppi di macro; ecco, quindi, lo schiaccia zanzare adatto; non il cannone delle “infinite” macro della libreria floaitng point di pgf. Per carità, anche quella libreria va benissimo, ma rallenta non poco i calcoli; ha senso quando si debbano calcolare funzioni trascendenti ma per un semplice rapporto sembra una cosa eccessiva.

            • #89634
              Liverpool
              Partecipante
                Up
                0
                Down
                ::


                Grazie. Hai ragione sulla storia del cannone. Purtroppo da solo non ci sarei arrivato, nonostante abbia letto più di una volta anche la guida GuIT dove l’argomento è trattato 🙁 Mi mancava la questione di rimuovere l’unità di misura e quindi ricevevo un errore. Poi la fretta ha suggerito la soluzione che ho adottato.

                Ciao

              • #89635
                Liverpool
                Partecipante
                  Up
                  0
                  Down
                  ::


                  Ancora una domanda e una curiosità.

                  Domanda. Supponiamo che io abbia memorizzato la lunghezza della linea in un registro [tt]\larr[/tt] e voglia scalare direttamente il risultato per questa grandezza, senza ricorrere a TikZ. Come si fa? Ho provato a scrivere:
                  `\dimexpr\larr*\strip@pt\dimexpr\p@*\datax/\deltadata\relax`
                  ma mi dice che non posso usare [tt]\dimexpr[/tt] in modalità orizzontale ristretta. Dove sbaglio?

                  Curiosità. Perché non si può usare direttamente [tt]\numexpr[/tt] per fare il rapporto delle date, come avevo pensato inizialmente io?

                  Grazie

                • #89636
                  OldClaudio
                  Partecipante
                    Up
                    0
                    Down
                    ::


                    Le esprrssioni dimensionali o numeriche o quant’altro secondo quel messaggio devono essre vautat quando si è fuori da quelunque scatola (modo orizzontale ristretto)

                    Non pu`ø usare \numexpr perché hia bisogno di un risultato decimale fratto, non di un numero intero; \numexpr fa conti solo con numeri interi.

                  • #89637
                    Liverpool
                    Partecipante
                      Up
                      0
                      Down
                      ::


                      Ho risolto così:
                      `\the\dimexpr\larr*\datax/\deltadata\relax`
                      Grazie per la spiegazione. Quel paragrafo l’avrò letto una decina di volte, ma non si ficca nella testa 🙁

                  Visualizzazione 6 filoni di risposte
                  • Devi essere connesso per rispondere a questo topic.

                  Go to top