quinta-feira, 11 de agosto de 2011

Script (em Python) para gerar gráficos "waterfall-like" no SciDAVis

Como todos devem saber, o SciDAVis ainda não possui ferramentas para gerar gráficos no estilo waterfall, como faz o Origin®, mas, felizmente, existem maneiras de contornar a situação e obter o que eu vou chamar de "gráfico waterfall-like", como é mostrado na figura 1, a seguir:

Figura 1: Gráfico no estilo waterfall.

Um gráfico do tipo waterfall envolve 3 coordenadas mas não é obtido através de um "plot3D". Geralmente estes gráficos surgem do fato de termos dados em que uma variável independente não se altera com a mudança de valores de alguma outra variável independente, mas a variável dependente sim. Em um exemplo prático seria assim: as leituras de X não mudam conforme alteramos os valores de Z, mas os valores de Y variam.
No caso da figura 1, os valores de comprimento de onda não variam com o tempo, mas a intensidade varia. E os dados que foram utilizados para gerar o gráfico estavam, inicialmente, dispostos em uma tabela com uma coluna X e 13 colunas Y.
Para gerar um gráfico como o da figura 1, a ideia básica é que os valores de X e Y sejam "deslocados na diagonal" a partir do segundo conjunto de dados. Para isto, basta somar valores adequados a cada conjunto (Xi,Yi) de dados. O script a seguir, juntamente com seus comentários, explica uma das maneiras de se fazer isto sem termos que estipular tais valores "na marra".
IMPORTANTE: As finalidades de se gerar este tipo de gráfico no SciDAVis são (apenas): visualização e apresentação. Quaisquer análises que dependam dos valores verdadeiros de X e Y, como suavização e ajustes de curvas, devem ser realizadas em cima das tabelas originais.
IMPORTANTE 2: é possível que algumas opções do script não funcionem em versões do SciDAVis anteriores à 0.2.4 (não testei pra saber).
IMPORTANTE 3: utilize este script apenas como base para o seu próprio, fazendo adaptações necessárias para os tipos de dados com os quais você trabalha.

Agora sim, o script:

# Partindo do pressuposto que tenhamos uma tabela, com o nome de
# "Tabela1", com uma coluna X e várias colunas Y
t1=table("Tabela1") # acessando a "Tabela1" com 't1'
nrt1=t1.numRows() # obtendo o número de linhas de 't1'
nct1=t1.numCols() # obtendo o número de colunas de 't1'
t2=newTable("Tabela2",2*(nct1-1),nrt1) # criando uma nova tabela com 
# o dobro de colunas Y de 't1', mas com o mesmo número de linhas
nrt2=t2.numRows() # número de linhas de 't2'
nct2=t2.numCols() # número de colunas de 't2'
# Primeiro definimos as colunas ímpares como X (abcissas)
#*** há um mistério a ser resolvido aqui: começando com 2, ao invés de 3?
for i in range(2,nct2,2):
 col=t2.column(i) # acessando a coluna 'i', de 't2'
 col.setPlotDesignation("X") # definindo a coluna 'i' como X
## Definindo os valores das coordenadas X na segunda tabela
# Não é possível fazer operações com uma coluna inteira de uma só vez.
# Logo, é necessário alterar os valores célula por célula
for j in range(1,nct2,2):
# calculando o incremento em cada coluna X ('xincr') como o intervalo
# de valores X dividido pelo número de conjuntos de (X,Y) que queremos;
# o fator (j-1)/3 vem do número da coluna dividido por um termo de ajuste
# da distância entre uma curva e outra. No meu caso, usei o número 3, mas
# isto pode ser definido de acordo com a necessidade: curvas mais próximas
# -> números maiores, mais distantes -> números menores
 xincr=(t1.cell(1,nrt1)-t1.cell(1,1))/(nct1-1)*(j-1)/3
 for k in range(1,nrt2):
  t2.setCell(j,k,xincr+t1.cell(1,k))
 
## Definindo os valores de Y na segunda tabela
# Aqui, partimos do pressuposto que o valor da primeira célula da primeira
# coluna Y é um valor adequado para utilizar como incremento. Isto deve ser
# verificado previamente e alterado de acordo com suas necessidades
for j in range(2,nct2+1,2):
 yincr=(t1.cell(2,1))*(j-2)/2
 for k in range(1,nrt2):
  t2.setCell(j,k,yincr+t1.cell(j-(j-2)/2,k))
## Gerando o gráfico
# Aqui, vou plotar a primeira coluna Y e adicionar as outras depois. Faço isto por
# querer todas as curvas na mesma cor
g=plot(t2,"2",0) # plotando a coluna 2 de 't2'
l=g.activeLayer() # acessando a camada ativa (a única no caso) de 'g'
#  e agora, insiro as demais curvas no gráfico
for n in range(4,nct2+1,2):
 l.insertCurve(t2,str(n),0,0)
# Pronto, a partir daqui, já podemos executar o script e teremos nosso gráfico
# no estilo "Waterfall"

## Extra: adicionando seta e legenda para a seta
seta = ArrowMarker() # ArrowMarker() =  desenhador de seta :-)
seta.setStart(515,200) # definindo o ponto inicial: setStart(x,y)
seta.setEnd(525,1200) # definindo o ponto final: setEnd(x,y)
seta.setWidth(1) # definindo largura da linha
seta.drawStartArrow(False) # sem ponta no começo
seta.drawEndArrow(True) # com ponta no final
seta.setColor(Qt.black) # cor da seta
l.addArrow(seta) # adicionando a seta à camada (só aparecerá após um l.replot())
legenda = l.newLegend("Tempo (ms)") # definindo texto da legenda
legenda.setTextColor(Qt.black) # cor do texto na legenda
legenda.setFont(QtGui.QFont("Arial",10)) # fonte do texto na legenda
legenda.setFrameStyle(0) # tipo de borda: 0 - nenhuma, 1 - retângulo e 2 - retângulo com sombra
legenda.setOriginCoord(518.0,800.0) # origem da legenda
l.replot() # redesenhando o conteúdo da camada
# Fim do script. Executando-o, obteremos um gráfico "waterfall-like"
Espero que este script seja útil. Um abraço e até a próxima.

sexta-feira, 13 de maio de 2011

Problemas com a última versão do muParser (1.34) e pacote para o Slackware 13.37

Para aqueles que gostam que seu sistema esteja sempre com todos os pacotes em suas versões mais atuais vale o seguinte lembrete: reveja as dependências de seus programas, pois eles podem não  ter suporte para as versões mais atuais das dependências.
Um bom exemplo disso é a relação entre o SciDAVis e o muParser: se instalarmos o muParser 1.34 no nosso sistema, o SciDAVis irá compilar sem problemas e irá executar a maioria das suas operações. Porém, se você tentar abrir um projeto que tem uma curva de ajuste (fit), tal curva não será reconhecida e veremos uma mensagem do tipo:

Undefined token ";  fórmula utilizada no ajuste" found at position ??.

Isto ocorre por causa de alguma alteração efetuada no muParser, após a versão 1.32, que ainda não foi incorporada ao SciDAVis.
Infelizmente, os empacotadores do SciDAVis de várias distribuições (Ubuntu, Mandriva/Mageia e ArchLinux, por exemplo) não perceberam isto a tempo de "entregar" o SciDAVis nos repositórios com a versão adequada do muParser.

-----------------------------------------------------------------------------------------------

Disponibilizei hoje um pacote do SciDAVis para a nova versão do Slackware, a 13.37.
O pacote criado  inclui as últimas revisões disponíveis no repositório svn do projeto, evitando assim que a tenhamos que conviver com bugs já resolvidos :-) Além disso, as dependências para este pacote também foram disponibilizadas, sendo a principal delas a qt-assistant-compat [1, 2]. Deem uma olhada em www.ifi.unicamp.br/~fellypen/progs/scidavis/slack13.37/ e confiram.

[1] labs.qt.nokia.com/2010/06/22/qt-assistant-compat-version-available-as-extra-source-package/
[2] sourceforge.net/tracker/?func=detail&aid=3026280&group_id=199120&atid=968214

quarta-feira, 13 de abril de 2011

Dica: Interpolação de curvas usando Python script

Como na dica anterior, vamos supor que tenhamos um gráfico, nomeado como Gráfico1, com uma curva rotulada de Tabela1_2, cujo parâmetro x varia entre 0 e 10.
As etapas necessárias para realizar a interpolação de uma curva são:

- definir uma função com a curva a ser interpolada, os limites inicial e final e o método de interpolação que será utilizado (0, 1 ou 2, para Linear, Cúbica ou Akima, respectivamente);
- definir o número de pontos da curva resultante;
- definir a cor da curva resultante;
- executar a interpolação.

A sintaxe da função que realiza a interpolação fica do seguinte modo:

interpolacao = Interpolation(graph("Nome do gráfico").activeLayer(), "Nome da curva", Limite inicial, Limite final, Número do método)

Para definir o número de pontos da curva resultante usamos:

interpolacao.setOutputPoints(Número de pontos desejado)

A cor da curva no gráfico é definida utilizando:

interpolacao.setColor("nome da cor, em inglês")

E para executar a interpolação:

interpolacao.run()

Exemplo prático:

interpolacao = Interpolation(graph("Gráfico1").activeLayer(), "Tabela1_2",0,10,2)
interpolacao.setOutputPoints(200)
interpolacao.setColor("blue")
interpolacao.run()

Com isto, a curva de interpolação será plotada no gráfico (Gráfico1), juntamente com os pontos originais. Além disso, a respectiva tabela com os pontos interpolados será criada.
Se esta informação lhe for útil, faça bom proveito.
Até mais.

segunda-feira, 21 de março de 2011

Dica: Integração numérica usando Python script

Nesta minha primeira dica que posto aqui sobre Python script no SciDAVis vou falar sobre integração numérica. Antes da dica, vale lembrar que a linguagem Python deve ter sido préviamente selecionada no menu "Programação" → "Linguagem de programação (script)" (ou "Scripting" → "Scripting Language", se você estiver utilizando a interface em inglês). Os scripts podem ser editados e executados em uma nota (menu "Arquivo" → "Novo" → "Nova nota / script") ou executados via linha de comando (este último método não será abordado nesta dica).

Para este exemplo, vamos supor que tenhamos um gráfico, nomeado como Gráfico1, com uma curva rotulada de Tabela1_2, cujo parâmetro x varia entre 0 e 10. Vamos supor também que o usuário tenha conhecimentos básicos de Python.

As etapas necessárias para efetuar a integração numérica e extrair o resultado são:

- definir uma função com a curva a ser integrada, juntamente com os limites inferior e superior;
- definir o método a ser utilizado para interpolação (0, 1 ou 2, para Linear, Cúbica ou Akima, respectivamente);
- executar a integração;
- extrair o resultado.

A sintaxe da função que efetua a integração numérica no SciDAVis é:

integral = Integration(graph("Nome do gráfico").activeLayer(), "Nome da curva", Limite inferior, Limite superior)

Para definir o método de interpolação usamos:

integral.setMethod(Número do método)

Em seguida executamos com:

integral.run()

E extraímos o resultado com:

integral.result()

Vamos a um exemplo prático.
Abra uma nota e digite (ou copie e cole) os seguintes comandos:

integral = Integration(graph("Gráfico1").activeLayer(), "Tabela1_2",0,5)
integral.setMethod(2)
integral.run()
integral.result()

Selecione tudo e tecle Ctrl + j para executar (se preferir, não selecione nada e tecle Ctrl + Shift + j). O resultado da operação aparecerá na janela de registro de resultados (Results Log), juntamente com todas as informações sobre a operação: método, limites, ymáx, etc.

Aí você pergunta: - Ok! Mas pra quê usar um script em Python para fazer esta operação se eu posso fazê-la através do menu "Análise" → "Integrar..."?

E eu respondo: - Pra poder automatizar o processo no caso de você precisar repeti-lo várias vezes. Por exemplo, se você precisar integrar vários intervalos da variável x, como é mostrado a seguir:

tabela2 = newTable("Tabela2",2,10) # criando uma nova tabela, com 2 colunas e 10 linhas
passo = 1.0 # incremento a ser utilizado para variar o intervalo de integração
lim_ini = 0.0
lim_fin = 1.0
for i in range(1,tabela2.numRows() + 1):
 tabela2.setCell(1,i,(lim_ini+lim_fin)/2)
 integral = Integration(graph("Gráfico1").activeLayer(),"Tabela1_2",lim_ini,lim_fin)
 integral.setMethod(1)
 integral.run()
 tabela2.setCell(2,i,integral.result())
 lim_ini = lim_ini + passo
 lim_fin = lim_fin + passo

Com este procedimento, obteremos uma tabela com valores da integração na segunda coluna e o valor médio do intervalo de integração na primeira.

Se esta informação for útil pra você, faça bom proveito.

Até a próxima.