精华内容
下载资源
问答
  • 什么要用桑基图桑基图 (Sankey diagram)是一种展现数据之间流动和相互关系图像,类似于一种网络图,通过不同层级节点之间连接以及连接边宽度,展示数据之间流动关系。在微生物群落分析中,桑基图可以用来...

    60d554c63f997e93e4d698cb4370ebf9.png

    为什么要用桑基图

    桑基图 (Sankey diagram)是一种展现数据之间流动和相互关系的图像,类似于一种网络图,通过不同层级节点之间的连接以及连接边的宽度,展示数据之间的流动关系。

    4689f8901781914d68a1c7f81a8d37a4.png

    在微生物群落分析中,桑基图可以用来展示不同分类学水平微生物的丰度及其从属关系,可以简单的说是一种包含物种丰度信息的系统发育树。

    在一些时间序列或大规模区域样本的研究中,研究人员通常都会非常关注核心微生物组,也就是在一系列时间序列样品或各种不同类型样品中共有的微生物,这些微生物代表了样本中最基本也是最重要的功能微生物。

    使用桑基图可以达到同时展示核心微生物组成、系统发育关系以及相对丰度的目的

    桑基图的绘制

    可以使用R语言的“d3Network”包进行桑基图的绘制,该包是在R环境下基于D3.j绘制桑基图的专门的包。

    还是照例先介绍一下绘图主函数的各项参数。

    d3Sankey(Links, Nodes, Source, Target, Value = NULL, NodeID, height = 600,  width = 900, fontsize = 7, nodeWidth = 15, nodePadding = 10,  parentElement = "body", standAlone = TRUE, file = NULL,  iframe = FALSE, d3Script = "http://d3js.org/d3.v3.min.js")

    各参数意义:

    • Links,用于绘图的数据框,给出了节点及其关联信息;

    • Nodes,包含节点ID及相关信息的数据框;

    • Source,Links文件中指定Source源的向量;

    • Target,Links文件中指定Target的向量;

    • Value,Links文件中指定节点关联边宽度的向量;

    • NodeID,Nodes文件中指定节点ID名称的向量;

    • height,输出图像的高度;

    • width,输出图像的宽度;

    • fontsize,图像中节点标签文字的字号;

    • nodeWidth,用于指定每一个节点的宽度;

    • nodePadding,介绍里的英语没看明白是什么意思;

    • file,输出文件的名称,要输出html格式。

    3dNetwork包绘制桑基图需要两个文件,一个是提供节点及其关联信息的数据框,另一个是提供节点名称及其性质的数据框

    我们首先要手动制作一个原始的数据文件,结构类似于网络分析的输入文件,包含三列信息,第一列为source,内容为节点的名称,第二列为target,内容为属于该source的target名称,第三列为value,及其对应target的相对丰度数据。

    76a5d480926f1f13471fe3b5508aecca.png

    我的示例数据格式如下,数据是一套时间序列微生物群落样本的共有OTU,之后手动计算各物种的丰度及其对应的系统发育层次信息。

    3dNetwork输入的文件要求使用数字来定义source和target的现实顺序,再用nodes文件将节点名称于数字匹配,因此要对输入文件进行一定的处理。

    sankey "sankey.txt",header = TRUE,sep = "\t")nodes as.character(sankey$source),as.character(sankey$target))),stringsAsFactors = FALSE)nodes$ID 0:(nrow(nodes)-1)sankey by.x = "source",by.y = "name")sankey by.x = "target",by.y = "name")colnames(sankey) "X","Y","value","source","target")sankey select = c("source","target","value"))nodes select = c("name"))

    之后就可以绘制图像了。

    d3Sankey(Links = sankey,Nodes = nodes,fontsize = 20,         Source = "source",Target = "target",Value = "value",         NodeID = "name",file = "Sankey.html",         width = 1200,height = 900)

    打开输出的html文件,我们会发现部分图像的元素存在一定的重叠,并且有些节点的顺序可能需要修改。

    596eb0fde278854cc0f642ec5d514f80.png

    这一步就非常简单了,输出的结果是可交互的,直接鼠标拖动节点模块即可改变其位置。

    5833355cfa50f268a9168d244100b4cd.gif

    关注公众号“红皇后学术”,后台回复“桑基图”获取本文介绍的绘图示例文件和完整代码。

    扩展阅读

    • 高通量测序基础知识
    • 转录组测序技术和结果解读
    • 红皇后学术文献解读列表
    • 基本分子生物学实验
    • PAST:最简便易用的统计学分析软件教程目录
    • 每天学习一点R系列
    • 微生物群落数据分析系列教程
    • 微生物研究相关工具
    • 微生物研究投稿期刊简介

    c2d6b68ed766b78b6f61d4d50b9c1753.png


    展开全文
  • 最近在编写公司项目战场时,刻意使用Notification将战场逻辑与战场表现还有战场UI拆分为相互...不得不说我们UI承担东西还是挺多,尤其UI动画,某种意义上它也是展现一部分,不过因为是在UI层展示,所以...

    最近在编写公司项目的战场时,刻意使用Notification将战场逻辑与战场表现还有战场UI拆分为相互独立的三大模块。今天所想记录的就是在开发UI当中设计的一种结构,或许可以值得深入探索总结。

    UI是什么?展现战场数据及信息,收集用户操作并向逻辑层、展现层发送通知,还有就是展示UI动画。不得不说我们的UI承担的东西还是挺多的,尤其UI动画,某种意义上它也是展现层的一部分,不过因为是在UI层展示,所以还是划入了UI层,却也发现了一些异常的好处。下面大概说说思路吧。

    UI层只有一个总页面,放入我们的结构中来说,他只是一个BattlePage。它的子节点可以有多个MonoBehaviour,但是内部并没有Mono自身的Start、Update等函数,所以全部控制权都放在了BattlePage中。所有的子节点都定义为SubPage的派生类。

    public class SubPage : MonoBehaviour
    {
        
        public virtual void FirstOpen() { }
        
        public virtual void Tick(float delta) { }
        
        public virtual void FinalClose() { }
    
    }

    BattlePage自身包含页面的Open、Close、Update等方法,所以核心需要做的就是这么几点事了:

    Open函数是页面第一次打开时候调用,所以在这里就需要通过GetComponentsInChildren获取子节点中所有的SubPage,并进行存储。之后调用所有SubPage的FirstOpen函数。

    Close函数是页面最终关闭时候调用,所以在这里就需要对记录的所有SubPage执行它们的FinalClose函数。

    Update函数则只需要简单执行SubPage的Tick方法即可,同时传入deltaTime参数。

    public class BattlePage : Page
    {
        List<SubPage> allSubPages;
        public override void PageOpen ()
        {
            allSubPages = new List<SubPage> (GetComponentsInChildren<SubPage> ());
            for (int i = 0, imax = allSubPages.Count; i < imax; i++) {
                allSubPages[i].FirstOpen ();
            }
        }
        public override void PageClose ()
        {
            for (int i = 0, imax = allSubPages.Count; i < imax; i++) {
                allSubPages[i].FinalClose ();
            }
        }
        private void Update ()
        {
            float deltaTime = Time.deltaTime;
            for (int i = 0, imax = allSubPages.Count; i < imax; i++) {
                allSubPages[i].Tick (deltaTime);
            }
        }
    }

    如此设计,BattlePage只是一个页面的管理器,内部则不需要再关注具体细节。而且一旦需要添加新的模块,只需要继承SubPage并添加到BattlePage成为其子节点,便可只关注内部具体实现。

    那么SubPage的子类们究竟需要实现一些什么呢?由于采用MVC结构,并且整体是使用Notification实现,所以SubPage只需要实现这么几件事就可以:1.在FirstOpen中注册观察者及观察消息和对应的处理函数;2.在FinalClose中移除观察者;3.实现当前SubPage的具体UI展现逻辑。以我们项目中某英雄角色放大招之前的动画为例:页面在进入战场时注册大招观察者,收到消息即开始展示该英雄的大头贴动画,动画由SubPage自身的Tick实现,展示结束则广播展示结束通知消息,当战场关闭时便释放观察者。

    public class HeroUIAnimPage : SubPage
    {
        public override void FinalClose()
        {
            NotificationCenter.Default.RemoveObserver(this);
        }
    
        public override void FirstOpen()
        {
            NotificationCenter.Default.AddObserver(this, BeginPlay, "PlayHeroAnim", null);
        }
    
        private void BeginPlay(Notification notification)
        {
            // Begin Play UI Anim
        }
    
        public override void Tick(float delta)
        {
            // Play UI Anim
        }
    }

    经过现有开发阶段的验证,针对当前需求,采用此种开发模式效率高,且页面逻辑之间不存在耦合,修改也很快。

    所以如果有人看到,希望大家一起交流

    转载于:https://www.cnblogs.com/sachuan/p/7077404.html

    展开全文
  • 什么是语法树语法树是一种树状结构的源程序代码呈现方式,它可以很好地展示源程序代码信息,这其中就包含了:保存源程序代码信息和对应运行时的结构。如何生成一棵语法树?在回答这个问题前,我们需要先了解...

    325fa7c638d9224034785afed6dfb02e.png

    如何在保证安全性的前提下,提升开发过程的效率,是每个开发者都在不断探索的问题。借助语法树,开发者能够更好地展现和修改源程序代码,优化开发环节,提高安全系数,还能进一步实现安卓预编译。


    什么是语法树

    语法树是一种树状结构的源程序代码呈现方式,它可以很好地展示源程序代码的信息,这其中就包含了:保存源程序的代码信息和对应运行时的结构。

    c8d4fb67384e9516d226e59d4a578db2.png

    如何生成一棵语法树?在回答这个问题前,我们需要先了解编译器的工作流程,它主要分为词法分析、语法分析、中间代码和目标代码这四个过程,语法树则是由语法分析一过程生成。

    ecaccb299dc5d8c96e510a77e790f155.png

    在词法分析过程中,会产生一系列的token流,token是一个保存着type和value的数据结构。词法分析将源代码的每一个关键词都分割出来,之后通过语法分析器进行语法模板匹配,最后生成语法树。

    f4b28f300dfe8cc7ed299e047600397b.png

    语法树的应用

    这一阶段,开发者可以对语法树进行修改,达到修改源代码的效果,从而实现不同的应用目的。

    开发者可以对语法树的一些节点进行修改或增加,来达到代码自动生成的目的。同理,开发者也可以通过遍历代码块插入部分埋点代码,或者找到没有用到的代码进行代码缩减。

    8540e5160971ec0bfa2ee4eaf2603458.png

    线上发版后,开发者会遇到各式各样的问题,需要通过日志定义这些问题。明文输出的日志存在安全隐患,日志混淆插件可以对日志的输出内容进行混淆,大大提高了这一过程中的安全系数。基于语法树实现的个推日志混淆插件,通过遍历指定签名的方法调用,修改它参数的值进行混淆。

    42e730746349cb6f8de88efe073202d1.png

    用语法树来实现预编译指令

    开发者还能用语法树来实现预编译指令,常见的预编译指令主要分为条件编译、宏定义、文件包含三大类。过去,开发者一般使用Antenna来实现预编译指令,它是一个基于ant的工具,随着ide的更新换代,开发者会发现ant中的一些缺陷。Antenna需要配置环境变量,配置文件比较繁琐,且不支持gradle集成。

    312eccf5738d96e7361809409c63983a.png

    个推预编译插件是一个基于语法树的流程,它经过词法分析产生token流,再通过语法分析进行模板匹配执行相应的预编译指令。

    f5c7f80fe71d070c49b7c6d1cce38537.png

    基于Antenna进行了改进的个推预编译插件,不仅支持集成到gradle,还简化了配置文件的流程。插件支持常见的预编译指令,如条件编译、宏定义、debug、mdebug等。

    8f842370a014f44bf3eb1449bf208a0a.png

    插件在Antenna上进行了类型扩展,支持float、double类型扩展;在表达式操作进行了扩展,提供了字符串的startwith、endwith等操作。

    e446f13f563875f184f42c4d26b70d1e.png

    预编译指令在安卓中的使用场景

    开发者经常需要输出一些调试信息,这些调试信息无法带到线上,开发者需要在发包时手动删除,并在再次调试时进行添加,这个过程不仅效率低,而且容易出现漏删的情况。

    通过预编译指令,开发者可以在调试时加上预编译指令debug,在发线上包时,执行预编译指令,注释掉不必要的信息。提高开发效率的同时,大大减少了因遗漏导致的安全隐患。

    2eeffd5cb2ebed4fa1d984c8838477ec.png

    f3d8511059ec79a5ea478493d2636037.png

    个推日志混淆插件个推预编译插件目前正处于代码整理阶段,未来这两个项目都会提供开源,帮助开发者打造一个既安全又高效的开发环境。

    展开全文
  • 但是发现visualdl展现的histograms似乎不是很直观,尤其是对histogram的第二个参数的意义不是很理解,它与参数维度以及展示的图片之间的关系是什么? with logger.mode("train") as writer: ...
  • 但是 以目前的展现形式,首页打开后,以看板形式展示的目录,应该是:例如 部门名称/产品线名称 等,这个层级。然后点进去,可以再是各种卡片,例如:产品需求&#...
  • 数据结构课程设计抽到了用栈和队列解决迷宫问题题目,小组突发奇想为什么不把结果使用可视化程序展现出来呢,因为DOS窗口里只会立即显示结果没有动态迷宫路径展示。 本篇博客实现了数据结构迷宫问题可视化解决程序...

    数据结构课程设计抽到了用栈和队列解决迷宫问题的题目,小组突发奇想为什么不把结果使用可视化程序展现出来呢,因为DOS窗口里只会立即显示结果没有动态迷宫路径展示。
    本篇博客实现了数据结构迷宫问题可视化解决程序。
    先上一些效果图。
    首先迷宫支持文件导入与手动输入。
    文件导入(txt)
    在这里插入图片描述

    在这里插入图片描述
    手动输入
    在这里插入图片描述
    点击生成迷宫与运行后会展示迷宫路径,动态,博客不便于展示。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    同时路径也会显示在输出结果栏目中。
    话不多说,上源代码。
    Qt目录
    在这里插入图片描述
    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QLineEdit>
    #include <QMainWindow>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fstream>
    #include <typeinfo>
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <QDebug>
    #include "QFileDialog"
    #include <QtMath>
    #include <QPainter>
    #include <QPaintEvent>
    #include <QPointF>
    #include <QMessageBox>
    #include <QPropertyAnimation>
    #include <QTimer>
    using namespace std;
    #define OK 1
    #define ERROR 0
    #define MAXSIZE 100
    typedef int Status;
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    struct node {
        int x;
        int y;
        char orientation;
    };
    
    typedef struct snode {
        node pos;
        struct snode* next;
    }snode;
    
    typedef struct linkstack {
        snode* top;
        snode* bottom;
        int length;
    }linkstack;
    
    typedef struct
    {
        int rx;				//位置x坐标
        int cy;				//位置y坐标
    }Set;
    typedef struct
    {
        Set data[MAXSIZE];
        int length;			//路径长度
    } PathType;//定义路径类型
    
    struct Move
    {
        int x;
        int y;
    };//移动方向坐标
    
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        bool GenerateMaze(int irow, int icol, QString text);
        void readInput();
        Status showPath(linkstack S);
        Status destroyStack(linkstack* S);
        ~MainWindow();
    
        Status creat(linkstack *S);
        bool empty(linkstack S);
        int size(linkstack S);
        Status push(linkstack *S, node pos);
        Status pop(linkstack *S);
        Status gettop(linkstack S, node &pos);
        void paintPath();
        void useStack();
        void useRecursion(int xis, int yis, int xes, int yes, PathType paths, int maze[8][8]);
    private slots:
        void on_pushButton_clicked();
    
        void on_pushButton_2_clicked();
    
        void on_pushButton_3_clicked();
    
        void on_pushButton_4_clicked();
        void paintEvent(QPaintEvent *);
    
    private:
        Ui::MainWindow *ui;
        int row = 0;
        int col = 0;
        int flag = false;
        int num = 0;
        int minpath = 100, b = 0;//求最短路径
        int maze[8][8] = {1};
        QString str;
        Move mov[4] = { {-1,0},{0,1},{1,0},{0,-1} };//四个移动方向,右下左上
        bool isCall = false;
        bool isDone = false;
        int pointCount = 1;
        int pathCount = 0;
        QLineEdit* input[MAXSIZE];
        QTimer *timer;
        QPointF point;
        QPointF points[MAXSIZE];
        QPointF path[MAXSIZE];
        QPointF currentPoint;
        QPointF nextPoint;
    };
    #endif // MAINWINDOW_H
    
    

    main.cpp

    #include "mainwindow.h"
    
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.setWindowTitle("迷宫可视化");
        w.setFixedSize(1200, 800);
        w.show();
        return a.exec();
    }
    
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    
    /*
                上N
            左W  x   东E
                下S
    */
    
    Status MainWindow::creat(linkstack* S) {//创建一个空栈
        S->top = S->bottom = (snode*)malloc(sizeof(snode));
        if (!S->top) {
            ui->label_3->setText("申请空间失败!");
            return ERROR;
        }
        S->top->next = NULL;
        S->bottom->next = NULL;
        S->length = 0;
        return OK;
    }
    bool MainWindow::empty(linkstack S) {//判断栈是否为空
        return !S.length;
    }
    int MainWindow::size(linkstack S) {//返回栈的大小
        return S.length;
    }
    Status MainWindow::push(linkstack* S, node pos) {//元素入栈
        snode* newx = (snode*)malloc(sizeof(snode));//新结点
        if (!newx) {//创建失败
            ui->label_3->setText("申请空间失败!");
            return ERROR;
        }
        newx->pos = pos;//新结点的pos赋值
        newx->next = S->top->next;//入栈
        S->top->next = newx;
        if (!S->length)//length = 0
            S->bottom = S->bottom->next;
        S->length++;
        return OK;
    }
    Status MainWindow::pop(linkstack* S) {//弹出栈顶元素
        if (!S->length) {
            ui->label_3->setText("当前栈已经为空!");
            return ERROR;
        }
        snode* del = S->top->next;
        S->top->next = del->next;
        free(del);
        S->length--;
        return OK;
    }
    Status MainWindow::gettop(linkstack S, node& pos) {//获得栈顶元素 存到pos中
        if (!S.length) {
            ui->label_3->setText("当前栈已经为空!");
            return ERROR;
        }
        pos = S.top->next->pos;
        return OK;
    }
    Status MainWindow::showPath(linkstack S) {//输出当前栈的内容
        qDebug() << "showPath开始执行";
        if (!S.length) {
            ui->label_3->setText("空!");
            return ERROR;
        }
        snode* p = S.top->next;
        QString str = "栈:";
        while (p) {
            QString s1 = QString::number(p->pos.x);
            QString s2 = QString::number(p->pos.y);
            QString s3;
            if(p->next && s1 == QString::number(p->next->pos.x) && s2 < QString::number(p->next->pos.y))//比如<1,1,E>→<1,2,x>
                s3 = QString("E");
            if(p->next && s1 == QString::number(p->next->pos.x) && s2 > QString::number(p->next->pos.y))//比如<2,2,W>→<2,1,x>
                s3 = QString("W");
            if(p->next && s2 == QString::number(p->next->pos.y) && s1 < QString::number(p->next->pos.x))//比如<1,1,S>→<2,1,x>
                s3 = QString("S");
            if(p->next && s2 == QString::number(p->next->pos.x) && s1 > QString::number(p->next->pos.y))//比如<2,1,N>→<1,1,x>
                s3 = QString("N");
    
            if(!(p->next))
            {
                str += "<"+s1+","+s2 + ">";
            }
            else
            {
                str += "<"+s1+","+s2+","+s3+">";
            }
            path[pathCount] = QPointF(input[(p->pos.x - 1) * col + p->pos.y - 1]->pos().x() + 20,input[(p->pos.x - 1) * col + p->pos.y - 1]->pos().y() + 20);
    
            p = p->next;
            pathCount++;
            if(pathCount == 9)
                str += '\n';
            qDebug() << str;
        }
        ui->label_3->setText(str);
        qDebug() << "showPath执行完毕";
        return OK;
    
    }
    Status MainWindow::destroyStack(linkstack* S) {//销毁当前栈
        snode* del;
        while (S->top) {
            del = S->top;
            S->top = S->top->next;
            free(del);
        }
        S->top = S->bottom = NULL;
        return OK;
    }
    void MainWindow::readInput()//读取用户在lineedit里输入的数据
    {
        int k = 0;
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                maze[i][j] = 1;
            }
        }
        for(int i = 0, m = 1; i < row; i++, m++)//显示lineedit
        {
            for (int j = 0, n = 1;j < col; j++, k++, n++) {
                if(j < col/2)
                    maze[m][n] = input[k]->text().toInt();
                else
                    maze[m][n] = input[k]->text().toInt();
            }
        }
        for (int i = 0; i < col*row; i++) {
            qDebug() << input[i]->text();
        }
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                qDebug() << "maze[i][j]" << i << j << maze[i][j];
            }
        }
        qDebug() << "readInput执行完毕";
    }
    bool MainWindow::GenerateMaze(int irow, int icol, QString text)
    {
        int k = 0;
        qDebug() << "GenerateMaze开始执行";
        QFont font("黑体", 20, 75); //第一个属性是字体(微软雅黑),第二个是大小,第三个是加粗(权重是75)
        row = irow;//迷宫高度是行数
        col = icol;//迷宫宽度是列数
        QRegExp regx("[0-1]+$");//lineedit只允许设置0或1
        for(int i = 0; i < row*col; i++)//生成row*col个lineedit
        {
            input[i] = new QLineEdit(QString::asprintf("0"), this);//最后一个参数一定为一个“父窗体”!
            input[i]->setMaxLength(1);
            input[i]->setAlignment(Qt::AlignHCenter);//内容居中显示
            input[i]->setFont(font);//字体设置
            if(i == 0)
                input[i]->setStyleSheet("background-color:green");
            if(i == row*col - 1)
                input[i]->setStyleSheet("background-color:red");
            QValidator *validator = new QRegExpValidator(regx, input[i]);
            input[i]->setValidator(validator);
            input[i]->hide();
            input[i]->show();
        }
        if(text != nullptr)
        {
            for (int i = 0; i < row*col; i++) {
                QString temp(text[i]);
                input[k++]->setText(temp);
            }
        }
        if(col%2)//col是奇数
        {
            int k = 0;
            int x = 600 - 20 - col/2*80;//控件初始位置,1200/2 = 600,20是靠近中轴线的lineedit与中轴线的距离,两个lineedit距离为40,中轴线左边有col/2个lineedit和空挡。
            int y = 40;//第一行lineedit和窗口顶部的距离
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    input[k++]->setGeometry(x + j*80, y + i*80,40,40);
                }
            }
        }
        else//col是偶数
        {
            int k = 0;
            int x = 600 - 20 - col/2*40 - (col/2 - 1)*40;
            int y = 40;
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    input[k++]->setGeometry(x + j*80, y + i*80,40,40);
                }
            }
        }
        for (int i = 0; i < row*col; i++) {
            points[i] = QPointF(input[i]->pos().x(), input[i]->pos().y());
        }
        ui->pushButton->setEnabled(false);//一旦生成迷宫之后就不能再点击了,主要原因是input数组已经生成了,如果再点击,那么新生成的input也会出现在屏幕上,原先的linneedit不会消失
        qDebug() << "GenerateMaze执行完毕";
        return OK;
    }
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        ui->pushButton_2->setEnabled(false);
        ui->pushButton_4->setEnabled(false);
    
    }
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    void MainWindow::on_pushButton_clicked()//生成迷宫按钮按下时
    {
        GenerateMaze(ui->spinBox_2->value(),ui->spinBox->value(), nullptr);//出现迷宫
        for (int i = 0; i < row*col; i++)
            input[i]->show();
        ui->pushButton_2->setEnabled(true);
    }
    void MainWindow::on_pushButton_2_clicked()//运行按钮按下时
    {
        readInput();
        useStack();
    //    PathType paths;
    //    paths.length = 0;	//初始化路径长度
    //    useRecursion(1, 1, row, col, paths, maze);
    //    ui->label_4->setText(str);
    //    if (b == 0)
    //        ui->label_4->setText("空!");
    }
    void MainWindow::on_pushButton_3_clicked()//导入txt文件
    {
        int irow = 0, icol = 0;
        QString text;
        QStringList infoList;
        //获取文件名
        QString fileName = QFileDialog::getOpenFileName(
                    this,
                    tr("导入文件"),
                    "",
                    tr("text(*.txt)"));
        if (fileName.isEmpty())
        {
            QMessageBox::warning(this, "错误", "打开文件失败!");
        }
        else
        {
            QFile file(fileName);
            //打开文件
            if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
            {
                qDebug()<<"无法打开!"<<endl;
            }
            //循环读取txt  并打印
            while(!file.atEnd())
            {
                QByteArray line = file.readLine();
                QString str(line);
                if(str.contains("\n"))
                {
                    str = str.replace("\n" , "");
                }
                qDebug()<< str;
    
                icol = str.length() - 2;
                irow++;
                text += str.mid(1,icol);
            }
    
            irow -= 2;
            qDebug() << text;
            text = text.mid(icol,icol*irow);
            qDebug() << irow;
            qDebug() << icol;
            qDebug() << text;
            ui->pushButton_4->setEnabled(true);
        }
        GenerateMaze(irow, icol, text);
    
    }
    void MainWindow::on_pushButton_4_clicked()//导入txt文件后运行
    {
        isCall = true;
        readInput();
        int sx = 1, sy = 1, ex = row, ey = col;//sx,sy是startx,starty即迷宫起始位置,对应的是迷宫的下标,ex,ey是endx,endy是endx,endy即迷宫终点位置。
        node now;//当前位置
        now.x = sx;
        now.y = sy;
        now.orientation = 'E';
        maze[sx][sy] = -1;//走过了
    
        linkstack s;
        creat(&s);创建一个空栈
        push(&s, now);//将now的信息亚展
        while (!empty(s)) {
            gettop(s, now);//获得栈顶元素 存到now中
            if (now.x == ex && now.y == ey)//now的x和y位置到达迷宫终点
                break;//终点
    
            if (!maze[now.x][now.y + 1]) {//右 为0表示可以走
                now.orientation = 'E';
                node next = now;
                next.y = now.y + 1;//向右走一步
                maze[next.x][next.y] = -1;//走过了置-1
                push(&s, next);
                continue;
            }
            //以下同理
            if (!maze[now.x + 1][now.y]) {//下
                now.orientation = 'S';
                node next = now;
                next.x = now.x + 1;
                maze[next.x][next.y] = -1;
                push(&s, next);
                continue;
            }
            if (!maze[now.x][now.y - 1]) {//左
                now.orientation = 'W';
                node next = now;
                next.y = now.y - 1;
                maze[next.x][next.y] = -1;
                push(&s, next);
                continue;
            }
            if (!maze[now.x - 1][now.y]) {//上
                now.orientation = 'N';
                node next = now;
                next.x = now.x - 1;
                maze[next.x][next.y] = -1;
                push(&s, next);
                continue;
            }
            pop(&s);
        }
        linkstack path;
        creat(&path);
        node step;
        while (!empty(s)) {
            gettop(s, step);
            push(&path, step);
            pop(&s);
        }//换成正向
        showPath(path);
        paintPath();
        qDebug() << "执行完毕";
        destroyStack(&s);
        destroyStack(&path);
    }
    void MainWindow::paintPath()//绘制路径函数
    {
        timer = new QTimer(this);
        currentPoint = path[0];
        nextPoint = path[1];
        timer->start(50);
        qDebug() << "path0" << path[0];
        qDebug() << "path1" << path[1];
        qDebug() << "path2" << path[2];
        qDebug() << "path3" << path[3];
        qDebug() << "path4" << path[4];
        qDebug() << "path5" << path[5];
        qDebug() << "path6" << path[6];
        qDebug() << "path[][]" << path[pathCount - 1];
        connect(timer, &QTimer::timeout,this,[=](){
            static int i = 0;
            static int j = 0;
            static int k = 2;
            double x = path[0].x() + 10*i;
            qDebug() << "x" << x;
            qDebug() << "i" << i;
            double y = path[0].y()+ 10*j;
            qDebug() << "y" << y;
            qDebug() << "j" << j;
            update();
            if(x == nextPoint.x())
            {
                point.setX(x);
                point.setY(y);
                if(y <= nextPoint.y()){
                    ++j;}
                else
                    --j;
                if(y == nextPoint.y())
                {
    
                    // --j;
                    currentPoint = QPointF(nextPoint.x(),nextPoint.y());
                    qDebug() << "currentPoint" << currentPoint;
                    nextPoint = path[k++];
                    qDebug() << "nextPoint" << nextPoint;
                    qDebug() << "到达一个点了";
                    pointCount++;
                    if(x > nextPoint.x())
                    {
                        --j;
                    }
                    if(x < nextPoint.x())
                    {
                        --i;
                        --j;
                    }
                    if(y < nextPoint.y()){}
                    if(nextPoint == QPointF(0,0)){
                        input[row*col - 1]->setStyleSheet("background-color:green");
                        qDebug() << "已经到达终点";
                        timer->stop();
                    }
                }
    
            }
            if(y == nextPoint.y())
            {
                point.setX(x);
                point.setY(y);
                if(x <= nextPoint.x())
                    ++i;
                else
                    --i;
                if(x == nextPoint.x())
                {
                    currentPoint = QPointF(nextPoint.x(),nextPoint.y());
                    qDebug() << "currentPoint" << currentPoint;
                    nextPoint = path[k++];
                    qDebug() << "nextPoint" << nextPoint;
                    qDebug() << "到达一个点了";
                    pointCount++;
                    if(x < nextPoint.x()){}
                    if(y > nextPoint.y())
                        --i;
                    if(y < nextPoint.y())
                    {
                        --i;
                        --j;
                    }
                    if(nextPoint == QPointF(0,0)){
                        input[row*col - 1]->setStyleSheet("background-color:green");
                        qDebug() << "已经到达终点";
                        timer->stop();
                    }
                }
            }
            qDebug() << x << "," << y;
        });
    
    }
    
    void MainWindow::useStack()
    {
        isCall = true;
        int sx = 1, sy = 1, ex = row, ey = col;//sx,sy是startx,starty即迷宫起始位置,对应的是迷宫的下标,ex,ey是endx,endy是endx,endy即迷宫终点位置。
        node now;//当前位置
        now.x = sx;
        now.y = sy;
        now.orientation = 'E';
        maze[sx][sy] = -1;//走过了
    
        linkstack s;
        creat(&s);创建一个空栈
        push(&s, now);//将now的信息入栈
        while (!empty(s)) {
            gettop(s, now);//获得栈顶元素 存到now中
            if (now.x == ex && now.y == ey)//now的x和y位置到达迷宫终点
                break;//终点
    
            if (!maze[now.x][now.y + 1]) {//右 为0表示可以走
                now.orientation = 'E';
                node next = now;
                next.y = now.y + 1;//向右走一步
                maze[next.x][next.y] = -1;//走过了置-1
                push(&s, next);
                continue;
            }
            //以下同理
            if (!maze[now.x + 1][now.y]) {//下
                now.orientation = 'S';
                node next = now;
                next.x = now.x + 1;
                maze[next.x][next.y] = -1;
                push(&s, next);
                continue;
            }
            if (!maze[now.x][now.y - 1]) {//左
                now.orientation = 'W';
                node next = now;
                next.y = now.y - 1;
                maze[next.x][next.y] = -1;
                push(&s, next);
                continue;
            }
            if (!maze[now.x - 1][now.y]) {//上
                now.orientation = 'N';
                node next = now;
                next.x = now.x - 1;
                maze[next.x][next.y] = -1;
                push(&s, next);
                continue;
            }
            pop(&s);
        }
        linkstack path;
        creat(&path);
        node step;
        while (!empty(s)) {
            gettop(s, step);
            push(&path, step);
            pop(&s);
        }//换成正向
        showPath(path);
        paintPath();
        qDebug() << "执行完毕";
        destroyStack(&s);
        destroyStack(&path);
    }
    
    void MainWindow::useRecursion(int xis, int yis, int xes, int yes, PathType paths, int maze[8][8])
    {
        int k, i, j;
        str = "迷宫第" + QString::number(num) + "条路径如下:";
        if (xis == xes && yis == yes)		//找到出口,输出路径
        {
            paths.data[paths.length].rx = xis;
            paths.data[paths.length].cy = yis;
            paths.length++; num++;
            if (paths.length < minpath)
            {
                minpath = paths.length;
                b = num;
            }
            for (k = 0; k < paths.length; k++)
                str += "(" + QString::number(paths.data[k].rx) + "," + QString::number(paths.data[k].cy) + ")" + " ";
        }
        else					//(xis,yis)不是出口
        {
            if (maze[xis][yis] == 0)//(xis,yis)可走
            {
                for (int m = 0; m < 4; m++)		// 找(xis, yis)的一个相邻位置(i, j)
                {
                    i = xis + mov[m].x; j = yis + mov[m].y;
                    paths.data[paths.length].rx = xis;
                    paths.data[paths.length].cy = yis;
                    paths.length++;
                    maze[xis][yis] = -1;			//避免重复找路径
                    useRecursion(i, j, xes, yes, paths, maze);
                    paths.length--;			//回退一个位置
                    maze[xis][yis] = 0;			//恢复(xis,yis)为可走
                }
            }
        }
    }
    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
        QPainter p(this);
        p.setRenderHint(QPainter::Antialiasing, true);
        p.setPen(QPen(Qt::green, 3));
        if(isCall)
        {
            p.drawPolyline(path,pointCount);
            p.drawLine(currentPoint,point);
        }
        else{}
    }
    
    

    UI布局
    在这里插入图片描述
    在这里插入图片描述
    课程设计成绩最终也拿到了优秀,算是值了。不过由于时间匆忙,还有一些bug没有解决,但自己又懒,实在是不想再看咯。

    以上 如果此篇博客对您有帮助欢迎点赞与转发 有疑问请留言或私信 2021/1/12

    展开全文
  • 打开网站,满眼的图片和动画特效,看起来网站是华丽了,但是这些却影响了网站内容的展示。用户关心的需求一点都没有展现,而且搜索引擎识别的是网站的文字,而非这些动画和特效。 (2)页面代码结构陈旧 有的网站...
  • 第二部分将会介绍webpack内部插件与钩子关系可视化展示工具📈,用一张图理清webpack内部这种错综复杂关系。 <p><strong>可视化工具使用效果图:</strong></p> <p><img alt="" src=...
  • 你该如何向众人展现大量信息,从而 使他们能迅速找到所需信息呢?这本经典之作将教导信息架构师、设计师 及网站开发人员建立大型网站,使网站能够被管理,充满魅力,并且易于用 户浏览。 新版《Web信息架构:...
  • 你该如何向众人展现大量信息,从而 使他们能迅速找到所需信息呢?这本经典之作将教导信息架构师、设计师 及网站开发人员建立大型网站,使网站能够被管理,充满魅力,并且易于用 户浏览。 新版《Web信息架构:...
  • 数据在页面上是一个扁平,不带数据类型字符串,无论你数据结构有多复杂,数据类型有多丰富,到了展示的时候,全都一视同仁成为字符串在页面上展现出来。  2.数据在Java世界中可以表现为丰富数据结构和...
  • 包含了数据分析的结构化思维、数据处理技巧、数据展现的技术,很能帮我们提升职场竞争能力。找不到工作的,学好了它,自然没问题。第2本《拯救你的Excel数据的分析、处理、展示(动画版)》一本用手机...
  • 这个应该是最简单的了,基本上是纯静态页面的展示,就算有交互模块,应该也是比较简单的那种。 2、门户类型网站的开发与维护 例如像搜狐一样的门户网站,相对来说也不难,这种网站一般分成很多个模块,每个模块的...
  • HTML是告诉浏览器接收到数据使用什么数据组织形式进行展示。 使用:HTML标准文档规范和HTML标签。 二.HTML三大基石 URL:统一资源定位符(唯一定位一个网络资源)。 HTTP:超文本传输协议(规范...
  • 数据可视化用途

    2020-03-12 10:07:00
    大数据可视化,就是指将结构或非结构数据转换成适当可视化图表,然后将隐藏在数据中信息直接展现于人们面前。那数据可视化优势在于合成呢? 展示需要相比传统用表格或文档展现数据方式,可视化能将数据以...
  • Vue前端路由优缺点

    千次阅读 2019-05-20 22:55:00
    路由是根据不同 url 地址展示不同内容或页面 前端路由就是把不同路由对应不同内容或页面任务交给前端来做,之前是通过服务端根据 url 不同返回不同页面实现 二、什么时候使用前端路由 在单页面应用...
  • Express中MVC

    2020-05-07 20:06:21
    什么是MVC模式 1, MVC模式是为了解决应用开发中代码增加后变得难以维护和复用问题而被提...3, View为视图,体现为最终展现给用户(广义,比如客户端)形式,View根据一个或者多个Model数据进行展示 4, Control...
  • 随着数据在当下互联网快速发展下变维度更广,数量更大、结构越来越复杂,人们想要更加清晰,快速认知和理解一份数据,传统二维平面图表已经不能满足需求,三维可视化技术越结合多媒体技术、网络技术以及三维...
  • 如何在保证安全性前提下,提升开发过程效率,是每个开发者都在不断探索问题。借助语法树,开发者能够更好地展现和修改源...语法树是一种树状结构的源程序代码呈现方式,它可以很好地展示源程序代码信息,...
  • 展现自信  7.5 特殊类型面试  7.5.1 电话面试  7.5.2 人事筛选面试  7.5.3 午餐面试  7.5.4 后续面试  7.6 面试结束之后应该做事  7.6.1 感谢信  7.6.2 从招聘人员那里了解后续进展  ...
  • 13.3.2 建立合理网站结构与网站地图应用 795 13.3.3 设计良好网页结构 798 13.3.4 seo基本功——关键词选用 800 13.3.5 域名与空间对seo影响 802 13.3.6 搜索引擎偏爱“勤快”网站 804 13.4 搜索...
  • 网络营销师古志强: SEM4:创意 ...3.普通创意要素:标题、描述、URL【展示的结构】 4.飘红:展现结果中与搜索词字面、语义相同字词显示为红色。(地域飘红、字段飘红、通配符飘红) 作用:
  • 大数据可视化,就是指将结构或非结构数据转换成适当可视化图表,然后将隐藏在数据中信息直接展现于人们面前。那数据可视化优势在于合成呢? 1. 展示需要相比传统用表格或文档展现数据方式...
  •  关于Oracle优化书在图书市场上并不少见,但有些图书内容陈旧,或是主要提供一些脚本风格案例展示,系统化且有深度优化图书并不多。这本Troubleshooting Oracle Performance(TOP)是从2008年到现在国外...
  • 对于测试帖,可以使用 Sandbox 机制:带有 Sandbox 标签帖子将视为测试帖,不会显示在首页或是某领域内,只会展现在发帖者自己帖子列表中。 人性化回帖交互 实时呈现:回帖提交后其他浏览者可以不刷新...
  • UML可视化的特性是由各种视图来展现的,每一种视图都从不同的角度对同一个软件产品的方方面面进行展示,说明将要开发的软件到底是什么样子。描述软件和描述现实世界一样,一方面我们需要描述系统的结构性特征,结构...
  • Vue学习之前端路由

    2018-11-18 11:12:09
    路由是根据不同url地址展示不同内容或页面 前端路由就是把不同路由对应不同内容或页面任务交给前端来做,之前是通过服务端根据url不同返回不同页面实现 什么时候使用前端路由 在单页面应用,大部分...

空空如也

空空如也

1 2 3 4 5 6
收藏数 107
精华内容 42
关键字:

展现的展示什么结构