python 可视化监控平台_python可视化篇之流式数据监控的实现

preface

流式数据的监控,以下主要是从算法的呈现出发,提供一种python的实现思路

其中:

1.python是2.X版本

2.提供两种实现思路,一是基于matplotlib的animation,一是基于matplotlib的ion

话不多说,先了解大概的效果,如下:

2019080710351034.gif

一、一点构思

在做此流数据输出可视化前,一直在捣鼓nupic框架,其内部HTM算法主要是一种智能的异常检测算法,是目前AI框架中垂直领域下的一股清流,但由于其实现的例子对应的流数据展示并非我想要的,故此借鉴后自己重新写了一个,主要是达到三个目的,一是展示真实数据的波动,二是展示各波动的异常得分,三是罗列异常的点。

上述的输出结构并非重点,重点是其实时更新的机制,了解后即可自行定义。另,js对于这种流数据展示应该不难,所以本文主要立足的是算法的呈现角度以及python的实现。

二、matplotlib animation实现思路

(一)、骨架与实时更新

animation翻译过来就是动画,其动画展示核心主要有三个:1是动画的骨架先搭好,就是图像的边边框框这些,2是更新的过程,即传入实时数据时图形的变化方法,3是FuncAnimation方法结尾。

下面以一个小例子做进一步说明:

1.对于动画的骨架:

# initial the figure.

x = []

y = []

fig = plt.figure(figsize=(18, 8), facecolor="white")

ax1 = fig.add_subplot(111)

p1, = ax1.plot(x, y, linestyle="dashed", color="red")

以上分别对应初始化空数据,初始化图形大小和背景颜色,插入子图(三个数字分别表示几行几列第几个位置),初始化图形(数据为空)。

import numpy as np

x = np.arange(0, 1000, 1)

y = np.random.normal(100, 10, 1000)

随机生成一些作图数据,下面定义update过程。

2.对于更新过程:

def update(i):

x.append(xs[i])

y.append(ys[i])

ax1.set_xlim(min(x),max(x)+1)

ax1.set_ylim(min(y),max(y)+1)

p1.set_data(x,y)

ax1.figure.canvas.draw()

return p1

上述定义更新函数,参数i为每轮迭代从FuncAnimation方法frames参数传进来的数值,frames参数的指定下文会进一步说,x/y通过相应更新之后,对图形的x/y轴大小做相应的重设,再把数据通过set_data传进图形,注意ax1和p1的区别,最后再把上述的变化通过draw()方法绘制到界面上,返回p1给FuncAnimation方法。

3.对于FuncAnimation方法:

ani = FuncAnimation(fig=fig,func=update,frames=len(xs),interval=1)

plt.show()

FuncAnimation方法主要是与update函数做交互,将frames参数对应的数据逐条传进update函数,再由update函数返回的图形覆盖FuncAnimation原先的图形,fig参数即为一开始对应的参数,interval为每次更新的时间间隔,还有其他一些参数如blit=True控制图形精细,当界面较多子图时,为True可以使得看起来不会太卡,关键是frames参数,下面是官方给出的注释:

2019080710351035.jpg

可为迭代数,可为函数,也可为空,上面我指定为数组的长度,其迭代则从0开始到最后该数值停止。

该例子最终呈现的效果如下:

2019080710351036.gif

了解大概的实现,细节就不在这里多说了。

(二)、animation的优缺点

animation的绘制的结果相比于下文的ion会更加的细腻,主要体现在FuncAnimation方法的一些参数的控制上。但是缺点也是明显,就是必须先有指定的数据或者指定的数据大小,显然这样对于预先无法知道数据的情况没法处理。所以换一种思路,在matplotlib ion打开的模式下,每次往模板插入数据都会进行相应的更新,具体看第二部分。

三、matplotlib ion实现思路

(一)、实时更新

matplotlib ion的实现也主要是三个核心,1是打开ion,2是实时更新机制,3是呈现在界面上。

1.对于打开ion:

ion全称是 interactive on(交互打开),其意为打开一个图形的交互接口,之后每次绘图都在之前打开的面板上操作,举个例子:

import matplotlib.pyplot as plt

plt.ion()

fig = plt.figure()

ax1 = fig.add_subplot(111)

line, = ax1.plot(t, v, linestyle="-", color="r")

打开交互接口,初始化图形。

2.对于实时更新机制:

import numpy as np

ys = np.random.normal(100, 10, 1000)

def p(a, b):

t.append(a)

v.append(b)

ax1.set_xlim(min(t), max(t) + 1)

ax1.set_ylim(min(v), max(v) + 1)

line.set_data(t, v)

plt.pause(0.001)

ax1.figure.canvas.draw()

for i in xrange(len(ys)):

p(i, ys[i])

随机生成一组数据,定义作图函数p(包含pause表示暂定时延,最好有,防止界面卡死),传入数据实时更新。

3.对于界面最终呈现

plt.ioff()

plt.show()

ioff是关闭交互模式,就像open打开文件产生的句柄,最好也有个close关掉。

最终效果如下:

2019080710351137.gif

(二)、ion的优缺点

animation可以在细节上控制比ion更加细腻,这也是ion没有的一点,但是单就无需预先指定数据这一点,ion也无疑是能把流数据做得更加好。

四、最后

贴一下两种方法在最开始那种图的做法,ion我定义成类,这样每次调用只需穿入参数就可以。

animation版本

# _*_ coding:utf-8 _*_

import os

import csv

import datetime

import matplotlib.pyplot as plt

from matplotlib.animation import FuncAnimation

from matplotlib.dates import DateFormatter

import matplotlib.ticker as ticker

# read the file

filePath = os.path.join(os.getcwd(), "data/anomalyDetect_output.csv")

file = open(filePath, "r")

allData = csv.reader(file)

# skip the first three columns

allData.next()

allData.next()

allData.next()

# cache the data

data = [line for line in allData]

# for i in data: print i

# take out the target value

timestamp = [line[0] for line in data]

value = [line[1:] for line in data]

# format the time style 2016-12-01 00:00:00

def timestampFormat(t):

result = datetime.datetime.strptime(t, "%Y-%m-%d %H:%M:%S")

return result

# take out the data

timestamp = map(timestampFormat, timestamp)

value_a = [float(x[0]) for x in value]

predict_a = [float(x[1]) for x in value]

anomalyScore_a = [float(x[2]) for x in value]

# initial the size of the figure

fig = plt.figure(figsize=(18, 8), facecolor="white")

fig.subplots_adjust(left=0.06, right=0.70)

ax1 = fig.add_subplot(2, 1, 1)

ax2 = fig.add_subplot(2, 1, 2)

ax3 = fig.add_axes([0.8, 0.1, 0.2, 0.8], frameon=False)

# initial plot

p1, = ax1.plot_date([], [], fmt="-", color="red", label="actual")

ax1.legend(loc="upper right", frameon=False)

ax1.grid(True)

p2, = ax2.plot_date([], [], fmt="-", color="red", label="anomaly score")

ax2.legend(loc="upper right", frameon=False)

ax2.axhline(0.8, color='black', lw=2)

# add the x/y label

ax2.set_xlabel("date time")

ax2.set_ylabel("anomaly score")

ax1.set_ylabel("value")

# add the table in ax3

col_labels = ["date time", 'actual value', 'predict value', 'anomaly score']

ax3.text(0.05, 0.99, "anomaly value table", size=12)

ax3.set_xticks([])

ax3.set_yticks([])

# axis format

dateFormat = DateFormatter("%m/%d %H:%M")

ax1.xaxis.set_major_formatter(ticker.FuncFormatter(dateFormat))

ax2.xaxis.set_major_formatter(ticker.FuncFormatter(dateFormat))

# define the initial function

def init():

p1.set_data([], [])

p2.set_data([], [])

return p1, p2

# initial data for the update function

x1 = []

x2 = []

x1_2 = []

y1_2 = []

x1_3 = []

y1_3 = []

y1 = []

y2 = []

highlightList = []

turnOn = True

tableValue = [[0, 0, 0, 0]]

# update function

def stream(i):

# update the main graph(contains actual value and predicted value)

# add the data

global turnOn, highlightList, ax3

x1.append(timestamp[i])

y1.append(value_a[i])

# update the axis

minAxis = max(x1) - datetime.timedelta(days=1)

ax1.set_xlim(minAxis, max(x1))

ax1.set_ylim(min(y1), max(y1))

ax1.figure.canvas.draw()

p1.set_data(x1, y1)

# update the anomaly graph(contains anomaly score)

x2.append(timestamp[i])

y2.append(anomalyScore_a[i])

ax2.set_xlim(minAxis, max(x2))

ax2.set_ylim(min(y2), max(y2))

# update the scatter

if anomalyScore_a[i] >= 0.8:

x1_3.append(timestamp[i])

y1_3.append(value_a[i])

ax1.scatter(x1_3, y1_3, s=50, color="black")

# update the high light

if anomalyScore_a[i] >= 0.8:

highlightList.append(i)

turnOn = True

else:

turnOn = False

if len(highlightList) != 0 and turnOn is False:

ax2.axvspan(timestamp[min(highlightList)] - datetime.timedelta(minutes=10),

timestamp[max(highlightList)] + datetime.timedelta(minutes=10),

color='r',

edgecolor=None,

alpha=0.2)

highlightList = []

turnOn = True

p2.set_data(x2, y2)

# add the table in ax3

# update the anomaly tabel

if anomalyScore_a[i] >= 0.8:

ax3.remove()

ax3 = fig.add_axes([0.8, 0.1, 0.2, 0.8], frameon=False)

ax3.text(0.05, 0.99, "anomaly value table", size=12)

ax3.set_xticks([])

ax3.set_yticks([])

tableValue.append([timestamp[i].strftime("%Y-%m-%d %H:%M:%S"), value_a[i], predict_a[i], anomalyScore_a[i]])

if len(tableValue) >= 40: tableValue.pop(0)

ax3.table(cellText=tableValue, colWidths=[0.35] * 4, colLabels=col_labels, loc=1, cellLoc="center")

return p1, p2

# main animated function

anim = FuncAnimation(fig, stream, init_func=init, frames=len(timestamp), interval=0)

plt.show()

file.close()

ion版本

#! /usr/bin/python

import os

import csv

import datetime

import matplotlib.pyplot as plt

from matplotlib.animation import FuncAnimation

from matplotlib.dates import DateFormatter

import matplotlib.ticker as ticker

class streamDetectionPlot(object):

"""

Anomaly plot output.

"""

# initial the figure parameters.

def __init__(self):

# Turn matplotlib interactive mode on.

plt.ion()

# initial the plot variable.

self.timestamp = []

self.actualValue = []

self.predictValue = []

self.anomalyScore = []

self.tableValue = [[0, 0, 0, 0]]

self.highlightList = []

self.highlightListTurnOn = True

self.anomalyScoreRange = [0, 1]

self.actualValueRange = [0, 1]

self.predictValueRange = [0, 1]

self.timestampRange = [0, 1]

self.anomalyScatterX = []

self.anomalyScatterY = []

# initial the figure.

global fig

fig = plt.figure(figsize=(18, 8), facecolor="white")

fig.subplots_adjust(left=0.06, right=0.70)

self.actualPredictValueGraph = fig.add_subplot(2, 1, 1)

self.anomalyScoreGraph = fig.add_subplot(2, 1, 2)

self.anomalyValueTable = fig.add_axes([0.8, 0.1, 0.2, 0.8], frameon=False)

# define the initial plot method.

def initPlot(self):

# initial two lines of the actualPredcitValueGraph.

self.actualLine, = self.actualPredictValueGraph.plot_date(self.timestamp, self.actualValue, fmt="-",

color="red", label="actual value")

self.predictLine, = self.actualPredictValueGraph.plot_date(self.timestamp, self.predictValue, fmt="-",

color="blue", label="predict value")

self.actualPredictValueGraph.legend(loc="upper right", frameon=False)

self.actualPredictValueGraph.grid(True)

# initial two lines of the anomalyScoreGraph.

self.anomalyScoreLine, = self.anomalyScoreGraph.plot_date(self.timestamp, self.anomalyScore, fmt="-",

color="red", label="anomaly score")

self.anomalyScoreGraph.legend(loc="upper right", frameon=False)

self.baseline = self.anomalyScoreGraph.axhline(0.8, color='black', lw=2)

# set the x/y label of the first two graph.

self.anomalyScoreGraph.set_xlabel("datetime")

self.anomalyScoreGraph.set_ylabel("anomaly score")

self.actualPredictValueGraph.set_ylabel("value")

# configure the anomaly value table.

self.anomalyValueTableColumnsName = ["timestamp", "actual value", "expect value", "anomaly score"]

self.anomalyValueTable.text(0.05, 0.99, "Anomaly Value Table", size=12)

self.anomalyValueTable.set_xticks([])

self.anomalyValueTable.set_yticks([])

# axis format.

self.dateFormat = DateFormatter("%m/%d %H:%M")

self.actualPredictValueGraph.xaxis.set_major_formatter(ticker.FuncFormatter(self.dateFormat))

self.anomalyScoreGraph.xaxis.set_major_formatter(ticker.FuncFormatter(self.dateFormat))

# define the output method.

def anomalyDetectionPlot(self, timestamp, actualValue, predictValue, anomalyScore):

# update the plot value of the graph.

self.timestamp.append(timestamp)

self.actualValue.append(actualValue)

self.predictValue.append(predictValue)

self.anomalyScore.append(anomalyScore)

# update the x/y range.

self.timestampRange = [min(self.timestamp), max(self.timestamp)+datetime.timedelta(minutes=10)]

self.actualValueRange = [min(self.actualValue), max(self.actualValue)+1]

self.predictValueRange = [min(self.predictValue), max(self.predictValue)+1]

# update the x/y axis limits

self.actualPredictValueGraph.set_ylim(

min(self.actualValueRange[0], self.predictValueRange[0]),

max(self.actualValueRange[1], self.predictValueRange[1])

)

self.actualPredictValueGraph.set_xlim(

self.timestampRange[1] - datetime.timedelta(days=1),

self.timestampRange[1]

)

self.anomalyScoreGraph.set_xlim(

self.timestampRange[1]- datetime.timedelta(days=1),

self.timestampRange[1]

)

self.anomalyScoreGraph.set_ylim(

self.anomalyScoreRange[0],

self.anomalyScoreRange[1]

)

# update the two lines of the actualPredictValueGraph.

self.actualLine.set_xdata(self.timestamp)

self.actualLine.set_ydata(self.actualValue)

self.predictLine.set_xdata(self.timestamp)

self.predictLine.set_ydata(self.predictValue)

# update the line of the anomalyScoreGraph.

self.anomalyScoreLine.set_xdata(self.timestamp)

self.anomalyScoreLine.set_ydata(self.anomalyScore)

# update the scatter.

if anomalyScore >= 0.8:

self.anomalyScatterX.append(timestamp)

self.anomalyScatterY.append(actualValue)

self.actualPredictValueGraph.scatter(

self.anomalyScatterX,

self.anomalyScatterY,

s=50,

color="black"

)

# update the highlight of the anomalyScoreGraph.

if anomalyScore >= 0.8:

self.highlightList.append(timestamp)

self.highlightListTurnOn = True

else:

self.highlightListTurnOn = False

if len(self.highlightList) != 0 and self.highlightListTurnOn is False:

self.anomalyScoreGraph.axvspan(

self.highlightList[0] - datetime.timedelta(minutes=10),

self.highlightList[-1] + datetime.timedelta(minutes=10),

color="r",

edgecolor=None,

alpha=0.2

)

self.highlightList = []

self.highlightListTurnOn = True

# update the anomaly value table.

if anomalyScore >= 0.8:

# remove the table and then replot it

self.anomalyValueTable.remove()

self.anomalyValueTable = fig.add_axes([0.8, 0.1, 0.2, 0.8], frameon=False)

self.anomalyValueTableColumnsName = ["timestamp", "actual value", "expect value", "anomaly score"]

self.anomalyValueTable.text(0.05, 0.99, "Anomaly Value Table", size=12)

self.anomalyValueTable.set_xticks([])

self.anomalyValueTable.set_yticks([])

self.tableValue.append([

timestamp.strftime("%Y-%m-%d %H:%M:%S"),

actualValue,

predictValue,

anomalyScore

])

if len(self.tableValue) >= 40: self.tableValue.pop(0)

self.anomalyValueTable.table(cellText=self.tableValue,

colWidths=[0.35] * 4,

colLabels=self.anomalyValueTableColumnsName,

loc=1,

cellLoc="center"

)

# plot pause 0.0001 second and then plot the next one.

plt.pause(0.0001)

plt.draw()

def close(self):

plt.ioff()

plt.show()

下面是ion版本的调用:

graph = stream_detection_plot.streamDetectionPlot()

graph.initPlot()

for i in xrange(len(timestamp)):

graph.anomalyDetectionPlot(timestamp[i],value_a[i],predict_a[i],anomalyScore_a[i])

graph.close()

具体为实例化类,初始化图形,传入数据作图,关掉。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/431048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

codeforce 606A - Magic Spheres

题意&#xff1a;a,b,c三种球&#xff0c;能把俩个一样的球变成另一颜色不一样的球。给你目标x,y,z&#xff0c;问能否经过变化至少达打目标。 1 #include<iostream>2 #include<stdio.h>3 #include<stdlib.h>4 #include<memory.h>5 #include<string…

cmd cd 无法切换目录_一分钟掌握cmd基础操作,告别鼠标

cmd基础操作cmdcmd是command的缩写&#xff0c;一直伴随着windows操作系统。有时称为&#xff1a;控制台窗口&#xff0c;cmd窗口&#xff0c;黑窗口&#xff0c;命令行窗口等。其实&#xff0c;在unix系统&#xff0c;Linux&#xff0c;MacOS等几乎所有的操作系统中&#xff0…

css 背景图怎么设置自动填充满_CSS属性设置 -- 背景样式

Ⅰ background-color: -- 设置标签的背景颜色rgba(0,0,0,0.65); -- (红,緑,蓝三原色,透明度)只能给背景设置透明度opacity: 0.65; -- 改变整个标签的透明度<style>Ⅱ background-image: --设置标签的背景图片url("图片网址"); -- 如果图片的大小没有标签大&…

php开发客服系统(持久连接+轮询+反向ajax)

欢迎在php严程序 - php教程学习AJAX教程, 本节课讲解&#xff1a;php开发客服系统(持久连接轮询反向ajax) php开发客服系统(下载源码) 用户端(可直接给客户发送消息)客服端(点击用户名.即可给该用户回复消息) 讲两种实现方式&#xff1a;一&#xff1a;iframe 服务器推技术com…

c语言判断整数_C语言技能|(草稿,不断完善中...)

2020年春考C语言有2个题型&#xff1a;填空&#xff0b;程序程序填空涉及&#xff1a;一、头文件的引用1.必有#include (注意&#xff1a;在devC 5.10中#include "stdio.h"也是正确的)2.若程序中使用数学函数&#xff0c;应加上头文件#include 3.头文件结尾无分号二、…

python生成器迭代_python中的生成器和迭代器

前言&#xff1a; 我们来了解一下什么是python中生成器。了解一下python生成器是什么&#xff0c;以及生成器在python编程之中能起到什么样的作用。 定义&#xff1a; 生成器和迭代器 通过列表生成式&#xff0c;我们可以直接创建一个列表。但是&#xff0c;受到内存限制&#…

python 生成pdf_如何使用Python生成PDF?

在日常办公中&#xff0c;我们会经常使用PDF文件。生成PDF的方法有很多&#xff0c;其中Python就可以。你知道怎么使用Python也可以生成PDF吗&#xff1f;下面来和小编一起学习下吧。首先我们访问网址&#xff1a;https://wkhtmltopdf.org/downloads.html &#xff0c;根据自己…

java 代码重用需要注意的事项_程序员笔记|编写高性能的Java代码需要注意的4个问题...

一、并发无法创建新的本机线程......问题1&#xff1a;Java的中创建一个线程消耗多少内存&#xff1f;每个线程有独自的栈内存&#xff0c;共享堆内存问题2&#xff1a;一台机器可以创建多少线程&#xff1f;CPU&#xff0c;内存&#xff0c;操作系统&#xff0c;JVM&#xff0…

java vbs_VBS基础篇 - vbscript Dictionary对象

Dictionary是存储数据键和项目对的对象&#xff0c;其主要属性有Count、Item、Key&#xff0c;主要方法有Add、Exists、Items、Keys、Remove、RemoveAll。创建Dictionary对象定义并创建Dictionary对象&#xff0c;使用CreateObject创建并返回自动化对象的引用Dim DicSet Dic C…

java integer最大值_五分钟学会java中的基础类型封装类

在刚刚学习java的时候&#xff0c;老师不止一次的说过java是一种面向对象的语言&#xff0c;万物皆对象。对于java中的基础数据类型&#xff0c;由于为了符合java中面向对象的特点&#xff0c;同样也有其封装类。这篇文章对其有一个认识。一、基本认识其实在jdk1.5之前&#xf…

web.xml文件位于web项目的目录结构中的_看完这篇,别人的开源项目结构应该能看懂了...

我为什么要写这篇近来&#xff0c;和不少初学Spring或Spring Boot的小伙伴私信交流了关于项目目录结构划分和代码分层的问题。很多小伙伴表示网上下载下来的开源项目看不懂&#xff0c;项目结构和代码分层看得很蒙&#xff0c;不知道应该以一个什么样的思路去学习和吸收别人的项…

mysql workbench中文设置_使用Workbench完成流体压力渗透分析

“之前的案例&#xff0c;APDL Showcase3里使用到了流体压力渗透载荷。有朋友读到以后&#xff0c;希望能在Workbench里实现这一功能。有需求就有动力&#xff0c;我们来试一试。 ”01—结果展示先看计算结果&#xff1a;(为了截图方便将模型旋转了90度)该案例为轴对称模型&…

ddns客户端_DDNS哪家最方便?试试看Mikrotik的ROS!

没有固定IP的情况下&#xff0c;想要提供外网访问&#xff0c;那么DDNS是必不可少的一个设置。DDNS&#xff08;Dynamic Domain Name Server&#xff0c;动态域名服务&#xff09;是将用户的动态IP地址映射到一个固定的域名解析服务。需要注意的是&#xff0c;不是域名是动态的…

python中级程序员是什么水准_程序员进阶:一篇搞懂Python中级应用

异常处理&#xff1a;try-except 异常即是一个事件&#xff0c;该事件会在程序执行过程中发生&#xff0c;影响了程序的正常执行。一般情况下&#xff0c;在Python无法正常处理程序时就会发生一个异常。 异常是Python对象&#xff0c;表示一个错误。当Python脚本发生异常时我们…

python做excel表格代码_[宜配屋]听图阁

安装两个库&#xff1a;pip install xlrd、pip install xlwt1.python读excel——xlrd2.python写excel——xlwt1.读excel数据&#xff0c;包括日期等数据#codingutf-8import xlrdimport datetimefrom datetime import datedef read_excel():#打开文件wb xlrd.open_workbook(rte…

python分布式框架_高性能分布式执行框架——Ray

Ray是UC Berkeley RISELab新推出的高性能分布式执行框架&#xff0c;它使用了和传统分布式计算系统不一样的架构和对分布式计算的抽象方式&#xff0c;具有比Spark更优异的计算性能。 Ray目前还处于实验室阶段&#xff0c;最新版本为0.2.2版本。虽然Ray自称是面向AI应用的分布式…

原 hibernate与mysql字段类型对应关系

原 hibernate与mysql字段类型对应关系 发表于8个月前(2015-04-17 08:56) 阅读&#xff08;1102&#xff09; | 评论&#xff08;0&#xff09; 2人收藏此文章, 我要收藏赞01月16日厦门 OSC 源创会火热报名中&#xff0c;奖品多多哦 摘要 hibernate与mysql字段类型对应关系 …

下拉选择框 其他_列表框 vs 下拉列表,哪个更好?

许多UI控件允许用户选择选项&#xff0c;它们包括复选框、单选按钮、切换开关、步进器、列表框和下拉列表。 在本文中&#xff0c;作者对列表框和下拉列表进行了定义&#xff0c;讨论何时使用各个元素&#xff0c;以及各个情况下使用哪一种更加合适。摘要列表框和下拉列表是紧凑…

springboot整合elasticsearch_Spring Boot学习10_整合Elasticsearch

一、Elasticsearch概念•以 员工文档 的形式存储为例&#xff1a;一个文档代表一个员工数据。存储数据到 ElasticSearch 的行为叫做 索引 &#xff0c;但在索引一个文档之前&#xff0c;需要确定将文档存储在哪里。•一个 ElasticSearch 集群可以 包含多个 索引 &#xff0c;相…

php制作图片轮播_图片轮播效果实现方法

图片轮播效果如何实现呢本文主要介绍了JQuery实现图片轮播效果的制作原理以及实现代码&#xff0c;文章末尾附上源码下载&#xff0c;具有很好的参考价值。下面跟着小编一起来看下吧&#xff0c;希望能帮助到大家。用JQuery操作DOM确实很方便&#xff0c;并且JQuery提供了非常人…